1 /*
2 * getopt() - command option parsing
3 *
4 * Gunnar Ritter, Freiburg i. Br., Germany, March 2002.
5 */
6
7 /* Sccsid @(#)getopt.c 1.7 (gritter) 12/16/07 */
8
9 #include "config.h"
10 #include <sys/types.h>
11 #ifdef HAVE_ALLOCA
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #else /* !HAVE_ALLOCA_H */
15 #include <stdlib.h>
16 #endif /* !HAVE_ALLOCA_H */
17 #endif /* HAVE_ALLOCA */
18 #include <string.h>
19
20 #ifdef HAVE_ALLOCA
21 #define ac_alloc(n) alloca(n)
22 #define ac_free(n)
23 #else /* !HAVE_ALLOCA */
24 extern void *smalloc(size_t);
25 #define ac_alloc(n) smalloc(n)
26 #define ac_free(n) free(n)
27 #endif /* !HAVE_ALLOCA */
28
29 #ifndef HAVE_SSIZE_T
30 typedef int ssize_t;
31 #endif /* !HAVE_SSIZE_T */
32
33 /*
34 * One should not think that re-implementing this is necessary, but
35 *
36 * - Some libcs print weird messages.
37 *
38 * - GNU libc getopt() is totally brain-damaged, as it requires special
39 * care _not_ to reorder parameters and can't be told to work correctly
40 * with ':' as first optstring character at all.
41 */
42
43 char *optarg;
44 int optind = 1;
45 int opterr = 1;
46 int optopt;
47
48 static void
error(const char * s,int c)49 error(const char *s, int c)
50 {
51 /*
52 * Avoid including <unistd.h>, in case its getopt() declaration
53 * conflicts.
54 */
55 extern ssize_t write(int, const void *, size_t);
56 const char *msg = 0;
57 char *buf, *bp;
58
59 switch (c) {
60 case '?':
61 msg = ": illegal option -- ";
62 break;
63 case ':':
64 msg = ": option requires an argument -- ";
65 break;
66 }
67 bp = buf = ac_alloc(strlen(s) + strlen(msg) + 2);
68 while (*s)
69 *bp++ = *s++;
70 while (*msg)
71 *bp++ = *msg++;
72 *bp++ = optopt;
73 *bp++ = '\n';
74 write(2, buf, bp - buf);
75 ac_free(buf);
76 }
77
78 int
getopt(int argc,char * const argv[],const char * optstring)79 getopt(int argc, char *const argv[], const char *optstring)
80 {
81 int colon;
82 static const char *lastp;
83 const char *curp;
84
85 if (optstring[0] == ':') {
86 colon = 1;
87 optstring++;
88 } else
89 colon = 0;
90 if (lastp) {
91 curp = lastp;
92 lastp = 0;
93 } else {
94 if (optind >= argc || argv[optind] == 0 ||
95 argv[optind][0] != '-' ||
96 argv[optind][1] == '\0')
97 return -1;
98 if (argv[optind][1] == '-' && argv[optind][2] == '\0') {
99 optind++;
100 return -1;
101 }
102 curp = &argv[optind][1];
103 }
104 optopt = curp[0] & 0377;
105 while (optstring[0]) {
106 if (optstring[0] == ':') {
107 optstring++;
108 continue;
109 }
110 if ((optstring[0] & 0377) == optopt) {
111 if (optstring[1] == ':') {
112 if (curp[1] != '\0') {
113 optarg = (char *)&curp[1];
114 optind++;
115 } else {
116 if ((optind += 2) > argc) {
117 if (!colon && opterr)
118 error(argv[0], ':');
119 return colon ? ':' : '?';
120 }
121 optarg = argv[optind - 1];
122 }
123 } else {
124 if (curp[1] != '\0')
125 lastp = &curp[1];
126 else
127 optind++;
128 optarg = 0;
129 }
130 return optopt;
131 }
132 optstring++;
133 }
134 if (!colon && opterr)
135 error(argv[0], '?');
136 if (curp[1] != '\0')
137 lastp = &curp[1];
138 else
139 optind++;
140 optarg = 0;
141 return '?';
142 }
143
144 #ifdef __APPLE__
145 /*
146 * Starting with Mac OS 10.5 Leopard, <unistd.h> turns getopt()
147 * into getopt$UNIX2003() by default. Consequently, this function
148 * is called instead of the one defined above. However, optind is
149 * still taken from this file, so in effect, options are not
150 * properly handled. Defining an own getopt$UNIX2003() function
151 * works around this issue.
152 */
153 int
getopt$UNIX2003(int argc,char * const argv[],const char * optstring)154 getopt$UNIX2003(int argc, char *const argv[], const char *optstring)
155 {
156 return getopt(argc, argv, optstring);
157 }
158 #endif /* __APPLE__ */
159