Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/heimdal/lib/roken/getarg.c
Line
Count
Source
1
/*
2
 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3
 * (Royal Institute of Technology, Stockholm, Sweden).
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 *
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * 3. Neither the name of the Institute nor the names of its contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
 * SUCH DAMAGE.
32
 */
33
34
#include <config.h>
35
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include "roken.h"
40
#include "getarg.h"
41
42
0
#define ISFLAG(X) ((X).type == arg_flag || (X).type == arg_negative_flag)
43
44
static size_t
45
print_arg (char *string,
46
     size_t len,
47
     int mdoc,
48
     int longp,
49
     struct getargs *arg,
50
     char *(i18n)(const char *))
51
0
{
52
0
    const char *s;
53
54
0
    *string = '\0';
55
56
0
    if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
57
0
  return 0;
58
59
0
    if(mdoc){
60
0
  if(longp)
61
0
      strlcat(string, "= Ns", len);
62
0
  strlcat(string, " Ar ", len);
63
0
    } else {
64
0
  if (longp)
65
0
      strlcat (string, "=", len);
66
0
  else
67
0
      strlcat (string, " ", len);
68
0
    }
69
70
0
    if (arg->arg_help)
71
0
  s = (*i18n)(arg->arg_help);
72
0
    else if (arg->type == arg_integer || arg->type == arg_counter)
73
0
  s = "integer";
74
0
    else if (arg->type == arg_string)
75
0
  s = "string";
76
0
    else if (arg->type == arg_strings)
77
0
  s = "strings";
78
0
    else if (arg->type == arg_double)
79
0
  s = "float";
80
0
    else
81
0
  s = "<undefined>";
82
83
0
    strlcat(string, s, len);
84
0
    return 1 + strlen(s);
85
0
}
86
87
static void
88
mandoc_template(struct getargs *args,
89
    size_t num_args,
90
    const char *progname,
91
    const char *extra_string,
92
    char *(i18n)(const char *))
