1 /*
2  *   getlopt.c
3  *
4  *   Oliver Fromme  <olli@fromme.com>
5  *
6  *   Copyright (C) 1997,1998,1999
7  *        Oliver Fromme.  All rights reserved.
8  *
9  *   Redistribution and use in source and binary forms, with or without
10  *   modification, are permitted provided that the following conditions
11  *   are met:
12  *   1. Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *   2. Redistributions in binary form must reproduce the above copyright
15  *      notice, this list of conditions and the following disclaimer in the
16  *      documentation and/or other materials provided with the distribution.
17  *   3. Neither the name of the author nor the names of any co-contributors
18  *      may be used to endorse or promote products derived from this software
19  *      without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY OLIVER FROMME AND CONTRIBUTORS ``AS IS'' AND
22  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *   ARE DISCLAIMED.  IN NO EVENT SHALL OLIVER FROMME OR CONTRIBUTORS BE LIABLE
25  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  *   SUCH DAMAGE.
32  *
33  *   @(#)$Id: getlopt.c,v 1.3 1999/01/01 23:31:48 olli Exp $
34  */
35 
36 static const char cvsid[]
37     = "@(#)$Id: getlopt.c,v 1.3 1999/01/01 23:31:48 olli Exp $";
38 
39 #include <stdio.h>
40 #include "getlopt.h"
41 
42 int loptind = 1;	/* index in argv[] */
43 int loptchr = 0;	/* index in argv[loptind] */
44 char *loptarg;		/* points to argument if present, else to option */
45 
46 #if defined(ultrix) || defined(ULTRIX)
47 char *
strdup(char * src)48 strdup (char *src)
49 {
50 	char *dest;
51 
52 	if (!(dest = (char *) malloc(strlen(src) + 1)))
53 		return (NULL);
54 	return (strcpy(dest, src));
55 }
56 #endif
57 
58 const topt *
findopt(int islong,char * opt,const topt * opts)59 findopt (int islong, char *opt, const topt *opts)
60 {
61 	if (!opts)
62 		return (0);
63 	while (opts->lname || opts->sname) {
64 		if (islong) {
65 			if (opts->lname && !strcmp(opts->lname, opt))
66 				return (opts);
67 		}
68 		else
69 			if (opts->sname == *opt)
70 				return (opts);
71 		opts++;
72 	}
73 	return (0);
74 }
75 
76 int
performoption(int argc,char * argv[],const topt * opt)77 performoption (int argc, char *argv[], const topt *opt)
78 {
79 	int result = GLO_CONTINUE;
80 
81 	if (!(opt->flags & 1)) /* doesn't take argument */
82 		if (opt->var)
83 			if (opt->flags & 2) /* var is *char */
84 				*((char *) opt->var) = (char) opt->value;
85 			else
86 				*((int *) opt->var) = opt->value;
87 		else
88 			result = opt->value ? opt->value : opt->sname;
89 	else { /* requires argument */
90 		if (loptind >= argc)
91 			return (GLO_NOARG);
92 		loptarg = argv[loptind++]+loptchr;
93 		loptchr = 0;
94 		if (opt->var)
95 			if (opt->flags & 2) /* var is *char */
96 				*((char **) opt->var) = strdup(loptarg);
97 			else
98 				*((int *) opt->var) = atoi(loptarg);
99 		else
100 			result = opt->value ? opt->value : opt->sname;
101 	}
102 	if (opt->func)
103 		if (opt->func(loptarg) < 0)
104 			result = GLO_USERERR;
105 	return (result);
106 }
107 
108 int
getsingleopt(int argc,char * argv[],const topt * opts)109 getsingleopt (int argc, char *argv[], const topt *opts)
110 {
111 	char *thisopt;
112 	const topt *opt;
113 	static char shortopt[2] = {0, 0};
114 
115 	if (loptind >= argc)
116 		return (GLO_END);
117 	thisopt = argv[loptind];
118 	if (!loptchr) { /* start new option string */
119 		if (thisopt[0] != '-' || !thisopt[1]) /* no more options */
120 			return (GLO_END);
121 		if (thisopt[1] == '-') /* "--" */
122 			if (thisopt[2]) { /* long option */
123 				loptarg = thisopt + 2;
124 				loptind++;
125 				if (!(opt = findopt(1, thisopt + 2, opts)))
126 					return (GLO_UNKNOWN);
127 				else
128 					return (performoption(argc, argv, opt));
129 			}
130 			else { /* "--" == end of options */
131 				loptind++;
132 				return (GLO_END);
133 			}
134 		else /* start short option(s) */
135 			loptchr = 1;
136 	}
137 	shortopt[0] = thisopt[loptchr];
138 	loptarg = shortopt;
139 	opt = findopt(0, thisopt + (loptchr++), opts);
140 	if (!thisopt[loptchr]) {
141 		loptind++;
142 		loptchr = 0;
143 	}
144 	if (!opt)
145 		return (GLO_UNKNOWN);
146 	else
147 		return (performoption(argc, argv, opt));
148 }
149 
150 int
getlopt(int argc,char * argv[],const topt * opts)151 getlopt (int argc, char *argv[], const topt *opts)
152 {
153 	int result;
154 
155 	while ((result = getsingleopt(argc, argv, opts)) == GLO_CONTINUE);
156 	return (result);
157 }
158 
159 int
parselopts(int argc,char * argv[],const topt * opts,char * progname)160 parselopts (int argc, char *argv[], const topt *opts, char *progname)
161 {
162 	int result;
163 
164 	while ((result = getlopt(argc, argv, opts)))
165 		switch (result) {
166 			case GLO_UNKNOWN:
167 				fprintf (stderr, "%s: Unknown option \"%s\".\n",
168 					progname, loptarg);
169 				exit (1);
170 			case GLO_NOARG:
171 				fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
172 					progname, loptarg);
173 				exit (1);
174 			case GLO_USERERR:
175 				return result;
176 		}
177 	return result;
178 }
179 
180 /* EOF */
181