1 /*
2 * gehopt; options processing with both single-character and whole-word
3 * options both introduced with -
4 */
5
6 #include <stdio.h>
7 #include <string.h>
8
9 #include "gethopt.h"
10
11
12 void
hoptset(ctx,argc,argv)13 hoptset(ctx, argc, argv)
14 struct h_context *ctx;
15 int argc;
16 char **argv;
17 {
18 memset(ctx, 0, sizeof *ctx);
19 ctx->argc = argc;
20 ctx->argv = argv;
21 ctx->optind = 1;
22 }
23
24
25 char *
hoptarg(ctx)26 hoptarg(ctx)
27 struct h_context *ctx;
28 {
29 return ctx->optarg;
30 }
31
32 int
hoptind(ctx)33 hoptind(ctx)
34 struct h_context *ctx;
35 {
36 return ctx->optind;
37 }
38
39 char
hoptopt(ctx)40 hoptopt(ctx)
41 struct h_context *ctx;
42 {
43 return ctx->optopt;
44 }
45
46
47 int
hopterr(ctx,val)48 hopterr(ctx,val)
49 struct h_context *ctx;
50 {
51 int old = ctx->opterr;
52
53 ctx->opterr = !!val;
54 return old;
55 }
56
57
58 struct h_opt *
gethopt(ctx,opts,nropts)59 gethopt(ctx, opts, nropts)
60 struct h_context *ctx;
61 struct h_opt *opts;
62 int nropts;
63 {
64 int i;
65 int dashes;
66
67
68 if ( (ctx == 0) || ctx->optend || (ctx->optind >= ctx->argc) )
69 return 0;
70
71 ctx->optarg = 0;
72 ctx->optopt = 0;
73
74 if ( ctx->optchar == 0) {
75 /* check for leading -
76 */
77 if ( ctx->argv[ctx->optind][0] != '-' ) {
78 /* out of arguments */
79 ctx->optend = 1;
80 return 0;
81 }
82
83 if ( ctx->argv[ctx->optind][1] == 0
84 || strcmp(ctx->argv[ctx->optind], "--") == 0 ) {
85 /* option list finishes with - or -- token
86 */
87 ctx->optend = 1;
88 ctx->optind++;
89 return 0;
90 }
91
92 dashes = 1;
93 if ( ctx->argv[ctx->optind][dashes] == '-' ) {
94 /* support GNU-style long option double-dash prefix
95 * (if gethopt is passed an unknown option with a double-dash
96 * prefix, it won't match a word and then the second dash
97 * will be scanned as if it was a regular old single-character
98 * option.)
99 */
100 dashes = 2;
101 }
102
103 for ( i=0; i < nropts; i++ ) {
104 if ( ! opts[i].optword )
105 continue;
106
107 if (strcmp(opts[i].optword, dashes+(ctx->argv[ctx->optind]) ) == 0 ) {
108 if ( opts[i].opthasarg ) {
109 if ( ctx->argc > ctx->optind ) {
110 ctx->optarg = ctx->argv[ctx->optind+1];
111 ctx->optind += 2;
112 }
113 else {
114 /* word argument with required arg at end of
115 *command line
116 */
117 if ( ctx->opterr )
118 fprintf(stderr,
119 "%s: option requires an argument -- %s\n",
120 ctx->argv[0], opts[i].optword);
121 ctx->optind ++;
122 return HOPTERR;
123 }
124 }
125 else {
126 ctx->optind ++;
127 }
128 return &opts[i];
129 }
130 }
131 ctx->optchar = 1;
132 }
133
134 ctx->optopt = ctx->argv[ctx->optind][ctx->optchar++];
135
136 if ( !ctx->optopt ) {
137 /* fell off the end of this argument */
138 ctx->optind ++;
139 ctx->optchar = 0;
140 return gethopt(ctx, opts, nropts);
141 }
142
143 for ( i=0; i<nropts; i++ ) {
144 if ( opts[i].optchar == ctx->optopt ) {
145 /* found a single-char option!
146 */
147 if ( opts[i].opthasarg ) {
148 if ( ctx->argv[ctx->optind][ctx->optchar] ) {
149 /* argument immediately follows this options (-Oc)
150 */
151 ctx->optarg = &ctx->argv[ctx->optind][ctx->optchar];
152 ctx->optind ++;
153 ctx->optchar = 0;
154 }
155 else if ( ctx->optind < ctx->argc-1 ) {
156 /* argument is next arg (-O c)
157 */
158 ctx->optarg = &ctx->argv[ctx->optind+1][0];
159 ctx->optind += 2;
160 ctx->optchar = 0;
161 }
162 else {
163 /* end of arg string (-O); set optarg to null, return
164 * (should it opterr on me?)
165 */
166 ctx->optarg = 0;
167 ctx->optind ++;
168 ctx->optchar = 0;
169 if ( ctx->opterr )
170 fprintf(stderr,
171 "%s: option requires an argument -- %c\n",
172 ctx->argv[0], opts[i].optchar);
173 return HOPTERR;
174 }
175 }
176 else {
177 if ( !ctx->argv[ctx->optind][ctx->optchar] ) {
178 ctx->optind ++;
179 ctx->optchar = 0;
180 }
181 }
182 return &opts[i];
183 }
184 }
185 if ( ctx->opterr )
186 fprintf(stderr, "%s: illegal option -- %c\n", ctx->argv[0], ctx->optopt);
187 return HOPTERR;
188 }
189
190
191 void
hoptusage(char * pgm,struct h_opt opts[],int nropts,char * arguments)192 hoptusage(char *pgm, struct h_opt opts[], int nropts, char *arguments)
193 {
194 int i;
195 int optcount;
196
197 fprintf(stderr, "usage: %s", pgm);
198
199 /* print out the options that don't have flags first */
200
201 for ( optcount=i=0; i < nropts; i++ ) {
202 if ( opts[i].optchar && !opts[i].opthasarg) {
203 if (optcount == 0 )
204 fputs(" [-", stderr);
205 fputc(opts[i].optchar, stderr);
206 optcount++;
207 }
208 }
209 if ( optcount )
210 fputc(']', stderr);
211
212 /* print out the options WITH flags */
213 for ( i = 0; i < nropts; i++ )
214 if ( opts[i].optchar && opts[i].opthasarg)
215 fprintf(stderr, " [-%c %s]", opts[i].optchar, opts[i].opthasarg);
216
217 /* print out the long options */
218 for ( i = 0; i < nropts; i++ )
219 if ( opts[i].optword ) {
220 fprintf(stderr, " [-%s", opts[i].optword);
221 if ( opts[i].opthasarg )
222 fprintf(stderr, " %s", opts[i].opthasarg);
223 fputc(']', stderr);
224 }
225
226 /* print out the arguments string, if any */
227
228 if ( arguments )
229 fprintf(stderr, " %s", arguments);
230
231 /* and we're done */
232 fputc('\n', stderr);
233 }
234
235
236 #if DEBUG
237 struct h_opt opts[] = {
238 { 0, "css", 0, 1, "css file" },
239 { 1, "header", 0, 1, "header file" },
240 { 2, 0, 'a', 0, "option a (no arg)" },
241 { 3, 0, 'b', 1, "option B (with arg)" },
242 { 4, "help", '?', 0, "help message" },
243 } ;
244
245 #define NROPT (sizeof opts/sizeof opts[0])
246
247
248 int
main(argc,argv)249 main(argc, argv)
250 char **argv;
251 {
252 struct h_opt *ret;
253 struct h_context ctx;
254 int i;
255
256
257 hoptset(&ctx, argc, argv);
258 hopterr(&ctx, 1);
259
260 while (( ret = gethopt(&ctx, opts, NROPT) )) {
261
262 if ( ret != HOPTERR ) {
263 if ( ret->optword )
264 printf("%s", ret->optword);
265 else
266 printf("%c", ret->optchar);
267
268 if ( ret->opthasarg ) {
269 if ( hoptarg(&ctx) )
270 printf(" with argument \"%s\"", hoptarg(&ctx));
271 else
272 printf(" with no argument?");
273 }
274 printf(" (%s)\n", ret->optdesc);
275 }
276 }
277
278 argc -= hoptind(&ctx);
279 argv += hoptind(&ctx);
280
281 for ( i=0; i < argc; i++ )
282 printf("%d: %s\n", i, argv[i]);
283 return 0;
284 }
285
286 #endif /*DEBUG*/
287