1 /*
2 * mpatrol
3 * A library for controlling and tracing dynamic memory allocations.
4 * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19 * MA 02111-1307, USA.
20 */
21
22
23 /*
24 * Option parsing. Implements a routine, similar to getopt() provided on most
25 * UNIX systems, which is used to parse command line options in the mpatrol
26 * tools. Options with long names are also supported in a way that is similar
27 * to the GNU style of command line option handling.
28 */
29
30
31 #include "getopt.h"
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <limits.h>
37
38
39 #if MP_IDENT_SUPPORT
40 #ident "$Id: getopt.c,v 1.17 2002/01/08 20:13:59 graeme Exp $"
41 #else /* MP_IDENT_SUPPORT */
42 static MP_CONST MP_VOLATILE char *getopt_id = "$Id: getopt.c,v 1.17 2002/01/08 20:13:59 graeme Exp $";
43 #endif /* MP_IDENT_SUPPORT */
44
45
46 #ifdef __cplusplus
47 extern "C"
48 {
49 #endif /* __cplusplus */
50
51
52 /* The index of the current option in the command line argument array.
53 */
54
55 MP_GLOBAL unsigned long __mp_optindex;
56
57
58 /* The argument for the current option.
59 */
60
61 MP_GLOBAL char *__mp_optarg;
62
63
64 /* Strip the path component from a fully-qualified filename.
65 */
66
67 MP_GLOBAL
68 char *
__mp_basename(char * s)69 __mp_basename(char *s)
70 {
71 char *t;
72
73 #if TARGET == TARGET_UNIX
74 while (t = strchr(s, '/'))
75 #elif TARGET == TARGET_AMIGA
76 while (t = strpbrk(s, ":/"))
77 #else /* TARGET */
78 while (t = strpbrk(s, ":/\\"))
79 #endif /* TARGET */
80 s = t + 1;
81 return s;
82 }
83
84
85 /* Convert a string representation of a number to an integer,
86 * reporting any errors that occur during the conversion.
87 */
88
89 MP_GLOBAL
90 int
__mp_getnum(char * p,char * s,long * n,int u)91 __mp_getnum(char *p, char *s, long *n, int u)
92 {
93 char *t;
94 int e;
95
96 e = errno;
97 errno = 0;
98 if ((u == 1) && (*s == '-'))
99 {
100 fprintf(stderr, "%s: Illegal positive number `%s'\n", p, s);
101 t = s;
102 }
103 else if ((u == 0) && (*s == '-') && (s[1] == '0') && ((s[2] == 'b') ||
104 (s[2] == 'B')))
105 /* This is a negative binary number.
106 */
107 *n = -strtol(s + 3, &t, 2);
108 else if ((*s == '0') && ((s[1] == 'b') || (s[1] == 'B')))
109 {
110 /* This is a positive binary number.
111 */
112 if (u == 0)
113 *n = strtol(s + 2, &t, 2);
114 else
115 *n = strtoul(s + 2, &t, 2);
116 }
117 /* Otherwise let the conversion function work out the number base
118 * from the prefix.
119 */
120 else if (u == 0)
121 *n = strtol(s, &t, 0);
122 else
123 *n = strtoul(s, &t, 0);
124 if (errno == ERANGE)
125 fprintf(stderr, "%s: %s number overflow in `%s'\n", p, ((u == 0) &&
126 (*n == LONG_MIN)) ? "Negative" : "Positive", s);
127 errno = e;
128 return (*t == '\0');
129 }
130
131
132 /* Search for an option in the long options table.
133 */
134
135 static
136 option *
findopt(char * s,option * l,char ** a)137 findopt(char *s, option *l, char **a)
138 {
139 char *t;
140 size_t n;
141
142 if (t = strchr(s, '='))
143 n = t - s;
144 else
145 n = strlen(s);
146 while (l->name != NULL)
147 {
148 if ((strncmp(s, l->name, n) == 0) && (l->name[n] == '\0'))
149 {
150 if (t != NULL)
151 n++;
152 *a = s + n;
153 return l;
154 }
155 l++;
156 }
157 return NULL;
158 }
159
160
161 /* Read an option from a supplied command line argument array.
162 */
163
164 MP_GLOBAL
165 int
__mp_getopt(unsigned long n,char ** a,char * s,option * l)166 __mp_getopt(unsigned long n, char **a, char *s, option *l)
167 {
168 static char *t;
169 option *m;
170 char *b, *p;
171 int r;
172
173 __mp_optarg = NULL;
174 /* If the index of the current option is zero or if there are no more
175 * options in this argument then we proceed to the next argument.
176 */
177 if ((__mp_optindex == 0) || ((t != NULL) && (*t == '\0')))
178 {
179 __mp_optindex++;
180 t = NULL;
181 }
182 /* Get the basename of the filename that the program was invoked with so
183 * that we can use that for any diagnostics.
184 */
185 b = __mp_basename(a[0]);
186 /* If there is not a current option then attempt to locate it, otherwise
187 * return EOF if there are no more options.
188 */
189 if (t == NULL)
190 {
191 if (__mp_optindex >= n)
192 return EOF;
193 t = a[__mp_optindex];
194 /* Stop parsing options if either the argument is not an option, if it
195 * is a single dash (representing stdin) or if it is a double dash
196 * representing the end of options.
197 */
198 if ((*t != '-') || (t[1] == '\0') || ((t[1] == '-') && (t[2] == '\0')))
199 {
200 if ((*t == '-') && (t[1] == '-') && (t[2] == '\0'))
201 __mp_optindex++;
202 t = NULL;
203 return EOF;
204 }
205 t++;
206 /* Parse a long option and possibly its argument.
207 */
208 if ((*t == '-') && (l != NULL))
209 {
210 t++;
211 /* Check that the option appears in the long options table.
212 */
213 if ((m = findopt(t, l, &t)) == NULL)
214 {
215 fprintf(stderr, "%s: Illegal option `--%s'\n", b, t);
216 __mp_optindex++;
217 t = NULL;
218 return '?';
219 }
220 /* Check to see if the option takes an argument.
221 */
222 if (m->arg)
223 if (*t == '\0')
224 {
225 /* The rest of this argument is empty, so we proceed to the
226 * next argument.
227 */
228 if ((++__mp_optindex >= n) ||
229 (strcmp(a[__mp_optindex], "--") == 0))
230 {
231 fprintf(stderr, "%s: Option `--%s' requires an "
232 "argument\n", b, m->name);
233 t = NULL;
234 return '?';
235 }
236 __mp_optarg = a[__mp_optindex];
237 }
238 else
239 __mp_optarg = t;
240 else if (*t != '\0')
241 fprintf(stderr, "%s: Ignoring argument `%s' for option "
242 "`--%s'\n", b, t, m->name);
243 __mp_optindex++;
244 t = NULL;
245 return m->value;
246 }
247 }
248 /* Check that the option appears in the string of recognised options.
249 */
250 if ((*t == ':') || ((p = strchr(s, *t)) == NULL))
251 {
252 fprintf(stderr, "%s: Illegal option `-%c'\n", b, *t++);
253 return '?';
254 }
255 r = *t++;
256 /* Check to see if the option takes an argument.
257 */
258 if (p[1] == ':')
259 {
260 if (*t == '\0')
261 {
262 /* The rest of this argument is empty, so we proceed to the next
263 * argument.
264 */
265 if ((++__mp_optindex >= n) || (strcmp(a[__mp_optindex], "--") == 0))
266 {
267 fprintf(stderr, "%s: Option `-%c' requires an argument\n", b,
268 r);
269 t = NULL;
270 return '?';
271 }
272 __mp_optarg = a[__mp_optindex];
273 }
274 else
275 __mp_optarg = t;
276 __mp_optindex++;
277 t = NULL;
278 }
279 return r;
280 }
281
282
283 /* Build a string of short options letters from the long options table.
284 */
285
286 MP_GLOBAL
287 char *
__mp_shortopts(char * s,option * l)288 __mp_shortopts(char *s, option *l)
289 {
290 char *t;
291
292 t = s;
293 while (l->name != NULL)
294 {
295 if ((l->value >= SHORTOPT_MIN) && (l->value <= SHORTOPT_MAX))
296 {
297 *t++ = l->value;
298 if (l->arg)
299 *t++ = ':';
300 }
301 l++;
302 }
303 *t = '\0';
304 return s;
305 }
306
307
308 /* Display a quick-reference option summary.
309 */
310
311 MP_GLOBAL
312 void
__mp_showopts(option * l)313 __mp_showopts(option *l)
314 {
315 fputs("Options:\n", stdout);
316 while (l->name != NULL)
317 {
318 if ((l->value >= SHORTOPT_MIN) && (l->value <= SHORTOPT_MAX))
319 fprintf(stdout, " -%c", l->value);
320 else
321 fputs(" ", stdout);
322 fprintf(stdout, " --%s", l->name);
323 if (l->arg)
324 fprintf(stdout, "=<%s>", l->arg);
325 fputc('\n', stdout);
326 fputs(l->desc, stdout);
327 l++;
328 }
329 }
330
331
332 /* Perform pattern-matching with shell metacharacters.
333 */
334
335 MP_GLOBAL
336 int
__mp_match(char * s,char * t)337 __mp_match(char *s, char *t)
338 {
339 int i, n;
340 char c, d;
341
342 while ((c = *t++) != '\0')
343 if (c == '[')
344 {
345 i = 0;
346 if (n = (*t == '!'))
347 t++;
348 if ((*t == ']') || ((d = *s++) == '\0'))
349 return 0;
350 while ((c = *t++) != ']')
351 if (*t == '-')
352 {
353 if ((c <= d) && (d <= t[1]))
354 i = 1;
355 t += 2;
356 }
357 else if (c == d)
358 i = 1;
359 else if (c == '\0')
360 return 0;
361 if (i == n)
362 return 0;
363 }
364 else if (c == '*')
365 {
366 if (*t == '\0')
367 return 1;
368 do
369 if (__mp_match(s, t))
370 return 1;
371 while (*s++ != '\0');
372 return 0;
373 }
374 else if (c == '?')
375 {
376 if (*s++ == '\0')
377 return 0;
378 }
379 else if (*s++ != c)
380 return 0;
381 return (*s == '\0');
382 }
383
384
385 #ifdef __cplusplus
386 }
387 #endif /* __cplusplus */
388