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