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