1 /*
2 ********************************************************************************
3 File: mygetopt.c
4
5 Tab size: 4
6 Max line length: 80
7 Programmer: Volker Kuhlmann
8
9
10 mygetopt 1.1 Copyright (C) 1997 Volker Kuhlmann
11 This program is free software under the terms of the GNU General Public License
12 version 2 (or later, at your option).
13 See the file COPYING for details about license terms and warranty.
14 <VolkerKuhlmann@gmx.de>
15
16
17 DESCRIPTION:
18
19 Function for command line argument scanning.
20 The function arguments are the same as for GNU getopt_long() and
21 getopt_long_only(), this is meant to be a (less functional!) replacement for
22 when the GNU functions are not available.
23
24 This module and its header work stand-alone and can be linked with any other
25 program.
26
27 Written with strict ANSI conformance.
28
29
30 CONDITIONALS:
31 DEBUG Generates some debugging output on stderr.
32
33
34 HISTORY:
35
36 1.1 08Dec97 Commented. Example.
37 1.1 07Dec97 Added scanning of short options, made more GNU compliant.
38 1.0 04Dec97 Created
39
40 ********************************************************************************
41 */
42
43
44
45 #include <string.h>
46
47 #ifdef DEBUG
48 #include <stdio.h>
49 #define STRNULL(charptr) ((charptr) == NULL ? "(NULL)" : (charptr))
50 #endif
51
52 #include "mygetopt.h"
53
54 #ifndef AND
55 #define AND &&
56 #endif
57
58
59
60 /* global variables (exported) */
61 int optind = 1;
62 char *optarg = NULL;
63 int optopt = '?';
64 int opterr = 1;
65
66
67
68 /*
69 My (quick) version of the GNU C library getopt_long() function.
70 Arguments are the same, though functionality is far less extensive.
71
72 No sorting of argv[] is done, scanning is terminated with the first
73 unrecognised option.
74 Short options can not be grouped together in a single word.
75 Options to both short and long options must be separated by a space (i.e.
76 be the next word on the command line). Options with optional options are
77 treated as if they required an option.
78 No abbreviations are recognised.
79
80 When returning -1, option scanning is finished and optind points to the
81 first command line word following the last option.
82 Between calls, optind shows whatever (the GNU version jumps all over the
83 place).
84 If options->flag is != NULL, it gets the value of options->val and 0 is
85 returned, otherwise options->val is returned.
86 Returns '?' when a short option is not recognised (optopt contains short
87 option), or when a long option is not recognised (optopt contains 0 and
88 optind points to the option + 1), or when a required argument is missing
89 (optopt contains the short option resp. options->val and optind points to
90 option + 1 i.e. NULL for long options).
91
92 Side: if the last recognised option requires an argument, it is returned in
93 optarg; updates optind, and optopt when returning '?'
94 In: see function arg list
95 Out: index into options array if option was recognised
96 Return: -1, 0, '?', or value
97 */
getopt_long(int argc,char * const argv[],const char * shortoptions,const struct option * options,int * lidx)98 int getopt_long (
99 int argc,
100 char *const argv[],
101 const char *shortoptions,
102 const struct option *options,
103 int *lidx)
104 {
105 int opt = 0; /* counter for option array */
106 char *thisarg;
107
108 #ifdef DEBUG
109 fprintf (stderr, "my getopt_long(), optind: %i\n", optind);
110 #endif
111 if (optind == 0) /* init */
112 optind = 1;
113 else
114 optind++; /* advance to index the currently analysed arg */
115
116 if (optind >= argc) /* finish if we run out of arguments */
117 return -1;
118
119 /* finish if this argument does not start with '-' and therefore can be no
120 option */
121 if ((thisarg = argv[optind])[0] != '-')
122 return -1;
123 thisarg++; /* advance thisarg till after '-' */
124 #ifdef DEBUG
125 fprintf (stderr, " thisarg: %s\n", thisarg);
126 #endif
127 if (thisarg[0] == '\0')
128 return -1; /* current arg is exactly "-", can't sort -> finished */
129
130 /* deal with short options */
131 if (thisarg[0] != '-') {
132 char *pc;
133
134 pc = strchr (shortoptions, thisarg[0]);
135 #ifdef DEBUG
136 fprintf (stderr, " thisarg: <%s>, strchr: <%s>\n",
137 thisarg, STRNULL(pc));
138 #endif
139 if (pc == NULL) {
140 optopt = thisarg[0]; /* illegal short option */
141 return '?';
142 }
143 if (pc[1] == ':') {
144 optind++;
145 optarg = argv[optind];
146 if (optind >= argc)
147 return optopt = pc[0], '?'; /* requires arg and none left */
148 }
149 return *pc;
150 } /* end scan short option */
151
152 if (*++thisarg == '\0') { /* if arg was -- stop opt processing */
153 optind++;
154 return -1;
155 }
156
157 /* scan long option */
158 #ifdef DEBUG
159 fprintf (stderr, " optind: %i, thisarg: %s\n", optind, thisarg);
160 #endif
161 while (options[opt].name != NULL) {
162 if (strcmp (thisarg, options[opt].name) == 0) {
163 /* have recognised option */
164 *lidx = opt;
165 if (options[opt].has_arg != no_argument) {
166 /* update *lidx, optind, optarg */
167 optind++;
168 optarg = argv[optind];
169 if ((options[opt].has_arg == required_argument)
170 && (optind >= argc))
171 /* requires arg and there is none left */
172 return optopt = options[opt].val, '?';
173 }
174 /* update flag or return val */
175 if (options[opt].flag == NULL)
176 return options[opt].val;
177 else {
178 *options[opt].flag = options[opt].val;
179 return 0;
180 }
181 }
182 opt++;
183 }
184
185 optopt = 0x00;
186 return -1; /* unrecognised option, can't sort therefore must finish */
187
188 } /* getopt_long() */
189
190
191
192 #if 0
193
194 This is an example showing how to use it.
195
196 /*
197 Parse command line and do some checks for consistency.
198 In: argc, argv
199 Out: ---
200 Return: ---
201 */
202 void scan_cmd_args (int argc, char **argv)
203 {
204 int lidx;
205 int r = 1;
206 enum {
207 o_whatever = 1,
208 o_swapwords0, o_swapwords1
209 };
210 const string shortoptions[] = "hi:o:";
211 const struct option longoptions[] = {
212 {"help", no_argument, NULL, 'h'},
213 {"usage", no_argument, cmdarg.usage, TRUE},
214 {"whatever", no_argument, NULL, o_whatever},
215 {"swapwords", no_argument, NULL, o_swapwords1},
216 {"noswapwords", no_argument, NULL, o_swapwords0},
217 {"in", required_argument, NULL, 'i'},
218 {"out", required_argument, NULL, 'o'},
219 {NULL, no_argument, NULL, 0}
220 };
221
222 optind = 0; /* tell getopt to init */
223 while (r != -1) {
224 r = getopt_long (argc, argv, shortoptions, longoptions, &lidx);
225 switch (r) {
226 case 'h':
227 cmdarg.help = TRUE;
228 break;
229 case o_swapwords1:
230 cmdarg.swapwords = TRUE;
231 break;
232 case o_swapwords0:
233 cmdarg.swapwords = FALSE;
234 break;
235 case o_whatever:
236 cmdarg.whatever = whatever;
237 break;
238 case 'i':
239 cmdarg.infilename = optarg;
240 break;
241 case 'o':
242 cmdarg.outfilename = optarg;
243 break;
244 case 0:
245 case -1:
246 break;
247 case '?':
248 /* some error, optopt knows more */
249 /* this test falls over for long options with option->val == 0 */
250 if (optopt == 0x00)
251 exit_error (ERR_CMDARG, "unknown option: ", argv[optind - 1]);
252 if ((strchr (shortoptions, optopt) != NULL)
253 OR NOT isprint (optopt))
254 exit_error (ERR_CMDARG,
255 argv[optind - 1], " requires an argument");
256 else {
257 string s[2];
258 s[0] = isprint (optopt) ? optopt : ' '; s[1] = '\0';
259 exit_error (ERR_CMDARG, "unknown short option: ", s);
260 }
261 default:
262 /* internal error */
263 }
264 }
265
266 /* remaining arguments (if any) parameters to be scanned by the user */
267 remaining = argc - optind;
268
269 } /* scan_cmd_args() */
270
271
272
273 #endif /* example */
274
275
276
277 /* EOF mygetopt.c */
278 /******************************************************************************/
279