3 * description: minimal replacement for GNU Argp library
4 * Copyright 2011 Peter Desnoyers, Northeastern University
6 * This file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * <http://pjd-notes.blogspot.jp/2011/06/gnu-argp-for-osx.html>
14 After using optparse in Python, I've become spoiled and never want to go back to getopt/getopt_long for C code. The only package I've found for C that handles both options and help strings in a reasonable fashion seems to be GNU Argp, but it's non-standard and works on my Linux machines but not my Mac. A quick try at pulling Argp from the glibc source and porting to the Mac was leading to more work than I wanted, so the solution was this quick-and-dirty replacement.
16 And yes, it commits the cardinal sin of including code in a header file, but it works fine if you're only including it from main.c, and keeps your source compatible between systems. (just put it in the local directory, add "-I ." to your compile flags, and you're done.)
23 /* This only includes the features I've used in my programs to date;
24 * in particular, it totally ignores any sort of flag.
27 #ifndef __error_t_defined
29 # define __error_t_defined
38 int group
; /* ignored */
49 struct argp_option
*options
;
50 error_t (*parser
)(int key
, char *arg
, struct argp_state
*state
);
55 void argp_help(struct argp_state
*state
)
57 printf("Usage: %s [OPTIONS...] %s\n%s\n\n",
58 state
->name
, state
->argp
->arg_doc
, state
->argp
->prog_doc
);
60 struct argp_option
*o
= state
->argp
->options
;
63 for (i
= 0; o
[i
].name
!= NULL
; i
++) {
64 char tmp
[80], *p
= tmp
;
65 p
+= sprintf(tmp
, "--%s", o
[i
].name
);
67 sprintf(p
, "=%s", o
[i
].arg
);
68 printf(" %-*s%s\n", state
->maxlen
+ 8, tmp
, o
[i
].doc
);
70 printf(" --%-*s%s\n", state
->maxlen
+6, "help", "Give this help list");
71 printf(" --%-*s%s\n", state
->maxlen
+6, "usage",
72 "Give a short usage message");
77 void argp_usage(struct argp_state
*state
)
79 char buf
[1024], *p
= buf
, *col0
= buf
;
80 p
+= sprintf(p
, "Usage: %s", state
->name
);
81 int i
, indent
= p
-buf
;
82 struct argp_option
*o
= state
->argp
->options
;
84 for (i
= 0; o
[i
].name
!= NULL
; i
++) {
85 p
+= sprintf(p
, " [--%s%s%s]", o
[i
].name
, o
[i
].arg
? "=":"",
86 o
[i
].arg
? o
[i
].arg
: "");
87 if (p
-col0
> (78-state
->maxlen
)) {
88 p
+= sprintf(p
, "\n");
90 p
+= sprintf(p
, "%*s", indent
, "");
93 sprintf(p
, " %s\n", state
->argp
->arg_doc
);
98 char *cleanarg(char *s
)
100 char *v
= strrchr(s
, '/');
104 enum {ARGP_KEY_ARG
, ARGP_KEY_END
, ARGP_ERR_UNKNOWN
, ARGP_IN_ORDER
};
106 void argp_parse(struct argp
*argp
, int argc
, char **argv
, int flags
, int tmp
,
110 struct argp_state state
= {.name
= cleanarg(argv
[0]),
111 .input
= input
, .argp
= argp
};
113 /* calculate max "--opt=var" length */
115 struct argp_option
*opt
= argp
->options
;
116 for (i
= 0; opt
[i
].name
!= NULL
; i
++) {
117 int m
= strlen(opt
[i
].name
) +
118 (opt
[i
].arg
? 1+strlen(opt
[i
].arg
) : 0);
119 max
= (max
< m
) ? m
: max
;
121 state
.maxlen
= max
+2;
124 struct option
*long_opts
= calloc((n_opts
+3) * sizeof(*long_opts
), 1);
127 long_opts
[i
].name
= "usage";
128 long_opts
[i
++].has_arg
= no_argument
;
130 long_opts
[i
].name
= "help";
131 long_opts
[i
++].has_arg
= no_argument
;
133 for (opt
= argp
->options
; opt
->name
!= NULL
; opt
++, i
++) {
134 int has_arg
= opt
->arg
!= NULL
;
135 long_opts
[i
].name
= opt
->name
;
136 long_opts
[i
].has_arg
= has_arg
? required_argument
: no_argument
;
139 /* we only accept long arguments - return value is zero, and 'i'
140 * gives us the index into 'long_opts[]'
142 while ((c
= getopt_long(argc
, argv
, "", long_opts
, &i
)) != -1) {
148 argp
->parser(argp
->options
[i
-2].key
, optarg
, &state
);
151 while (optind
< argc
)
152 argp
->parser(ARGP_KEY_ARG
, argv
[optind
++], &state
);
153 argp
->parser(ARGP_KEY_END
, NULL
, &state
);
158 #endif /* __ARGP_H__ */