1 /* @(#)optget.c 1.9 16/06/19 Copyright 2015-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 static UConst char sccsid[] =
4 "@(#)optget.c 1.9 16/06/19 Copyright 2015-2016 J. Schilling";
5 /*
6 * A version of getopt() that maintains state
7 * so it can be used from witin a shell builtin
8 * without being in conflict with getopts(1).
9 *
10 * Copyright (c) 2015-2016 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include "defs.h"
27
28 void
optinit(optv)29 optinit(optv)
30 struct optv *optv;
31 {
32 #ifdef __never__
33 optv->opterr = 1;
34 #else
35 optv->opterr = 0; /* In the shell, like getopt() to be quiet */
36 #endif
37 optv->optind = 1;
38 optv->optopt = 0;
39 optv->opt_sp = 1;
40 optv->optret = 0;
41 optv->ooptind = 1;
42 optv->optflag = 0;
43 optv->optarg = 0;
44 }
45
46 /*
47 * Wrapper around getopt() that helps to preserve the state of the
48 * getopts(1) builtin. This only works with the AT&T getopt() extensions
49 * introduced in 1989 for the Bourne Shell (the state variable _sp).
50 */
51 int
optget(argc,argv,optv,optstring)52 optget(argc, argv, optv, optstring)
53 int argc;
54 unsigned char **argv;
55 struct optv *optv;
56 const char *optstring;
57 {
58 int ret;
59 int savopterr;
60 int savoptind;
61 int savoptopt;
62 int savopt_sp;
63 char *savoptarg;
64
65 savopterr = opterr;
66 savoptind = optind;
67 savoptopt = optopt;
68 savopt_sp = _sp;
69 savoptarg = optarg;
70
71 opterr = optv->opterr;
72 optind = optv->optind;
73 optopt = optv->optopt;
74 _sp = optv->opt_sp;
75 optarg = optv->optarg;
76
77 optv->ooptind = optind;
78 ret = getopt(argc, (char **)argv, optstring);
79
80 optv->opterr = opterr;
81 optv->optind = optind;
82 optv->optopt = optopt;
83 optv->opt_sp = _sp;
84 optv->optret = ret;
85 optv->optarg = optarg;
86
87 opterr = savopterr;
88 optind = savoptind;
89 optopt = savoptopt;
90 _sp = savopt_sp;
91 optarg = savoptarg;
92
93 return (ret);
94 }
95
96 #ifndef NO_OPTNEXT
97 /*
98 * Routine to complain about bad option arguments.
99 */
100 void
optbad(argc,argv,optv)101 optbad(argc, argv, optv)
102 int argc;
103 unsigned char **argv;
104 struct optv *optv;
105 {
106 unsigned char *p;
107 unsigned char opt[4];
108
109 if (argc > optv->ooptind) {
110 /*
111 * This may be a long option, so print the whole argument.
112 */
113 p = locstak();
114 *p = ' ';
115 movstrstak(argv[optv->ooptind], &p[1]);
116 p += stakbot - p;
117 } else {
118 opt[0] = ' '; opt[1] = '-',
119 opt[2] = optv->optopt; opt[3] = '\0';
120 p = opt;
121 }
122 if (optv->optret == ':')
123 bfailure(argv[0], "option requires argument", p);
124 else
125 bfailure(argv[0], badopt, p);
126
127 if ((optv->optflag & OPT_SPC) && !(flags & noexit))
128 exitsh(ERROR);
129 }
130
131 /*
132 * A variant of optget() that supports the -help option.
133 * Make sure not to use 999 as a long only option identifier in optstring.
134 * Use the null string ("") if no options besides -help are supported.
135 *
136 * Returns:
137 * -1 End of args
138 * 0 -help or bad option
139 * > 0 Option character or option identifier
140 */
141 int
optnext(argc,argv,optv,optstring,use)142 optnext(argc, argv, optv, optstring, use)
143 int argc;
144 unsigned char **argv;
145 struct optv *optv;
146 const char *optstring;
147 const char *use;
148 {
149 struct optv soptv;
150 int c;
151
152 soptv = *optv;
153 if ((c = optget(argc, argv, optv, optstring)) != '?') {
154 /* EMPTY */
155 ;
156 } else if ((c = optget(argc, argv, &soptv, "()?999?(help)")) != '?') {
157 *optv = soptv;
158 }
159
160 switch (c) {
161
162 default:
163 break;
164
165 case ':': /* Option requires argument */
166 case '?': /* Bad option */
167 if (optv->optflag & OPT_NOFAIL)
168 return (c);
169 optbad(argc, argv, optv);
170 /* FALLTHROUGH */
171
172 case 999:
173 if (use)
174 gfailure((unsigned char *)usage, use);
175 return (0);
176 }
177 return (c);
178 }
179
180 /*
181 * This is the routine to enable POSIX untility syntax guidelines for builtins
182 * that do not implement options. We always implement "-help" and complain if
183 * any other (unknown) option was specified.
184 *
185 * Returns:
186 * -1 -help or bad option
187 * > 0 Arg index for next file type argument.
188 */
189 int
optskip(argc,argv,use)190 optskip(argc, argv, use)
191 int argc;
192 unsigned char **argv;
193 const char *use;
194 {
195 struct optv optv;
196 int c;
197
198 optinit(&optv);
199
200 while ((c = optnext(argc, argv, &optv, nullstr, use)) != -1) {
201 if (c == 0)
202 return (-1);
203 }
204 return (optv.optind);
205 }
206 #endif
207