Build Lunapaint from Contrib.
[AROS-Contrib.git] / regina / getopt.c
blob18714f8111d18fb27e63ea78bdfb54ad7297322f
1 /*----------------------------------------------------*- Fundamental -*-
3 Module: getopt() [X/OPEN]
5 File: getopt.c
7 Assoc. files: config.h (but see below)
9 Description: This module implements a command line parser. It
10 returns option flags (specified by the user) and
11 associated values (if any) to the calling program.
13 Notes: This module began life as a Pascal routine for Oregon
14 Software's Pascal-2 compiler, and was later rewritten
15 into C.
17 Acknowl.: Some features of the AT&T public domain getopt()
18 released to Usenet have been incorporated:
20 * It is now possible to use syscalls for error
21 messages. I disagree slightly with this: the
22 only reason I can think of is to avoid getting
23 the stdio-package in linkage. getopt() is likely
24 to be used in programs where code size is a minor
25 issue. However, I've made it configurable.
27 Author: Anders Thulin
28 Rydsvagen 288
29 S-582 50 Linkoping
30 SWEDEN
32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34 This program/module/routine has been developed as a part of `The Source Code
35 Project', a personal attempt at producing well-written, portable software
36 primarily intended to be executed in the ANSI C and POSIX / X/OPEN Unix
37 environments.
39 The program/module/routine is hereby placed in the public domain, which
40 means that it may be freely copied, sold for profit or for fun, praised or
41 buried as your fancy takes you.
43 Comments on the portability and adaptability of the program/module/routine
44 will be appreciated, and, if they result in modifications, acknowledged in
45 future releases.
47 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49 Edit history :
51 Vers Ed Date By Comments
52 ---- --- ---------- ---------------- -------------------------------
53 1.0 0 1987-12-18 Anders Thulin Initial version
54 1 1988-06-06 Anders Thulin Got a copy of the AT&T public
55 domain getopt(). Changed
56 a few things to the better.
58 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
60 /* #include "config.h" -- included below: */
62 /*----------------------------------------------------*- Fundamental -*-
64 Module: getopt(3c)
66 File: config.h
68 Associated files: getopt.c
70 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
72 /*--- Configuration: ------------------------------------------------
74 getopt() may write error messages to stderr.
76 USE_STDIO == 0 Use write(2, ...) for error messages
77 USE_STDIO == 1 Use fprintf(stderr, ...) for error messages
79 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
81 #define USE_STDIO 1 /* Default is 1 */
83 /* -- end of "config.h" */
85 #include <assert.h>
86 #include <stdio.h> /* for EOF and (optionally) fprintf() */
87 #include <string.h>
89 char *optarg = (char *) 0; /* Points to option argument (if any) */
90 int opterr = 1; /* Enable error reporting */
91 int optind = 1; /* Begin with argv[optind] */
94 #define BUMP(p) (*++p == '\0' ? (optind++, (char *) 0) : p)
96 #if USE_STDIO
97 # define ERROR(pname, s, ch) \
98 do { \
99 if (opterr != 0) { \
100 fprintf(stderr, "%s: %s -- '%c'\n", pname, (s), (ch)); \
102 } while (0)
103 #else
104 # define ERROR(pname, s, c) do { \
105 if (opterr != 0) { \
106 #if __STDC__ != 0 \
107 extern int write(int, char *, unsigned); \
108 #else \
109 extern int write(); \
110 #endif \
111 char errbuf[4]; \
112 errbuf[0] = errbuf[2] = '\''; \
113 errbuf[1] = (c); errbuf[3] = '\0'; \
114 write(2, (pname), strlen(pname)); \
115 write(2, ": " s " -- ", strlen(s)+6); \
116 write(2, errbuf, strlen(errbuf)); \
118 } while (1 == 0)
119 #endif /* USE_STDIO */
122 /*----------------------------------------------------------------------
124 Routine: getopt
126 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
128 int getopt(int argc, char * const argv[], const char *optstring)
130 static char *ap = (char *) 0;
131 char *vp;
132 char ch;
134 optarg = (char *) 0; /* Presume no-argument option */
136 if (optind >= argc) { /* Reached end of argv[] */
137 return EOF;
141 * ap points into argv[optind], and is used to keep track of how far
142 * we have parsed the current option string. Remember that an argv[]
143 * string may contain several separate option letters (e.g. the line
144 * 'foo -abc -x -y' contains five option letters, but only three
145 * arguments).
147 * If ap == 0, we have reached a new string. Check that it *is* a
148 * legal option, that is:
150 * + check that the first character is '-'
151 * + check that the string isn't "-"
152 * + check that the string isn't "--"
156 if (ap == (char *) 0) {
157 ap = argv[optind];
159 if (*ap != '-') { /* Doesn't begin with '-' -- not an option */
160 ap = (char *) 0;
161 return EOF;
164 ap++; /* Examine second character */
166 if (*ap == '\0') { /* String was "-" -- not an option */
167 ap = (char *) 0;
168 return EOF;
171 if (*ap == '-' && *(ap+1) == '\0') { /* String is "--" -- n.a.o. */
172 ap = (char *) 0;
173 optind++;
174 return EOF;
179 * At this point we know that the string appears to be an option string.
180 * Check that the current character really is one of those specified in
181 * 'optstring' (remember, ':' is NOT a permissible option character, as
182 * it is used in optstring to specify that the option takes an argument).
184 * Also note that strchr() treats the terminating NUL character as a part
185 * of the string -- hence strchr() always finds NUL in optstring. The
186 * routine relies on ch never taking the value NUL.
190 ch = *ap;
191 assert(ch != '\0');
193 if (ch == ':' || (vp = strchr(optstring, ch)) == (char *) 0) {
194 ERROR(argv[0], "illegal option", ch);
195 ap = BUMP(ap);
196 return '?';
200 * ch is a permissible option letter, and vp points to it in optstring.
201 * If it takes an argument, that is it is followed by ':' in optstring,
202 * extract the argument, and set optarg to point to it. If not, just
203 * return the option letter.
207 if (*++vp == ':') {
208 optarg = BUMP(ap);
209 if (optarg == (char *) 0) { /* option value might be in next argument */
210 if (optind >= argc) { /* No, it wasn't */
211 ERROR(argv[0], "option requires an argument", ch);
212 ch = '?';
214 else {
215 optarg = argv[optind];
218 optind++;
219 ap = (char *) 0;
221 else {
222 ap = BUMP(ap);
225 return ch;
228 #ifdef TEST
230 /*----------------------------------------------------------------------
232 Routine: main()
234 Description: This routine provides confidence testing of the
235 getopt() routine. It is rather crude at present. A
236 better way of doing things would be to build argument
237 structures in memory, sending them to getopt(), and
238 check that the returned values are as expected.
240 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
242 int main(argc, argv)
243 int argc;
244 char *argv[];
246 int c;
247 char *opts = "abcd:g0%";
249 extern char *optarg;
250 extern int optind;
252 fprintf(stderr, "optstring = '%s'\n", opts);
254 while ( (c = getopt(argc, argv, opts)) != EOF) {
255 switch(c) {
256 default :
257 fprintf(stderr, "getopt() returned unknown character (0x%x)\n", c);
258 break;
260 case '?' :
261 fprintf(stderr, "getopt() returned '?' -- error detected\n");
262 break;
264 case 'a' :
265 case 'b' :
266 case 'c' :
267 case 'g' :
268 case '0' :
269 case '%' :
270 fprintf(stderr, "getopt() returned option letter %c\n", c);
271 break;
273 case 'd' :
274 fprintf(stderr, "getopt() returned option letter %c\n", c);
275 fprintf(stderr, "option value is '%s'\n", optarg);
276 break;
281 fprintf(stderr, "end of option list detected\n");
282 if (optind < argc) {
283 fprintf(stderr, "remaining arguments are:\n");
284 for ( ; optind <argc; optind++) {
285 fprintf(stderr, "argv[%d] = '%s'\n", optind, argv[optind]);
289 return 0;
291 #endif