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