1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22: #ifndef _GNU_SOURCE
23: # define _GNU_SOURCE 1
24: #endif
25:
26: #ifdef HAVE_CONFIG_H
27: #include <config.h>
28: #endif
29:
30:
31: #ifndef __GNUC__
32: # if HAVE_ALLOCA_H || defined _LIBC
33: # include <alloca.h>
34: # else
35: # ifdef _AIX
36: #pragma alloca
37: # else
38: # ifndef alloca
39: char *alloca ();
40: # endif
41: # endif
42: # endif
43: #endif
44:
45: #include <stddef.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <assert.h>
49: #include <stdarg.h>
50: #include <ctype.h>
51: #include <limits.h>
52: #ifdef _LIBC
53: # include <../libio/libioP.h>
54: # include <wchar.h>
55: #endif
56:
57: #ifndef _
58:
59: # if defined HAVE_LIBINTL_H || defined _LIBC
60: # include <libintl.h>
61: # ifdef _LIBC
62: # undef dgettext
63: # define dgettext(domain, msgid) \
64: INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES)
65: # endif
66: # else
67: # define dgettext(domain, msgid) (msgid)
68: # endif
69: #endif
70:
71: #ifndef _LIBC
72: # if HAVE_STRERROR_R
73: # if !HAVE_DECL_STRERROR_R
74: char *strerror_r (int errnum, char *buf, size_t buflen);
75: # endif
76: # else
77: # if !HAVE_DECL_STRERROR
78: char *strerror (int errnum);
79: # endif
80: # endif
81: #endif
82:
83: #include "argp.h"
84: #include "argp-fmtstream.h"
85: #include "argp-namefrob.h"
86:
87: #ifndef SIZE_MAX
88: # define SIZE_MAX ((size_t) -1)
89: #endif
90: ^L
91:
92:
93:
94:
95:
96:
97:
98:
99: #define DUP_ARGS 0
100: #define DUP_ARGS_NOTE 1
101: #define SHORT_OPT_COL 2
102: #define LONG_OPT_COL 6
103: #define DOC_OPT_COL 2
104: #define OPT_DOC_COL 29
105: #define HEADER_COL 1
106: #define USAGE_INDENT 12
107: #define RMARGIN 79
108:
109:
110:
111: struct uparams
112: {
113:
114:
115:
116:
117:
118: int dup_args;
119:
120:
121:
122: int dup_args_note;
123:
124:
125: int short_opt_col;
126: int long_opt_col;
127: int doc_opt_col;
128: int opt_doc_col;
129: int header_col;
130: int usage_indent;
131: int rmargin;
132: };
133:
134:
135: static struct uparams uparams = {
136: DUP_ARGS, DUP_ARGS_NOTE,
137: SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
138: USAGE_INDENT, RMARGIN
139: };
140:
141:
142: struct uparam_name
143: {
144: const char name[14];
145: bool is_bool;
146: uint8_t uparams_offs;
147: };
148:
149:
150: static const struct uparam_name uparam_names[] =
151: {
152: { "dup-args", true, offsetof (struct uparams, dup_args) },
153: { "dup-args-note", true, offsetof (struct uparams, dup_args_note) },
154: { "short-opt-col", false, offsetof (struct uparams, short_opt_col) },
155: { "long-opt-col", false, offsetof (struct uparams, long_opt_col) },
156: { "doc-opt-col", false, offsetof (struct uparams, doc_opt_col) },
157: { "opt-doc-col", false, offsetof (struct uparams, opt_doc_col) },
158: { "header-col", false, offsetof (struct uparams, header_col) },
159: { "usage-indent", false, offsetof (struct uparams, usage_indent) },
160: { "rmargin", false, offsetof (struct uparams, rmargin) }
161: };
162: #define nuparam_names (sizeof (uparam_names) / sizeof (uparam_names[0]))
163:
164:
165: static void
166: fill_in_uparams (const struct argp_state *state)
167: {
168: const char *var = getenv ("ARGP_HELP_FMT");
169:
170: #define SKIPWS(p) do { while (isspace (*p)) p++; } while (0);
171:
172: if (var)
173:
174: while (*var)
175: {
176: SKIPWS (var);
177:
178: if (isalpha (*var))
179: {
180: size_t var_len;
181: const struct uparam_name *un;
182: int unspec = 0, val = 0;
183: const char *arg = var;
184:
185: while (isalnum (*arg) || *arg == '-' || *arg == '_')
186: arg++;
187: var_len = arg - var;
188:
189: SKIPWS (arg);
190:
191: if (*arg == '\0' || *arg == ',')
192: unspec = 1;
193: else if (*arg == '=')
194: {
195: arg++;
196: SKIPWS (arg);
197: }
198:
199: if (unspec)
200: {
201: if (var[0] == 'n' && var[1] == 'o' && var[2] == '-')
202: {
203: val = 0;
204: var += 3;
205: var_len -= 3;
206: }
207: else
208: val = 1;
209: }
210: else if (isdigit (*arg))
211: {
212: val = atoi (arg);
213: while (isdigit (*arg))
214: arg++;
215: SKIPWS (arg);
216: }
217:
218: un = uparam_names;
219: size_t u;
220: for (u = 0; u < nuparam_names; ++un, ++u)
221: if (strlen (un->name) == var_len
222: && strncmp (var, un->name, var_len) == 0)
223: {
224: if (unspec && !un->is_bool)
225: __argp_failure (state, 0, 0,
226: dgettext (state == NULL ? NULL
227: : state->root_argp->argp_domain,
228: "\
229: %.*s: ARGP_HELP_FMT parameter requires a value"),
230: (int) var_len, var);
231: else
232: *(int *)((char *)&uparams + un->uparams_offs) = val;
233: break;
234: }
235: if (u == nuparam_names)
236: __argp_failure (state, 0, 0,
237: dgettext (state == NULL ? NULL
238: : state->root_argp->argp_domain, "\
239: %.*s: Unknown ARGP_HELP_FMT parameter"),
240: (int) var_len, var);
241:
242: var = arg;
243: if (*var == ',')
244: var++;
245: }
246: else if (*var)
247: {
248: __argp_failure (state, 0, 0,
249: dgettext (state == NULL ? NULL
250: : state->root_argp->argp_domain,
251: "Garbage in ARGP_HELP_FMT: %s"), var);
252: break;
253: }
254: }
255: }
256: ^L
257:
258:
259: #define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
260:
261:
262: #define oalias(opt) ((opt)->flags & OPTION_ALIAS)
263:
264:
265: #define odoc(opt) ((opt)->flags & OPTION_DOC)
266:
267:
268: #define oend(opt) __option_is_end (opt)
269:
270:
271: #define oshort(opt) __option_is_short (opt)
272: ^L
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336: ^L
337:
338: static int
339: find_char (char ch, char *beg, char *end)
340: {
341: while (beg < end)
342: if (*beg == ch)
343: return 1;
344: else
345: beg++;
346: return 0;
347: }
348: ^L
349: struct hol_cluster;
350:
351: struct hol_entry
352: {
353:
354: const struct argp_option *opt;
355:
356: unsigned num;
357:
358:
359:
360:
361:
362:
363:
364: char *short_options;
365:
366:
367:
368:
369: int group;
370:
371:
372: struct hol_cluster *cluster;
373:
374:
375: const struct argp *argp;
376: };
377:
378:
379: struct hol_cluster
380: {
381:
382: const char *header;
383:
384:
385:
386:
387: int index;
388:
389:
390:
391: int group;
392:
393:
394:
395: struct hol_cluster *parent;
396:
397:
398: const struct argp *argp;
399:
400:
401: int depth;
402:
403:
404:
405: struct hol_cluster *next;
406: };
407:
408:
409: struct hol
410: {
411:
412: struct hol_entry *entries;
413:
414:
415: unsigned num_entries;
416:
417:
418:
419: char *short_options;
420:
421:
422: struct hol_cluster *clusters;
423: };
424: ^L
425:
426:
427: static struct hol *
428: make_hol (const struct argp *argp, struct hol_cluster *cluster)
429: {
430: char *so;
431: const struct argp_option *o;
432: const struct argp_option *opts = argp->options;
433: struct hol_entry *entry;
434: unsigned num_short_options = 0;
435: struct hol *hol = malloc (sizeof (struct hol));
436:
437: assert (hol);
438:
439: hol->num_entries = 0;
440: hol->clusters = 0;
441:
442: if (opts)
443: {
444: int cur_group = 0;
445:
446:
447: assert (! oalias (opts));
448:
449:
450: for (o = opts; ! oend (o); o++)
451: {
452: if (! oalias (o))
453: hol->num_entries++;
454: if (oshort (o))
455: num_short_options++;
456: }
457:
458: hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
459: hol->short_options = malloc (num_short_options + 1);
460:
461: assert (hol->entries && hol->short_options);
462: #if SIZE_MAX <= UINT_MAX
463: assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry));
464: #endif
465:
466:
467: so = hol->short_options;
468: for (o = opts, entry = hol->entries; ! oend (o); entry++)
469: {
470: entry->opt = o;
471: entry->num = 0;
472: entry->short_options = so;
473: entry->group = cur_group =
474: o->group
475: ? o->group
476: : ((!o->name && !o->key)
477: ? cur_group + 1
478: : cur_group);
479: entry->cluster = cluster;
480: entry->argp = argp;
481:
482: do
483: {
484: entry->num++;
485: if (oshort (o) && ! find_char (o->key, hol->short_options, so))
486:
487: *so++ = o->key;
488: o++;
489: }
490: while (! oend (o) && oalias (o));
491: }
492: *so = '\0';
493: }
494:
495: return hol;
496: }
497: ^L
498:
499:
500:
501: static struct hol_cluster *
502: hol_add_cluster (struct hol *hol, int group, const char *header, int index,
503: struct hol_cluster *parent, const struct argp *argp)
504: {
505: struct hol_cluster *cl = malloc (sizeof (struct hol_cluster));
506: if (cl)
507: {
508: cl->group = group;
509: cl->header = header;
510:
511: cl->index = index;
512: cl->parent = parent;
513: cl->argp = argp;
514: cl->depth = parent ? parent->depth + 1 : 0;
515:
516: cl->next = hol->clusters;
517: hol->clusters = cl;
518: }
519: return cl;
520: }
521: ^L
522:
523: static void
524: hol_free (struct hol *hol)
525: {
526: struct hol_cluster *cl = hol->clusters;
527:
528: while (cl)
529: {
530: struct hol_cluster *next = cl->next;
531: free (cl);
532: cl = next;
533: }
534:
535: if (hol->num_entries > 0)
536: {
537: free (hol->entries);
538: free (hol->short_options);
539: }
540:
541: free (hol);
542: }
543: ^L
544: static int
545: hol_entry_short_iterate (const struct hol_entry *entry,
546: int (*func)(const struct argp_option *opt,
547: const struct argp_option *real,
548: const char *domain, void *cookie),
549: const char *domain, void *cookie)
550: {
551: unsigned nopts;
552: int val = 0;
553: const struct argp_option *opt, *real = entry->opt;
554: char *so = entry->short_options;
555:
556: for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
557: if (oshort (opt) && *so == opt->key)
558: {
559: if (!oalias (opt))
560: real = opt;
561: if (ovisible (opt))
562: val = (*func)(opt, real, domain, cookie);
563: so++;
564: }
565:
566: return val;
567: }
568:
569: static inline int
570: __attribute__ ((always_inline))