send.c: fix compiler warnings..
[s-mailx.git] / getopt.c
blob83ce628794aca1063c892fffc91ac9a0e8fe3136
1 /*
2 * getopt() - command option parsing
4 * Gunnar Ritter, Freiburg i. Br., Germany, March 2002.
5 */
7 /* Sccsid @(#)getopt.c 1.7 (gritter) 12/16/07 */
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>
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 */
29 #ifndef HAVE_SSIZE_T
30 typedef int ssize_t;
31 #endif /* !HAVE_SSIZE_T */
34 * One should not think that re-implementing this is necessary, but
36 * - Some libcs print weird messages.
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.
43 char *optarg;
44 int optind = 1;
45 int opterr = 1;
46 int optopt;
48 static void
49 error(const char *s, int c)
52 * Avoid including <unistd.h>, in case its getopt() declaration
53 * conflicts.
55 extern ssize_t write(int, const void *, size_t);
56 const char *msg = 0;
57 char *buf, *bp;
59 switch (c) {
60 case '?':
61 msg = ": illegal option -- ";
62 break;
63 case ':':
64 msg = ": option requires an argument -- ";
65 break;
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);
78 int
79 getopt(int argc, char *const argv[], const char *optstring)
81 int colon;
82 static const char *lastp;
83 const char *curp;
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;
102 curp = &argv[optind][1];
104 optopt = curp[0] & 0377;
105 while (optstring[0]) {
106 if (optstring[0] == ':') {
107 optstring++;
108 continue;
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 ? ':' : '?';
121 optarg = argv[optind - 1];
123 } else {
124 if (curp[1] != '\0')
125 lastp = &curp[1];
126 else
127 optind++;
128 optarg = 0;
130 return optopt;
132 optstring++;
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 '?';
144 #ifdef __APPLE__
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.
154 getopt$UNIX2003(int argc, char *const argv[], const char *optstring)
156 return getopt(argc, argv, optstring);
158 #endif /* __APPLE__ */