Home | History | Annotate | Download | only in util
      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
     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
    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
    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
    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
    171 no_check(char *ans)
    172 {
    173 	return (yes_no_check(ans, &preg_no, &preg_yes));
    174 }
    175 
    176 int
    177 yes(void)
    178 {
    179 	return (yes_no(yes_check));
    180 }
    181 
    182 int
    183 no(void)
    184 {
    185 	return (yes_no(no_check));
    186 }
    187