xref: /illumos-gate/usr/src/common/util/getresponse.c (revision 3d63ea05cb8474d8036d3588cf8299306a994b8c)
1*3d63ea05Sas145665 /*
2*3d63ea05Sas145665  * CDDL HEADER START
3*3d63ea05Sas145665  *
4*3d63ea05Sas145665  * The contents of this file are subject to the terms of the
5*3d63ea05Sas145665  * Common Development and Distribution License (the "License").
6*3d63ea05Sas145665  * You may not use this file except in compliance with the License.
7*3d63ea05Sas145665  *
8*3d63ea05Sas145665  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3d63ea05Sas145665  * or http://www.opensolaris.org/os/licensing.
10*3d63ea05Sas145665  * See the License for the specific language governing permissions
11*3d63ea05Sas145665  * and limitations under the License.
12*3d63ea05Sas145665  *
13*3d63ea05Sas145665  * When distributing Covered Code, include this CDDL HEADER in each
14*3d63ea05Sas145665  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3d63ea05Sas145665  * If applicable, add the following below this CDDL HEADER, with the
16*3d63ea05Sas145665  * fields enclosed by brackets "[]" replaced with your own identifying
17*3d63ea05Sas145665  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3d63ea05Sas145665  *
19*3d63ea05Sas145665  * CDDL HEADER END
20*3d63ea05Sas145665  */
21*3d63ea05Sas145665 /*
22*3d63ea05Sas145665  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*3d63ea05Sas145665  * Use is subject to license terms.
24*3d63ea05Sas145665  */
25*3d63ea05Sas145665 
26*3d63ea05Sas145665 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3d63ea05Sas145665 
28*3d63ea05Sas145665 
29*3d63ea05Sas145665 #include <stdio.h>
30*3d63ea05Sas145665 #include <string.h>
31*3d63ea05Sas145665 #include <stdlib.h>
32*3d63ea05Sas145665 #include <regex.h>
33*3d63ea05Sas145665 #include <locale.h>
34*3d63ea05Sas145665 #include <langinfo.h>
35*3d63ea05Sas145665 #include <limits.h>
36*3d63ea05Sas145665 #include <errno.h>
37*3d63ea05Sas145665 #include "getresponse.h"
38*3d63ea05Sas145665 
39*3d63ea05Sas145665 /* defaults - C locale values for yesstr, nostr, yesexpr (LC_MESSAGES) */
40*3d63ea05Sas145665 #define	DEFAULT_YESSTR  "yes"
41*3d63ea05Sas145665 #define	DEFAULT_NOSTR   "no"
42*3d63ea05Sas145665 #define	DEFAULT_YESEXPR "^[yY]"
43*3d63ea05Sas145665 #define	DEFAULT_NOEXPR	"^[nN]"
44*3d63ea05Sas145665 
45*3d63ea05Sas145665 #define	FREE_MEM        \
46*3d63ea05Sas145665 	if (yesstr)     \
47*3d63ea05Sas145665 		free(yesstr);   \
48*3d63ea05Sas145665 	if (nostr)      \
49*3d63ea05Sas145665 		free(nostr);    \
50*3d63ea05Sas145665 	if (yesexpr)    \
51*3d63ea05Sas145665 		free(yesexpr);  \
52*3d63ea05Sas145665 	if (noexpr)     \
53*3d63ea05Sas145665 		free(noexpr)
54*3d63ea05Sas145665 
55*3d63ea05Sas145665 #define	SET_DEFAULT_STRS \
56*3d63ea05Sas145665 	yesstr = DEFAULT_YESSTR; \
57*3d63ea05Sas145665 	nostr = DEFAULT_NOSTR; \
58*3d63ea05Sas145665 	yesexpr = DEFAULT_YESEXPR; \
59*3d63ea05Sas145665 	noexpr = DEFAULT_NOEXPR;
60*3d63ea05Sas145665 
61*3d63ea05Sas145665 /* variables used by getresponse functions */
62*3d63ea05Sas145665 char    *yesstr = NULL;
63*3d63ea05Sas145665 char    *nostr = NULL;
64*3d63ea05Sas145665 
65*3d63ea05Sas145665 /* for regcomp()/regexec() yesexpr and noexpr */
66*3d63ea05Sas145665 static regex_t preg_yes, preg_no;
67*3d63ea05Sas145665 
68*3d63ea05Sas145665 /*
69*3d63ea05Sas145665  * This function compiles a regular expression that is used to match an
70*3d63ea05Sas145665  * affirmative response from the user, and also assigns the strings used
71*3d63ea05Sas145665  * in the prompts that request affirmative or negative responses.  The
72*3d63ea05Sas145665  * locale's values for YESEXPR, NOEXPR, YESSTR and NOSTR are used.
73*3d63ea05Sas145665  *
74*3d63ea05Sas145665  * If there are any problems using the locale's YESEXPR, NOEXPR, YESSTR or NOSTR
75*3d63ea05Sas145665  * values, default values of YESEXPR, YESSTR and NOSTR will be used
76*3d63ea05Sas145665  * as a fallback.  The default values are the same as the C locale values.
77*3d63ea05Sas145665  */
78*3d63ea05Sas145665 int
79*3d63ea05Sas145665 init_yes(void)
80*3d63ea05Sas145665 {
81*3d63ea05Sas145665 	int	fallback = 0;
82*3d63ea05Sas145665 	char    *yesexpr;
83*3d63ea05Sas145665 	char	*noexpr;
84*3d63ea05Sas145665 
85*3d63ea05Sas145665 	/* get yes expression and strings for yes/no prompts */
86*3d63ea05Sas145665 	yesstr  = strdup(nl_langinfo(YESSTR));
87*3d63ea05Sas145665 	nostr   = strdup(nl_langinfo(NOSTR));
88*3d63ea05Sas145665 	yesexpr = strdup(nl_langinfo(YESEXPR));
89*3d63ea05Sas145665 	noexpr  = strdup(nl_langinfo(NOEXPR));
90*3d63ea05Sas145665 
91*3d63ea05Sas145665 	if (yesstr == NULL || nostr == NULL ||
92*3d63ea05Sas145665 	    yesexpr == NULL || noexpr == NULL) {
93*3d63ea05Sas145665 		FREE_MEM;
94*3d63ea05Sas145665 		errno = ENOMEM;
95*3d63ea05Sas145665 		return (-1);
96*3d63ea05Sas145665 	}
97*3d63ea05Sas145665 
98*3d63ea05Sas145665 	/* if problem with locale strings, use default values */
99*3d63ea05Sas145665 	if (*yesstr == '\0' || *nostr == '\0' ||
100*3d63ea05Sas145665 	    *yesexpr == '\0' || *noexpr == '\0') {
101*3d63ea05Sas145665 		FREE_MEM;
102*3d63ea05Sas145665 		SET_DEFAULT_STRS;
103*3d63ea05Sas145665 		fallback = 1;
104*3d63ea05Sas145665 	}
105*3d63ea05Sas145665 	/* Compile the yes and no expressions */
106*3d63ea05Sas145665 	while (regcomp(&preg_yes, yesexpr, REG_EXTENDED | REG_NOSUB) != 0 ||
107*3d63ea05Sas145665 	    regcomp(&preg_no, noexpr, REG_EXTENDED | REG_NOSUB) != 0) {
108*3d63ea05Sas145665 		if (fallback == 1) {
109*3d63ea05Sas145665 			/* The fallback yesexpr failed, so exit */
110*3d63ea05Sas145665 			errno = EINVAL;
111*3d63ea05Sas145665 			return (-1);
112*3d63ea05Sas145665 		}
113*3d63ea05Sas145665 		/* The locale's yesexpr or noexpr failed so use fallback */
114*3d63ea05Sas145665 		FREE_MEM;
115*3d63ea05Sas145665 		SET_DEFAULT_STRS;
116*3d63ea05Sas145665 		fallback = 1;
117*3d63ea05Sas145665 	}
118*3d63ea05Sas145665 	return (0);
119*3d63ea05Sas145665 }
120*3d63ea05Sas145665 
121*3d63ea05Sas145665 static int
122*3d63ea05Sas145665 yes_no(int (*func)(char *))
123*3d63ea05Sas145665 {
124*3d63ea05Sas145665 	int	i, b;
125*3d63ea05Sas145665 	char    ans[LINE_MAX + 1];
126*3d63ea05Sas145665 
127*3d63ea05Sas145665 	/* Get user's answer */
128*3d63ea05Sas145665 	for (i = 0; b = getchar(); i++) {
129*3d63ea05Sas145665 		if (b == '\n' || b == '\0' || b == EOF)
130*3d63ea05Sas145665 			break;
131*3d63ea05Sas145665 		if (i < LINE_MAX)
132*3d63ea05Sas145665 			ans[i] = b;
133*3d63ea05Sas145665 	}
134*3d63ea05Sas145665 	if (i >= LINE_MAX)
135*3d63ea05Sas145665 		ans[LINE_MAX] = '\0';
136*3d63ea05Sas145665 	else
137*3d63ea05Sas145665 		ans[i] = '\0';
138*3d63ea05Sas145665 
139*3d63ea05Sas145665 	return (func(ans));
140*3d63ea05Sas145665 }
141*3d63ea05Sas145665 
142*3d63ea05Sas145665 static int
143*3d63ea05Sas145665 yes_no_check(char *ans, regex_t *reg1, regex_t *reg2)
144*3d63ea05Sas145665 {
145*3d63ea05Sas145665 	if (regexec(reg1, ans, 0, NULL, 0) == 0) {
146*3d63ea05Sas145665 		if (regexec(reg2, ans, 0, NULL, 0) == 0) {
147*3d63ea05Sas145665 			/* Both Expressions Match (reg2 conservative) */
148*3d63ea05Sas145665 			return (0);
149*3d63ea05Sas145665 		}
150*3d63ea05Sas145665 		/* Match */
151*3d63ea05Sas145665 		return (1);
152*3d63ea05Sas145665 	}
153*3d63ea05Sas145665 	return (0);
154*3d63ea05Sas145665 }
155*3d63ea05Sas145665 
156*3d63ea05Sas145665 /*
157*3d63ea05Sas145665  * yes_check() returns 1 if the input string is matched by yesexpr and is
158*3d63ea05Sas145665  * not matched by noexpr;  otherwise yes_check() returns 0.
159*3d63ea05Sas145665  */
160*3d63ea05Sas145665 int
161*3d63ea05Sas145665 yes_check(char *ans)
162*3d63ea05Sas145665 {
163*3d63ea05Sas145665 	return (yes_no_check(ans, &preg_yes, &preg_no));
164*3d63ea05Sas145665 }
165*3d63ea05Sas145665 
166*3d63ea05Sas145665 /*
167*3d63ea05Sas145665  * no_check() returns 1 if the input string is matched by noexpr and is
168*3d63ea05Sas145665  * not matched by yesexpr;  otherwise no_check() returns 0.
169*3d63ea05Sas145665  */
170*3d63ea05Sas145665 int
171*3d63ea05Sas145665 no_check(char *ans)
172*3d63ea05Sas145665 {
173*3d63ea05Sas145665 	return (yes_no_check(ans, &preg_no, &preg_yes));
174*3d63ea05Sas145665 }
175*3d63ea05Sas145665 
176*3d63ea05Sas145665 int
177*3d63ea05Sas145665 yes(void)
178*3d63ea05Sas145665 {
179*3d63ea05Sas145665 	return (yes_no(yes_check));
180*3d63ea05Sas145665 }
181*3d63ea05Sas145665 
182*3d63ea05Sas145665 int
183*3d63ea05Sas145665 no(void)
184*3d63ea05Sas145665 {
185*3d63ea05Sas145665 	return (yes_no(no_check));
186*3d63ea05Sas145665 }
187