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