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