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