xref: /illumos-gate/usr/src/cmd/valtools/ckitem.c (revision dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <valtools.h>
38 #include <stdlib.h>
39 #include <locale.h>
40 #include <libintl.h>
41 #include <limits.h>
42 #include <wchar.h>
43 #include "usage.h"
44 #include "libadm.h"
45 
46 #define	BADPID	(-2)
47 #define	INVISMAXSIZE 36
48 
49 static char	*prog;
50 static char	*deflt = NULL, *prompt = NULL, *error = NULL, *help = NULL;
51 static int	kpid = BADPID;
52 static int	signo;
53 
54 static char	*label, **invis;
55 static int	ninvis = 0;
56 static int	max = 1;
57 static int	attr = CKALPHA;
58 
59 #define	MAXSIZE	128
60 #define	LSIZE	1024
61 #define	INTERR	\
62 	"%s: ERROR: internal error occurred while attempting menu setup\n"
63 #define	MYOPTS \
64 	"\t-f file             #file containing choices\n" \
65 	"\t-l label            #menu label\n" \
66 	"\t-i invis [, ...]    #invisible menu choices\n" \
67 	"\t-m max              #maximum choices user may select\n" \
68 	"\t-n                  #do not sort choices alphabetically\n" \
69 	"\t-o                  #don't prompt if only one choice\n" \
70 	"\t-u                  #unnumbered choices\n"
71 
72 static const char	husage[] = "Wh";
73 static const char	eusage[] = "We";
74 
75 static void
76 usage(void)
77 {
78 	switch (*prog) {
79 	default:
80 		(void) fprintf(stderr,
81 			gettext("usage: %s [options] [choice [...]]\n"), prog);
82 		(void) fprintf(stderr, gettext(OPTMESG));
83 		(void) fprintf(stderr, gettext(MYOPTS));
84 		(void) fprintf(stderr, gettext(STDOPTS));
85 		break;
86 
87 	case 'h':
88 		(void) fprintf(stderr,
89 			gettext("usage: %s [options] [choice [...]]\n"), prog);
90 		(void) fprintf(stderr, gettext(OPTMESG));
91 		(void) fprintf(stderr,
92 			gettext("\t-W width\n\t-h help\n"));
93 		break;
94 
95 	case 'e':
96 		(void) fprintf(stderr,
97 			gettext("usage: %s [options] [choice [...]]\n"), prog);
98 		(void) fprintf(stderr, gettext(OPTMESG));
99 		(void) fprintf(stderr,
100 			gettext("\t-W width\n\t-e error\n"));
101 		break;
102 	}
103 	exit(1);
104 }
105 
106 /*
107  * Given argv[0], return a pointer to the basename of the program.
108  */
109 static char *
110 prog_name(char *arg0)
111 {
112 	char *str;
113 
114 	/* first strip trailing '/' characters (exec() allows these!) */
115 	str = arg0 + strlen(arg0);
116 	while (str > arg0 && *--str == '/')
117 		*str = '\0';
118 	if ((str = strrchr(arg0, '/')) != NULL)
119 		return (str + 1);
120 	return (arg0);
121 }
122 
123 int
124 main(int argc, char **argv)
125 {
126 	CKMENU	*mp;
127 	FILE	*fp = NULL;
128 	int	c, i;
129 	char	**item;
130 	char	temp[LSIZE * MB_LEN_MAX];
131 	size_t	mmax;
132 	size_t invismaxsize = INVISMAXSIZE;
133 	size_t	n, r;
134 	wchar_t	wline[LSIZE], wtemp[LSIZE];
135 
136 	(void) setlocale(LC_ALL, "");
137 
138 #if	!defined(TEXT_DOMAIN)
139 #define	TEXT_DOMAIN	"SYS_TEST"
140 #endif
141 	(void) textdomain(TEXT_DOMAIN);
142 
143 	prog = prog_name(argv[0]);
144 
145 	invis = (char **)calloc(invismaxsize, sizeof (char *));
146 	if (!invis) {
147 		(void) fprintf(stderr,
148 			gettext("Not enough memory\n"));
149 			exit(1);
150 	}
151 	while ((c = getopt(argc, argv, "m:oni:l:f:ud:p:e:h:k:s:QW:?")) != EOF) {
152 		/* check for invalid option */
153 		if ((*prog == 'e') && !strchr(eusage, c))
154 			usage(); /* no valid options */
155 		if ((*prog == 'h') && !strchr(husage, c))
156 			usage();
157 
158 		switch (c) {
159 		case 'Q':
160 			ckquit = 0;
161 			break;
162 
163 		case 'W':
164 			ckwidth = atol(optarg);
165 			if (ckwidth < 0) {
166 				(void) fprintf(stderr,
167 		gettext("%s: ERROR: negative display width specified\n"),
168 					prog);
169 				exit(1);
170 			}
171 			break;
172 
173 		case 'm':
174 			max = atoi(optarg);
175 			if (max > SHRT_MAX || max < SHRT_MIN) {
176 				(void) fprintf(stderr,
177 	gettext("%s: ERROR: too large or too small max value specified\n"),
178 					prog);
179 				exit(1);
180 			}
181 			break;
182 
183 		case 'o':
184 			attr |= CKONEFLAG;
185 			break;
186 
187 		case 'n':
188 			attr &= ~CKALPHA;
189 			break;
190 
191 		case 'i':
192 			invis[ninvis++] = optarg;
193 			if (ninvis == invismaxsize) {
194 				invismaxsize += INVISMAXSIZE;
195 				invis = (char **)realloc(invis,
196 						invismaxsize * sizeof (char *));
197 				if (!invis) {
198 					(void) fprintf(stderr,
199 						gettext("Not enough memory\n"));
200 						exit(1);
201 				}
202 				(void) memset(invis + ninvis, 0,
203 					(invismaxsize - ninvis) *
204 					sizeof (char *));
205 			}
206 			break;
207 
208 		case 'l':
209 			label = optarg;
210 			break;
211 
212 		case 'f':
213 			if ((fp = fopen(optarg, "r")) == NULL) {
214 				(void) fprintf(stderr,
215 					gettext("%s: ERROR: can't open %s\n"),
216 					prog, optarg);
217 				exit(1);
218 			}
219 			break;
220 
221 		case 'u':
222 			attr |= CKUNNUM;
223 			break;
224 
225 		case 'd':
226 			deflt = optarg;
227 			break;
228 
229 		case 'p':
230 			prompt = optarg;
231 			break;
232 
233 		case 'e':
234 			error = optarg;
235 			break;
236 
237 		case 'h':
238 			help = optarg;
239 			break;
240 
241 		case 'k':
242 			kpid = atoi(optarg);
243 			break;
244 
245 		case 's':
246 			signo = atoi(optarg);
247 			break;
248 
249 		default:
250 			usage();
251 		}
252 	}
253 
254 	if (signo) {
255 		if (kpid == BADPID)
256 			usage();
257 	} else
258 		signo = SIGTERM;
259 
260 	mp = allocmenu(label, attr);
261 	if (fp) {
262 		*wtemp = L'\0';
263 		while (fgetws(wline, LSIZE, fp)) {
264 			/*
265 			 * Skip comment lines, those beginning with '#'.
266 			 * Note:  AT&T forgot this & needs the next 2 lines.
267 			 */
268 			if (*wline == L'#')
269 				continue;
270 			n = wcslen(wline);
271 			if ((n != 0) && (wline[n - 1] == L'\n'))
272 				wline[n - 1] = L'\0';
273 			/*
274 			 * if the line begins with a space character,
275 			 * this is a continuous line to the previous line.
276 			 */
277 			if (iswspace(*wline)) {
278 				(void) wcscat(wtemp, L"\n");
279 				(void) wcscat(wtemp, wline);
280 			} else {
281 				if (*wtemp) {
282 					n = wcslen(wtemp);
283 					r = wcstombs(temp, wtemp,
284 						n * MB_LEN_MAX);
285 					if (r == (size_t)-1) {
286 						(void) fprintf(stderr,
287 			gettext("Invalid character in the menu definition.\n"));
288 						exit(1);
289 					}
290 					if (setitem(mp, temp)) {
291 						(void) fprintf(stderr,
292 							gettext(INTERR), prog);
293 						exit(1);
294 					}
295 				}
296 				(void) wcscpy(wtemp, wline);
297 			}
298 		}
299 		if (*wtemp) {
300 			n = wcslen(wtemp);
301 			r = wcstombs(temp, wtemp, n * MB_LEN_MAX);
302 			if (r == (size_t)-1) {
303 				(void) fprintf(stderr,
304 			gettext("Invalid character in the menu definition.\n"));
305 				exit(1);
306 			}
307 			if (setitem(mp, temp)) {
308 				(void) fprintf(stderr, gettext(INTERR), prog);
309 				exit(1);
310 			}
311 		}
312 	}
313 
314 	while (optind < argc) {
315 		if (setitem(mp, argv[optind++])) {
316 			(void) fprintf(stderr, gettext(INTERR), prog);
317 			exit(1);
318 		}
319 	}
320 
321 	for (n = 0; n < ninvis; ) {
322 		if (setinvis(mp, invis[n++])) {
323 			(void) fprintf(stderr, gettext(INTERR), prog);
324 			exit(1);
325 		}
326 	}
327 
328 	if (*prog == 'e') {
329 		ckindent = 0;
330 		ckitem_err(mp, error);
331 		exit(0);
332 	} else if (*prog == 'h') {
333 		ckindent = 0;
334 		ckitem_hlp(mp, help);
335 		exit(0);
336 	}
337 
338 	if (max < 1) {
339 		mmax = mp->nchoices;
340 	} else {
341 		mmax = max;
342 	}
343 
344 /*
345  * if -o option is specified, mp->nchoices is 1, and if no invisible
346  * item is specified, ckitem() will consume two entries of item,
347  * even though 'max' is set to 1. So to take care of that problem, we
348  * allocate one extra element for item
349  */
350 	item = (char **)calloc(mmax+1, sizeof (char *));
351 	if (!item) {
352 		(void) fprintf(stderr,
353 			gettext("Not enough memory\n"));
354 		exit(1);
355 	}
356 	n = ckitem(mp, item, max, deflt, error, help, prompt);
357 	if (n == 3) {
358 		if (kpid > -2)
359 			(void) kill(kpid, signo);
360 		(void) puts("q");
361 	} else if (n == 0) {
362 		i = 0;
363 		while (item[i])
364 			(void) puts(item[i++]);
365 	}
366 	return (n);
367 }
368