93
0
{
94
0
    size_t i;
95
0
    char timestr[64], cmd[64];
96
0
    char buf[128];
97
0
    const char *p;
98
0
    time_t t;
99
100
0
    printf(".\\\" Things to fix:\n");
101
0
    printf(".\\\"   * correct section, and operating system\n");
102
0
    printf(".\\\"   * remove Op from mandatory flags\n");
103
0
    printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
104
0
    printf(".\\\"\n");
105
0
    t = time(NULL);
106
0
    strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
107
0
    printf(".Dd %s\n", timestr);
108
0
    p = strrchr(progname, '/');
109
0
    if(p) p++; else p = progname;
110
0
    strlcpy(cmd, p, sizeof(cmd));
111
0
    strupr(cmd);
112
113
0
    printf(".Dt %s SECTION\n", cmd);
114
0
    printf(".Os OPERATING_SYSTEM\n");
115
0
    printf(".Sh NAME\n");
116
0
    printf(".Nm %s\n", p);
117
0
    printf(".Nd in search of a description\n");
118
0
    printf(".Sh SYNOPSIS\n");
119
0
    printf(".Nm\n");
120
0
    for(i = 0; i < num_args; i++){
121
  /* we seem to hit a limit on number of arguments if doing
122
           short and long flags with arguments -- split on two lines */
123
0
  if(ISFLAG(args[i]) ||
124
0
     args[i].short_name == 0 || args[i].long_name == NULL) {
125
0
      printf(".Op ");
126
127
0
      if(args[i].short_name) {
128
0
    print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
129
0
    printf("Fl %c%s", args[i].short_name, buf);
130
0
    if(args[i].long_name)
131
0
        printf(" | ");
132
0
      }
133
0
      if(args[i].long_name) {
134
0
    print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
135
0
    printf("Fl Fl %s%s%s",
136
0
           args[i].type == arg_negative_flag ? "no-" : "",
137
0
           args[i].long_name, buf);
138
0
      }
139
0
      printf("\n");
140
0
  } else {
141
0
      print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
142
0
      printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
143
0
      print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
144
0
      printf(".Fl Fl %s%s\n.Xc\n.Oc\n", args[i].long_name, buf);
145
0
  }
146
    /*
147
      if(args[i].type == arg_strings)
148
    fprintf (stderr, "...");
149
    */
150
0
    }
151
0
    if (extra_string && *extra_string)
152
0
  printf (".Ar %s\n", extra_string);
153
0
    printf(".Sh DESCRIPTION\n");
154
0
    printf("Supported options:\n");
155
0
    printf(".Bl -tag -width Ds\n");
156
0
    for(i = 0; i < num_args; i++){
157
0
  printf(".It Xo\n");
158
0
  if(args[i].short_name){
159
0
      printf(".Fl %c", args[i].short_name);
160
0
      print_arg(buf, sizeof(buf), 1, 0, args + i, i18n);
161
0
      printf("%s", buf);
162
0
      if(args[i].long_name)
163
0
    printf(" ,");
164
0
      printf("\n");
165
0
  }
166
0
  if(args[i].long_name){
167
0
      printf(".Fl Fl %s%s",
168
0
       args[i].type == arg_negative_flag ? "no-" : "",
169
0
       args[i].long_name);
170
0
      print_arg(buf, sizeof(buf), 1, 1, args + i, i18n);
171
0
      printf("%s\n", buf);
172
0
  }
173
0
  printf(".Xc\n");
174
0
  if(args[i].help)
175
0
      printf("%s\n", args[i].help);
176
    /*
177
      if(args[i].type == arg_strings)
178
    fprintf (stderr, "...");
179
    */
180
0
    }
181
0
    printf(".El\n");
182
0
    printf(".\\\".Sh ENVIRONMENT\n");
183
0
    printf(".\\\".Sh FILES\n");
184
0
    printf(".\\\".Sh EXAMPLES\n");
185
0
    printf(".\\\".Sh DIAGNOSTICS\n");
186
0
    printf(".\\\".Sh SEE ALSO\n");
187
0
    printf(".\\\".Sh STANDARDS\n");
188
0
    printf(".\\\".Sh HISTORY\n");
189
0
    printf(".\\\".Sh AUTHORS\n");
190
0
    printf(".\\\".Sh BUGS\n");
191
0
}
192
193
static int
194
check_column(FILE *f, int col, int len, int columns)
195
0
{
196
0
    if(col + len > columns) {
197
0
  fprintf(f, "\n");
198
0
  col = fprintf(f, "  ");
199
0
    }
200
0
    return col;
201
0
}
202
203
static char *
204
builtin_i18n(const char *str)
205
0
{
206
0
    return rk_UNCONST(str);
207
0
}
208
209
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
210
arg_printusage (struct getargs *args,
211
    size_t num_args,
212
    const char *progname,
213
    const char *extra_string)
214
0
{
215
0
    arg_printusage_i18n(args, num_args, "Usage",
216
0
      progname, extra_string, builtin_i18n);
217
0
}
218
219
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
220
arg_printusage_i18n (struct getargs *args,
221
         size_t num_args,
222
         const char *usage,
223
         const char *progname,
224
         const char *extra_string,
225
         char *(*i18n)(const char *))
226
0
{
227
0
    size_t i, max_len = 0;
228
0
    char buf[128];
229
0
    int col = 0, columns;
230
231
0
    if (progname == NULL)
232
0
  progname = getprogname();
233
234
0
    if (i18n == NULL)
235
0
  i18n = builtin_i18n;
236
237
0
    if(getenv("GETARGMANDOC")){
238
0
  mandoc_template(args, num_args, progname, extra_string, i18n);
239
0
  return;
240
0
    }
241
0
    if(get_window_size(2, NULL, &columns) == -1)
242
0
  columns = 80;
243
0
    col = 0;
244
0
    col += fprintf (stderr, "%s: %s", usage, progname);
245
0
    buf[0] = '\0';
246
0
    for (i = 0; i < num_args; ++i) {
247
0
  if(args[i].short_name && ISFLAG(args[i])) {
248
0
      char s[2];
249
0
      if(buf[0] == '\0')
250
0
    strlcpy(buf, "[-", sizeof(buf));
251
0
      s[0] = args[i].short_name;
252
0
      s[1] = '\0';
253
0
      strlcat(buf, s, sizeof(buf));
254
0
  }
255
0
    }
256
0
    if(buf[0] != '\0') {
257
0
  strlcat(buf, "]", sizeof(buf));
258
0
  col = check_column(stderr, col, strlen(buf) + 1, columns);
259
0
  col += fprintf(stderr, " %s", buf);
260
0
    }
261
262
0
    for (i = 0; i < num_args; ++i) {
263
0
  size_t len = 0;
264
265
0
  if (args[i].long_name) {
266
0
      buf[0] = '\0';
267
0
      strlcat(buf, "[--", sizeof(buf));
268
0
      len += 2;
269
0
      if(args[i].type == arg_negative_flag) {
270
0
    strlcat(buf, "no-", sizeof(buf));
271
0
    len += 3;
272
0
      }
273
0
      strlcat(buf, args[i].long_name, sizeof(buf));
274
0
      len += strlen(args[i].long_name);
275
0
      len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
276
0
           0, 1, &args[i], i18n);
277
0
      strlcat(buf, "]", sizeof(buf));
278
0
      if(args[i].type == arg_strings)
279
0
    strlcat(buf, "...", sizeof(buf));
280
0
      col = check_column(stderr, col, strlen(buf) + 1, columns);
281
0
      col += fprintf(stderr, " %s", buf);
282
0
  }
283
0
  if (args[i].short_name && !ISFLAG(args[i])) {
284
0
      snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
285
0
      len += 2;
286
0
      len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
287
0
           0, 0, &args[i], i18n);
288
0
      strlcat(buf, "]", sizeof(buf));
289
0
      if(args[i].type == arg_strings)
290
0
    strlcat(buf, "...", sizeof(buf));
291
0
      col = check_column(stderr, col, strlen(buf) + 1, columns);
292
0
      col += fprintf(stderr, " %s", buf);
293
0
  }
