xref: /illumos-gate/usr/src/common/util/getresponse.c (revision c536b1f9)
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 	if (yesstr)     \
443d63ea05Sas 		free(yesstr);   \
453d63ea05Sas 	if (nostr)      \
463d63ea05Sas 		free(nostr);    \
473d63ea05Sas 	if (yesexpr)    \
483d63ea05Sas 		free(yesexpr);  \
493d63ea05Sas 	if (noexpr)     \
503d63ea05Sas 		free(noexpr)
513d63ea05Sas 
523d63ea05Sas #define	SET_DEFAULT_STRS \
533d63ea05Sas 	yesstr = DEFAULT_YESSTR; \
543d63ea05Sas 	nostr = DEFAULT_NOSTR; \
553d63ea05Sas 	yesexpr = DEFAULT_YESEXPR; \
563d63ea05Sas 	noexpr = DEFAULT_NOEXPR;
573d63ea05Sas 
583d63ea05Sas /* variables used by getresponse functions */
593d63ea05Sas char    *yesstr = NULL;
603d63ea05Sas char    *nostr = NULL;
613d63ea05Sas 
623d63ea05Sas /* for regcomp()/regexec() yesexpr and noexpr */
633d63ea05Sas static regex_t preg_yes, preg_no;
643d63ea05Sas 
653d63ea05Sas /*
663d63ea05Sas  * This function compiles a regular expression that is used to match an
673d63ea05Sas  * affirmative response from the user, and also assigns the strings used
683d63ea05Sas  * in the prompts that request affirmative or negative responses.  The
693d63ea05Sas  * locale's values for YESEXPR, NOEXPR, YESSTR and NOSTR are used.
703d63ea05Sas  *
713d63ea05Sas  * If there are any problems using the locale's YESEXPR, NOEXPR, YESSTR or NOSTR
723d63ea05Sas  * values, default values of YESEXPR, YESSTR and NOSTR will be used
733d63ea05Sas  * as a fallback.  The default values are the same as the C locale values.
743d63ea05Sas  */
753d63ea05Sas int
763d63ea05Sas init_yes(void)
773d63ea05Sas {
783d63ea05Sas 	int	fallback = 0;
793d63ea05Sas 	char    *yesexpr;
803d63ea05Sas 	char	*noexpr;
813d63ea05Sas 
823d63ea05Sas 	/* get yes expression and strings for yes/no prompts */
833d63ea05Sas 	yesstr  = strdup(nl_langinfo(YESSTR));
843d63ea05Sas 	nostr   = strdup(nl_langinfo(NOSTR));
853d63ea05Sas 	yesexpr = strdup(nl_langinfo(YESEXPR));
863d63ea05Sas 	noexpr  = strdup(nl_langinfo(NOEXPR));
873d63ea05Sas 
883d63ea05Sas 	if (yesstr == NULL || nostr == NULL ||
893d63ea05Sas 	    yesexpr == NULL || noexpr == NULL) {
903d63ea05Sas 		FREE_MEM;
913d63ea05Sas 		errno = ENOMEM;
923d63ea05Sas 		return (-1);
933d63ea05Sas 	}
943d63ea05Sas 
953d63ea05Sas 	/* if problem with locale strings, use default values */
963d63ea05Sas 	if (*yesstr == '\0' || *nostr == '\0' ||
973d63ea05Sas 	    *yesexpr == '\0' || *noexpr == '\0') {
983d63ea05Sas 		FREE_MEM;
993d63ea05Sas 		SET_DEFAULT_STRS;
1003d63ea05Sas 		fallback = 1;
1013d63ea05Sas 	}
1023d63ea05Sas 	/* Compile the yes and no expressions */
1033d63ea05Sas 	while (regcomp(&preg_yes, yesexpr, REG_EXTENDED | REG_NOSUB) != 0 ||
1043d63ea05Sas 	    regcomp(&preg_no, noexpr, REG_EXTENDED | REG_NOSUB) != 0) {
1053d63ea05Sas 		if (fallback == 1) {
1063d63ea05Sas 			/* The fallback yesexpr failed, so exit */
1073d63ea05Sas 			errno = EINVAL;
1083d63ea05Sas 			return (-1);
1093d63ea05Sas 		}
1103d63ea05Sas 		/* The locale's yesexpr or noexpr failed so use fallback */
1113d63ea05Sas 		FREE_MEM;
1123d63ea05Sas 		SET_DEFAULT_STRS;
1133d63ea05Sas 		fallback = 1;
1143d63ea05Sas 	}
1153d63ea05Sas 	return (0);
1163d63ea05Sas }
1173d63ea05Sas 
1183d63ea05Sas static int
1193d63ea05Sas yes_no(int (*func)(char *))
1203d63ea05Sas {
1213d63ea05Sas 	int	i, b;
1223d63ea05Sas 	char    ans[LINE_MAX + 1];
1233d63ea05Sas 
1243d63ea05Sas 	/* Get user's answer */
125*c536b1f9SRobert Mustacchi 	i = 0;
126*c536b1f9SRobert Mustacchi 	for (;;) {
127*c536b1f9SRobert Mustacchi 		b = getchar();
1283d63ea05Sas 		if (b == '\n' || b == '\0' || b == EOF)
1293d63ea05Sas 			break;
1303d63ea05Sas 		if (i < LINE_MAX)
1313d63ea05Sas 			ans[i] = b;
132*c536b1f9SRobert Mustacchi 		i++;
1333d63ea05Sas 	}
1343d63ea05Sas 	if (i >= LINE_MAX)
1353d63ea05Sas 		ans[LINE_MAX] = '\0';
1363d63ea05Sas 	else
1373d63ea05Sas 		ans[i] = '\0';
1383d63ea05Sas 
1393d63ea05Sas 	return (func(ans));
1403d63ea05Sas }
1413d63ea05Sas 
1423d63ea05Sas static int
1433d63ea05Sas yes_no_check(char *ans, regex_t *reg1, regex_t *reg2)
1443d63ea05Sas {
1453d63ea05Sas 	if (regexec(reg1, ans, 0, NULL, 0) == 0) {
1463d63ea05Sas 		if (regexec(reg2, ans, 0, NULL, 0) == 0) {
1473d63ea05Sas 			/* Both Expressions Match (reg2 conservative) */
1483d63ea05Sas 			return (0);
1493d63ea05Sas 		}
1503d63ea05Sas 		/* Match */
1513d63ea05Sas 		return (1);
1523d63ea05Sas 	}
1533d63ea05Sas 	return (0);
1543d63ea05Sas }
1553d63ea05Sas 
1563d63ea05Sas /*
1573d63ea05Sas  * yes_check() returns 1 if the input string is matched by yesexpr and is
1583d63ea05Sas  * not matched by noexpr;  otherwise yes_check() returns 0.
1593d63ea05Sas  */
1603d63ea05Sas int
1613d63ea05Sas yes_check(char *ans)
1623d63ea05Sas {
1633d63ea05Sas 	return (yes_no_check(ans, &preg_yes, &preg_no));
1643d63ea05Sas }
1653d63ea05Sas 
1663d63ea05Sas /*
1673d63ea05Sas  * no_check() returns 1 if the input string is matched by noexpr and is
1683d63ea05Sas  * not matched by yesexpr;  otherwise no_check() returns 0.
1693d63ea05Sas  */
1703d63ea05Sas int
1713d63ea05Sas no_check(char *ans)
1723d63ea05Sas {
1733d63ea05Sas 	return (yes_no_check(ans, &preg_no, &preg_yes));
1743d63ea05Sas }
1753d63ea05Sas 
1763d63ea05Sas int
1773d63ea05Sas yes(void)
1783d63ea05Sas {
1793d63ea05Sas 	return (yes_no(yes_check));
1803d63ea05Sas }
1813d63ea05Sas 
1823d63ea05Sas int
1833d63ea05Sas no(void)
1843d63ea05Sas {
1853d63ea05Sas 	return (yes_no(no_check));
1863d63ea05Sas }
187