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$
53 */
54
55static char *O_usage;
56static char *O_name;
57extern long atol();
58
59void
60pusage()
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