294
0
  if (args[i].long_name && args[i].short_name)
295
0
      len += 2; /* ", " */
296
0
  max_len = max(max_len, len);
297
0
    }
298
0
    if (extra_string) {
299
0
  check_column(stderr, col, strlen(extra_string) + 1, columns);
300
0
  fprintf (stderr, " %s\n", extra_string);
301
0
    } else
302
0
  fprintf (stderr, "\n");
303
0
    for (i = 0; i < num_args; ++i) {
304
0
  if (args[i].help) {
305
0
      size_t count = 0;
306
307
0
      if (args[i].short_name) {
308
0
    count += fprintf (stderr, "-%c", args[i].short_name);
309
0
    print_arg (buf, sizeof(buf), 0, 0, &args[i], i18n);
310
0
    count += fprintf(stderr, "%s", buf);
311
0
      }
312
0
      if (args[i].short_name && args[i].long_name)
313
0
    count += fprintf (stderr, ", ");
314
0
      if (args[i].long_name) {
315
0
    count += fprintf (stderr, "--");
316
0
    if (args[i].type == arg_negative_flag)
317
0
        count += fprintf (stderr, "no-");
318
0
    count += fprintf (stderr, "%s", args[i].long_name);
319
0
    print_arg (buf, sizeof(buf), 0, 1, &args[i], i18n);
320
0
    count += fprintf(stderr, "%s", buf);
321
0
      }
322
0
      while(count++ <= max_len)
323
0
    putc (' ', stderr);
324
0
      fprintf (stderr, "%s\n", (*i18n)(args[i].help));
325
0
  }
326
0
    }
327
0
}
328
329
static int
330
add_string(getarg_strings *s, char *value)
331
0
{
332
0
    char **strings;
333
334
0
    strings = realloc(s->strings, (s->num_strings + 1) * sizeof(*s->strings));
335
0
    if (strings == NULL) {
336
0
  free(s->strings);
337
0
  s->strings = NULL;
338
0
  s->num_strings = 0;
339
0
  return ENOMEM;
340
0
    }
341
0
    s->strings = strings;
342
0
    s->strings[s->num_strings] = value;
343
0
    s->num_strings++;
344
0
    return 0;
345
0
}
346
347
static int
348
arg_match_long(struct getargs *args, size_t num_args,
349
         char *argv, int argc, char **rargv, int *goptind)
