13d63ea05Sas145665 /*
23d63ea05Sas145665 * CDDL HEADER START
33d63ea05Sas145665 *
43d63ea05Sas145665 * The contents of this file are subject to the terms of the
53d63ea05Sas145665 * Common Development and Distribution License (the "License").
63d63ea05Sas145665 * You may not use this file except in compliance with the License.
73d63ea05Sas145665 *
83d63ea05Sas145665 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93d63ea05Sas145665 * or http://www.opensolaris.org/os/licensing.
103d63ea05Sas145665 * See the License for the specific language governing permissions
113d63ea05Sas145665 * and limitations under the License.
123d63ea05Sas145665 *
133d63ea05Sas145665 * When distributing Covered Code, include this CDDL HEADER in each
143d63ea05Sas145665 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153d63ea05Sas145665 * If applicable, add the following below this CDDL HEADER, with the
163d63ea05Sas145665 * fields enclosed by brackets "[]" replaced with your own identifying
173d63ea05Sas145665 * information: Portions Copyright [yyyy] [name of copyright owner]
183d63ea05Sas145665 *
193d63ea05Sas145665 * CDDL HEADER END
203d63ea05Sas145665 */
213d63ea05Sas145665 /*
223d63ea05Sas145665 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
233d63ea05Sas145665 * Use is subject to license terms.
243d63ea05Sas145665 */
253d63ea05Sas145665
263d63ea05Sas145665 #include <stdio.h>
273d63ea05Sas145665 #include <string.h>
283d63ea05Sas145665 #include <stdlib.h>
293d63ea05Sas145665 #include <regex.h>
303d63ea05Sas145665 #include <locale.h>
313d63ea05Sas145665 #include <langinfo.h>
323d63ea05Sas145665 #include <limits.h>
333d63ea05Sas145665 #include <errno.h>
343d63ea05Sas145665 #include "getresponse.h"
353d63ea05Sas145665
363d63ea05Sas145665 /* defaults - C locale values for yesstr, nostr, yesexpr (LC_MESSAGES) */
373d63ea05Sas145665 #define DEFAULT_YESSTR "yes"
383d63ea05Sas145665 #define DEFAULT_NOSTR "no"
393d63ea05Sas145665 #define DEFAULT_YESEXPR "^[yY]"
403d63ea05Sas145665 #define DEFAULT_NOEXPR "^[nN]"
413d63ea05Sas145665
423d63ea05Sas145665 #define FREE_MEM \
433d63ea05Sas145665 if (yesstr) \
443d63ea05Sas145665 free(yesstr); \
453d63ea05Sas145665 if (nostr) \
463d63ea05Sas145665 free(nostr); \
473d63ea05Sas145665 if (yesexpr) \
483d63ea05Sas145665 free(yesexpr); \
493d63ea05Sas145665 if (noexpr) \
503d63ea05Sas145665 free(noexpr)
513d63ea05Sas145665
523d63ea05Sas145665 #define SET_DEFAULT_STRS \
533d63ea05Sas145665 yesstr = DEFAULT_YESSTR; \
543d63ea05Sas145665 nostr = DEFAULT_NOSTR; \
553d63ea05Sas145665 yesexpr = DEFAULT_YESEXPR; \
563d63ea05Sas145665 noexpr = DEFAULT_NOEXPR;
573d63ea05Sas145665
583d63ea05Sas145665 /* variables used by getresponse functions */
593d63ea05Sas145665 char *yesstr = NULL;
603d63ea05Sas145665 char *nostr = NULL;
613d63ea05Sas145665
623d63ea05Sas145665 /* for regcomp()/regexec() yesexpr and noexpr */
633d63ea05Sas145665 static regex_t preg_yes, preg_no;
643d63ea05Sas145665
653d63ea05Sas145665 /*
663d63ea05Sas145665 * This function compiles a regular expression that is used to match an
673d63ea05Sas145665 * affirmative response from the user, and also assigns the strings used
683d63ea05Sas145665 * in the prompts that request affirmative or negative responses. The
693d63ea05Sas145665 * locale's values for YESEXPR, NOEXPR, YESSTR and NOSTR are used.
703d63ea05Sas145665 *
713d63ea05Sas145665 * If there are any problems using the locale's YESEXPR, NOEXPR, YESSTR or NOSTR
723d63ea05Sas145665 * values, default values of YESEXPR, YESSTR and NOSTR will be used
733d63ea05Sas145665 * as a fallback. The default values are the same as the C locale values.
743d63ea05Sas145665 */
753d63ea05Sas145665 int
init_yes(void)763d63ea05Sas145665 init_yes(void)
773d63ea05Sas145665 {
783d63ea05Sas145665 int fallback = 0;
793d63ea05Sas145665 char *yesexpr;
803d63ea05Sas145665 char *noexpr;
813d63ea05Sas145665
823d63ea05Sas145665 /* get yes expression and strings for yes/no prompts */
833d63ea05Sas145665 yesstr = strdup(nl_langinfo(YESSTR));
843d63ea05Sas145665 nostr = strdup(nl_langinfo(NOSTR));
853d63ea05Sas145665 yesexpr = strdup(nl_langinfo(YESEXPR));
863d63ea05Sas145665 noexpr = strdup(nl_langinfo(NOEXPR));
873d63ea05Sas145665
883d63ea05Sas145665 if (yesstr == NULL || nostr == NULL ||
893d63ea05Sas145665 yesexpr == NULL || noexpr == NULL) {
903d63ea05Sas145665 FREE_MEM;
913d63ea05Sas145665 errno = ENOMEM;
923d63ea05Sas145665 return (-1);
933d63ea05Sas145665 }
943d63ea05Sas145665
953d63ea05Sas145665 /* if problem with locale strings, use default values */
963d63ea05Sas145665 if (*yesstr == '\0' || *nostr == '\0' ||
973d63ea05Sas145665 *yesexpr == '\0' || *noexpr == '\0') {
983d63ea05Sas145665 FREE_MEM;
993d63ea05Sas145665 SET_DEFAULT_STRS;
1003d63ea05Sas145665 fallback = 1;
1013d63ea05Sas145665 }
1023d63ea05Sas145665 /* Compile the yes and no expressions */
1033d63ea05Sas145665 while (regcomp(&preg_yes, yesexpr, REG_EXTENDED | REG_NOSUB) != 0 ||
1043d63ea05Sas145665 regcomp(&preg_no, noexpr, REG_EXTENDED | REG_NOSUB) != 0) {
1053d63ea05Sas145665 if (fallback == 1) {
1063d63ea05Sas145665 /* The fallback yesexpr failed, so exit */
1073d63ea05Sas145665 errno = EINVAL;
1083d63ea05Sas145665 return (-1);
1093d63ea05Sas145665 }
1103d63ea05Sas145665 /* The locale's yesexpr or noexpr failed so use fallback */
1113d63ea05Sas145665 FREE_MEM;
1123d63ea05Sas145665 SET_DEFAULT_STRS;
1133d63ea05Sas145665 fallback = 1;
1143d63ea05Sas145665 }
1153d63ea05Sas145665 return (0);
1163d63ea05Sas145665 }
1173d63ea05Sas145665
1183d63ea05Sas145665 static int
yes_no(int (* func)(char *))1193d63ea05Sas145665 yes_no(int (*func)(char *))
1203d63ea05Sas145665 {
1213d63ea05Sas145665 int i, b;
1223d63ea05Sas145665 char ans[LINE_MAX + 1];
1233d63ea05Sas145665
1243d63ea05Sas145665 /* Get user's answer */
125*c536b1f9SRobert Mustacchi i = 0;
126*c536b1f9SRobert Mustacchi for (;;) {
127*c536b1f9SRobert Mustacchi b = getchar();
1283d63ea05Sas145665 if (b == '\n' || b == '\0' || b == EOF)
1293d63ea05Sas145665 break;
1303d63ea05Sas145665 if (i < LINE_MAX)
1313d63ea05Sas145665 ans[i] = b;
132*c536b1f9SRobert Mustacchi i++;
1333d63ea05Sas145665 }
1343d63ea05Sas145665 if (i >= LINE_MAX)
1353d63ea05Sas145665 ans[LINE_MAX] = '\0';
1363d63ea05Sas145665 else
1373d63ea05Sas145665 ans[i] = '\0';
1383d63ea05Sas145665
1393d63ea05Sas145665 return (func(ans));
1403d63ea05Sas145665 }
1413d63ea05Sas145665
1423d63ea05Sas145665 static int
yes_no_check(char * ans,regex_t * reg1,regex_t * reg2)1433d63ea05Sas145665 yes_no_check(char *ans, regex_t *reg1, regex_t *reg2)
1443d63ea05Sas145665 {
1453d63ea05Sas145665 if (regexec(reg1, ans, 0, NULL, 0) == 0) {
1463d63ea05Sas145665 if (regexec(reg2, ans, 0, NULL, 0) == 0) {
1473d63ea05Sas145665 /* Both Expressions Match (reg2 conservative) */
1483d63ea05Sas145665 return (0);
1493d63ea05Sas145665 }
1503d63ea05Sas145665 /* Match */
1513d63ea05Sas145665 return (1);
1523d63ea05Sas145665 }
1533d63ea05Sas145665 return (0);
1543d63ea05Sas145665 }
1553d63ea05Sas145665
1563d63ea05Sas145665 /*
1573d63ea05Sas145665 * yes_check() returns 1 if the input string is matched by yesexpr and is
1583d63ea05Sas145665 * not matched by noexpr; otherwise yes_check() returns 0.
1593d63ea05Sas145665 */
1603d63ea05Sas145665 int
yes_check(char * ans)1613d63ea05Sas145665 yes_check(char *ans)
1623d63ea05Sas145665 {
1633d63ea05Sas145665 return (yes_no_check(ans, &preg_yes, &preg_no));
1643d63ea05Sas145665 }
1653d63ea05Sas145665
1663d63ea05Sas145665 /*
1673d63ea05Sas145665 * no_check() returns 1 if the input string is matched by noexpr and is
1683d63ea05Sas145665 * not matched by yesexpr; otherwise no_check() returns 0.
1693d63ea05Sas145665 */
1703d63ea05Sas145665 int
no_check(char * ans)1713d63ea05Sas145665 no_check(char *ans)
1723d63ea05Sas145665 {
1733d63ea05Sas145665 return (yes_no_check(ans, &preg_no, &preg_yes));
1743d63ea05Sas145665 }
1753d63ea05Sas145665
1763d63ea05Sas145665 int
yes(void)1773d63ea05Sas145665 yes(void)
1783d63ea05Sas145665 {
1793d63ea05Sas145665 return (yes_no(yes_check));
1803d63ea05Sas145665 }
1813d63ea05Sas145665
1823d63ea05Sas145665 int
no(void)1833d63ea05Sas145665 no(void)
1843d63ea05Sas145665 {
1853d63ea05Sas145665 return (yes_no(no_check));
1863d63ea05Sas145665 }
187