1 /*
2 * Macros for processing command arguments.
3 *
4 * Conforms closely to the command option requirements of intro(1) in System V
5 * and intro(C) in Xenix.
6 *
7 * A command consists of: cmdname [ options ] [ cmdarguments ]
8 *
9 * Options consist of a leading dash '-' and a flag letter. An argument may
10 * follow optionally preceded by white space.
11 * Options without arguments may be grouped behind a single dash.
12 * A dash on its own is interpreted as the end of the options and is retained
13 * as a command argument.
14 * A double dash '--' is interpreted as the end of the options and is discarded.
15 *
16 * For example:
17 * zap -xz -f flame -q34 -- -x
18 *
19 * where zap.c contains the following in main():
20 *
21 * OPTIONS("[-xz] [-q queue-id] [-f dump-file] user")
22 * FLAG('x', xecute)
23 * FLAG('z', zot)
24 * STRING('f', file)
25 * fp = fopen(file, "w");
26 * NUMBER('q', queue)
27 * ENDOPTS
28 *
29 * Results in:
30 * xecute = 1
31 * zot = 1
32 * file = "flame"
33 * fp = fopen("flame", "w")
34 * queue = 34
35 * argc = 2
36 * argv[0] = "zap"
37 * argv[1] = "-x"
38 *
39 * Should the user enter unknown flags or leave out required arguments,
40 * the message:
41 *
42 * Usage: zap [-xz] [-q queue-id] [-f dump-file] user
43 *
44 * will be printed. This message can be printed by calling pusage(), or
45 * usage(). usage() will also cause program termination with exit code 1.
46 *
47 * Author: Stephen McKay, February 1991
48 *
49 * Based on recollection of the original options.h produced at the University
50 * of Queensland by Ross Patterson (and possibly others).
51 *
52 * $FreeBSD: stable/10/usr.sbin/ctm/ctm_rmail/options.h 95258 2002-04-22 13:44:47Z des $
53 */
54
55 static char *O_usage;
56 static char *O_name;
57 extern long atol();
58
59 void
pusage()60 pusage()
61 {
62 /*
63 * Avoid gratuitously loading stdio.
64 */
65 write(STDERR_FILENO, "usage: ", 7);
66 write(STDERR_FILENO, O_name, strlen(O_name));
67 write(STDERR_FILENO, " ", 1);
68 write(STDERR_FILENO, O_usage, strlen(O_usage));
69 write(STDERR_FILENO, "\n", 1);
70 }
71
72 #define usage() (pusage(), exit(1))
73
74 #define OPTIONS(usage_msg) \
75 { \
76 char O_cont; \
77 O_usage = (usage_msg); \
78 O_name = argv[0]; \
79 while (*++argv && **argv == '-') \
80 { \
81 if ((*argv)[1] == '\0') \
82 break; \
83 argc--; \
84 if ((*argv)[1] == '-' && (*argv)[2] == '\0') \
85 { \
86 argv++; \
87 break; \
88 } \
89 O_cont = 1; \
90 while (O_cont) \
91 switch (*++*argv) \
92 { \
93 default: \
94 case '-': \
95 usage(); \
96 case '\0': \
97 O_cont = 0;
98
99 #define FLAG(x,flag) \
100 break; \
101 case (x): \
102 (flag) = 1;
103
104 #define CHAR(x,ch) \
105 break; \
106 case (x): \
107 O_cont = 0; \
108 if (*++*argv == '\0' && (--argc, *++argv == 0)) \
109 usage(); \
110 (ch) = **argv;
111
112 #define NUMBER(x,n) \
113 break; \
114 case (x): \
115 O_cont = 0; \
116 if (*++*argv == '\0' && (--argc, *++argv == 0)) \
117 usage(); \
118 (n) = atol(*argv);
119
120 #define STRING(x,str) \
121 break; \
122 case (x): \
123 O_cont = 0; \
124 if (*++*argv == '\0' && (--argc, *++argv == 0)) \
125 usage(); \
126 (str) = *argv;
127
128 #define SUFFIX(x,str) \
129 break; \
130 case (x): \
131 (str) = ++*argv; \
132 O_cont = 0;
133
134 #define ENDOPTS \
135 break; \
136 } \
137 } \
138 *--argv = O_name; \
139 }
140