350
0
{
351
0
    size_t i;
352
0
    char *goptarg = NULL;
353
0
    int negate = 0;
354
0
    int partial_match = 0;
355
0
    struct getargs *partial = NULL;
356
0
    struct getargs *current = NULL;
357
0
    int argv_len;
358
0
    char *p;
359
0
    int p_len;
360
361
0
    argv_len = strlen(argv);
362
0
    p = strchr (argv, '=');
363
0
    if (p != NULL)
364
0
  argv_len = p - argv;
365
366
0
    for (i = 0; i < num_args; ++i) {
367
0
  if(args[i].long_name) {
368
0
      int len = strlen(args[i].long_name);
369
0
      p = argv;
370
0
      p_len = argv_len;
371
0
      negate = 0;
372
373
0
      for (;;) {
374
0
    if (strncmp (args[i].long_name, p, p_len) == 0) {
375
0
        if(p_len == len)
376
0
      current = &args[i];
377
0
        else {
378
0
      ++partial_match;
379
0
      partial = &args[i];
380
0
        }
381
0
        goptarg  = p + p_len;
382
0
    } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
383
0
        negate = !negate;
384
0
        p += 3;
385
0
        p_len -= 3;
386
0
        continue;
387
0
    }
388
0
    break;
389
0
      }
390
0
      if (current)
391
0
    break;
392
0
  }
393
0
    }
394
0
    if (current == NULL) {
395
0
  if (partial_match == 1)
396
0
      current = partial;
397
0
  else
398
0
      return ARG_ERR_NO_MATCH;
399
0
    }
400
401
0
    if(*goptarg == '\0'
402
0
       && !ISFLAG(*current)
403
0
       && current->type != arg_collect
404
0
       && current->type != arg_counter)
405
0
  return ARG_ERR_NO_MATCH;
406
0
    switch(current->type){
407
0
    case arg_integer:
408
0
    {
409
0
  int tmp;
410
0
  if(sscanf(goptarg + 1, "%d", &tmp) != 1)
411
0
      return ARG_ERR_BAD_ARG;
412
0
  *(int*)current->value = tmp;
413
0
  return 0;
414
0
    }
415
0
    case arg_string:
416
0
    {
417
0
  *(char**)current->value = goptarg + 1;
418
0
  return 0;
419
0
    }
420
0
    case arg_strings:
421
0
    {
422
0
  return add_string((getarg_strings*)current->value, goptarg + 1);
423
0
    }
424
0
    case arg_flag:
425
0
    case arg_negative_flag:
426
0
    {
427
0
  int *flag = current->value;
428
0
  if(*goptarg == '\0' ||
429
0
     strcmp(goptarg + 1, "yes") == 0 ||
430
0
     strcmp(goptarg + 1, "true") == 0){
431
0
      *flag = !negate;
432
0
      return 0;
433
0
  } else if (*goptarg && strcmp(goptarg + 1, "maybe") == 0) {
434
0
      *flag = rk_random() & 1;
435
0
  } else {
436
0
      *flag = negate;
437
0
      return 0;
438
0
  }
439
0
  return ARG_ERR_BAD_ARG;
440
0
    }
441
0
    case arg_counter :
442
0
    {
443
0
  int val;
444
445
0
  if (*goptarg == '\0')
446
0
      val = 1;
447
0
  else if(sscanf(goptarg + 1, "%d", &val) != 1)
448
0
      return ARG_ERR_BAD_ARG;
449
0
  *(int *)current->value += val;
450
0
  return 0;
451
0
    }
452
0
    case arg_double:
453
0
    {
454
0
  double tmp;
455
0
  if(sscanf(goptarg + 1, "%lf", &tmp) != 1)
456
0
      return ARG_ERR_BAD_ARG;
457
0
  *(double*)current->value = tmp;
458
0
  return 0;
459
0
    }
460
0
    case arg_collect:{
461
0
  struct getarg_collect_info *c = current->value;
462
0
  int o = argv - rargv[*goptind];
463
0
  return (*c->func)(FALSE, argc, rargv, goptind, &o, c->data);
464
0
    }
465
466
0
    default:
467
0
  abort ();
468
0
  UNREACHABLE(return 0);
469
0
    }
470
0
}
471
472
static int
473
arg_match_short (struct getargs *args, size_t num_args,
474
     char *argv, int argc, char **rargv, int *goptind)
475
0
{
476
0
    size_t j, k;
477
478
0
    for(j = 1; j > 0 && j < strlen(rargv[*goptind]); j++) {
479
0
  for(k = 0; k < num_args; k++) {
480
0
      char *goptarg;
481
482
0
      if(args[k].short_name == 0)
483
0
    continue;
484
0
      if(argv[j] == args[k].short_name) {
485
0
    if(args[k].type == arg_flag) {
486
0
        *(int*)args[k].value = 1;
487
0
        break;
488
0
    }
489
0
    if(args[k].type == arg_negative_flag) {
490
0
        *(int*)args[k].value = 0;
491
0
        break;
492
0
    }
493
0
    if(args[k].type == arg_counter) {
494
0
        ++*(int *)args[k].value;
495
0
        break;
496
0
    }
497
0
    if(args[k].type == arg_collect) {
498
0
        struct getarg_collect_info *c = args[k].value;
499
0
        int a = (int)j;
500
501
0
        if((*c->func)(TRUE, argc, rargv, goptind, &a, c->data))
502
0
      return ARG_ERR_BAD_ARG;
503
0
        j = a;
504
0
        break;
505
0
    }
506
507
0
    if(argv[j + 1])
508
0
        goptarg = &argv[j + 1];
509
0
    else {
510
0
        ++*goptind;
511
0
        goptarg = rargv[*goptind];
512
0
    }
513
0
    if(goptarg == NULL) {
514
0
        --*goptind;
515
0
        return ARG_ERR_NO_ARG;
516
0
    }
517
0
    if(args[k].type == arg_integer) {
518
0
        int tmp;
519
0
        if(sscanf(goptarg, "%d", &tmp) != 1)
520
0
      return ARG_ERR_BAD_ARG;
521
0
        *(int*)args[k].value = tmp;
522
0
        return 0;
523
0
    } else if(args[k].type == arg_string) {
524
0
        *(char**)args[k].value = goptarg;
525
0
        return 0;
526
0
    } else if(args[k].type == arg_strings) {
527
0
        return add_string((getarg_strings*)args[k].value, goptarg);
528
0
    } else if(args[k].type == arg_double) {
529
0
        double tmp;
530
0
        if(sscanf(goptarg, "%lf", &tmp) != 1)
531
0
      return ARG_ERR_BAD_ARG;
532
0
        *(double*)args[k].value = tmp;
533
0
        return 0;
534
0
    }
535
0
    return ARG_ERR_BAD_ARG;
536
0
      }
537
0
  }
538
0
  if (k == num_args)
539
0
      return ARG_ERR_NO_MATCH;
540
0
    }
541
0
    return 0;
542
0
}
543
544
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
545
getarg(struct getargs *args, size_t num_args,
546
       int argc, char **argv, int *goptind)
547
0
{
548
0
    int i;
549
0
    int ret = 0;
550
551
0
    rk_random_init();
552
0
    (*goptind)++;
553
0
    for(i = *goptind; i < argc; i++) {
554
0
  if(argv[i][0] != '-')
555
0
      break;
556
0
  if(argv[i][1] == '-'){
557
0
      if(argv[i][2] == 0){
558
0
    i++;
559
0
    break;
560
0
      }
561
0
      ret = arg_match_long (args, num_args, argv[i] + 2,
562
0
          argc, argv, &i);
563
0
  } else {
564
0
      ret = arg_match_short (args, num_args, argv[i],
565
0
           argc, argv, &i);
566
0
  }
567
0
  if(ret)
568
0
      break;
569
0
    }
570
0
    *goptind = i;
571
0
    return ret;
572
0
}
573
574
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
575
free_getarg_strings (getarg_strings *s)
576
0
{
577
0
    free (s->strings);
578
0
}
579
580
#if TEST
581
int foo_flag = 2;
582
int flag1 = 0;
583
int flag2 = 0;
584
int bar_int;
585
char *baz_string;
586
587
struct getargs args[] = {
588
    { NULL, '1', arg_flag, &flag1, "one", NULL },
589
    { NULL, '2', arg_flag, &flag2, "two", NULL },
590
    { "foo", 'f', arg_negative_flag, &foo_flag, "foo", NULL },
591
    { "bar", 'b', arg_integer, &bar_int, "bar", "seconds"},
592
    { "baz", 'x', arg_string, &baz_string, "baz", "name" },
593
};
594
595
int main(int argc, char **argv)
596
{
597
    int goptind = 0;
598
    while (getarg(args, 5, argc, argv, &goptind))
599
  printf("Bad arg: %s\n", argv[goptind]);
600
    printf("flag1 = %d\n", flag1);
601
    printf("flag2 = %d\n", flag2);
602
    printf("foo_flag = %d\n", foo_flag);
603
    printf("bar_int = %d\n", bar_int);
604
    printf("baz_flag = %s\n", baz_string);
605
    arg_printusage (args, 5, argv[0], "nothing here");
606
}
607
#endif