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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1997,1998 by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 /*LINTLIBRARY*/ 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <sys/types.h> 38 #include <stdlib.h> 39 #include <limits.h> 40 #include "libadm.h" 41 42 static int fmtcheck(char *); 43 44 #define MSGSIZ 64 45 #define PROMPT "Enter the date" 46 #define MESG "Please enter a date" 47 #define DEFAULT "%m/%d/%y" 48 49 static char *p_ndigit(char *, int *, int); 50 static char *p_date(char *, int, int, int); 51 static char *p_eday(char *, int, int); 52 static char *p_dlm(char *, char); 53 54 #define MLIM 9 55 #define STDIG 2 56 #define LD2 10 57 #define LD 01 58 #define UD 31 59 #define LM 01 60 #define UM 12 61 /* 62 * All digits are valid for a YY year format 63 * 70-99 refer to the 20th Century 64 * 00-69 refer to the 21st Century 65 */ 66 #define LY 00 67 #define UY 99 68 #define LCY 1970 69 #define UCY 9999 70 #define CCYY 4 71 #define DELIM1 '/' 72 #define DELIM2 '-' 73 #define BLANK ' ' 74 #define TAB ' ' 75 76 static void 77 setmsg(char *msg, char *fmt) 78 { 79 if ((fmt == NULL) || strcmp(fmt, "%D") == 0) 80 fmt = "%m/%d/%y"; 81 (void) sprintf(msg, "%s. Format is <%s>.", MESG, fmt); 82 } 83 84 static char * 85 p_ndigit(char *string, int *value, int n) 86 { 87 char *ptr; 88 int accum = 0; 89 90 if (!string) 91 return (NULL); 92 for (ptr = string; *ptr && n > 0; n--, ptr++) { 93 if (! isdigit((unsigned char)*ptr)) 94 return (NULL); 95 accum = (10 * accum) + (*ptr - '0'); 96 } 97 if (n) 98 return (NULL); 99 *value = accum; 100 return (ptr); 101 } 102 103 static char * 104 p_date(char *string, int llim, int ulim, int ndig) 105 { 106 char *ptr; 107 int begin = -1; 108 109 if (!(ptr = p_ndigit(string, &begin, ndig))) 110 return (NULL); 111 if (begin >= llim && begin <= ulim) 112 return (ptr); 113 else 114 return (NULL); 115 } 116 117 static char * 118 p_eday(char *string, int llim, int ulim) 119 { 120 char *ptr, *copy; 121 char daynum[3]; 122 int begin = -1; 123 int iday = 0; 124 int idaymax = 2; 125 126 daynum[0] = '\0'; 127 if (*string == BLANK) { 128 string++; 129 idaymax--; 130 } 131 copy = string; 132 while (isdigit((unsigned char)*copy) && (iday < idaymax)) { 133 daynum[iday] = *copy++; 134 iday++; 135 } 136 daynum[iday] = '\0'; 137 if (iday == 1) { 138 llim = 1; 139 ulim = 9; 140 } else if (iday == 2) { 141 llim = 10; 142 ulim = 31; 143 } 144 if (iday == 0) 145 return (NULL); 146 147 if (!(ptr = p_ndigit(string, &begin, iday))) 148 return (NULL); 149 150 if (begin >= llim && begin <= ulim) 151 return (ptr); 152 else 153 return (NULL); 154 } 155 156 /* p_month will parse the string for the month - abbr. form i.e. JAN - DEC */ 157 158 static char * 159 p_month(char *string, char mnabr) 160 { 161 static char *fmonth[] = { 162 "JANUARY", "FEBRUARY", "MARCH", "APRIL", 163 "MAY", "JUNE", "JULY", "AUGUST", 164 "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" 165 }; 166 static char *amonth[] = { 167 "JAN", "FEB", "MAR", "APR", "MAY", "JUN", 168 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" 169 }; 170 int ichng, icnt; 171 char *mnth[12]; 172 char *copy; 173 char mletter[MLIM]; 174 int mlen; 175 int imnth = 0; 176 int legit = 0; 177 int n = 0; 178 179 if (mnabr == 'a') { 180 mlen = 3; 181 for (icnt = 0; icnt < 12; icnt++) 182 mnth[icnt] = amonth[icnt]; 183 } else { 184 mlen = 9; 185 for (icnt = 0; icnt < 12; icnt++) 186 mnth[icnt] = fmonth[icnt]; 187 } 188 189 copy = string; 190 191 while (((islower((unsigned char)*copy)) || 192 (isupper((unsigned char)*copy))) && (imnth < mlen)) { 193 mletter[imnth] = toupper((unsigned char)*copy++); 194 imnth++; 195 } 196 mletter[imnth] = '\0'; 197 while (!(legit) && (n < 12)) { 198 if (strncmp(mletter, mnth[n], 199 (imnth = (int)strlen(mnth[n]))) == 0) 200 legit = 1; /* found legitimate string */ 201 n++; 202 } 203 if (legit) { 204 for (ichng = 0; ichng < imnth; ichng++) { 205 *string = toupper((unsigned char)*string); 206 string++; 207 } 208 209 return (string); 210 /* 211 * I know this causes side effects, but it's less 212 * code than adding in a copy for string and using that 213 */ 214 } else 215 return (NULL); 216 } 217 218 static char * 219 p_dlm(char *string, char dchoice) 220 { 221 char dlm; 222 223 224 if (! string) 225 return (NULL); 226 (void) sscanf(string, "%1c", &dlm); 227 if (dchoice == '/') 228 return (((dlm == DELIM1) || (dlm == DELIM2)) ? string+1 : NULL); 229 else 230 return ((dlm == dchoice) ? string + 1 : NULL); 231 } 232 233 int 234 ckdate_err(char *fmt, char *error) 235 { 236 char defmesg[MSGSIZ]; 237 238 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 239 return (4); 240 setmsg(defmesg, fmt); 241 puterror(stdout, defmesg, error); 242 return (0); 243 } 244 245 int 246 ckdate_hlp(char *fmt, char *help) 247 { 248 char defmesg[MSGSIZ]; 249 250 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 251 return (4); 252 setmsg(defmesg, fmt); 253 puthelp(stdout, defmesg, help); 254 return (0); 255 } 256 257 /* 258 * A little state machine that checks out the format to 259 * make sure it is acceptable. 260 * return value 1: NG 261 * return value 0: OK 262 */ 263 static int 264 fmtcheck(char *fmt) 265 { 266 int percent = 0; 267 268 while (*fmt) { 269 switch (*fmt++) { 270 case '%': /* previous state must be start or letter */ 271 if (percent == 0) 272 percent = 1; 273 else 274 return (1); 275 break; 276 case 'd': /* previous state must be "%" */ 277 case 'e': 278 case 'm': 279 case 'y': 280 case 'Y': 281 case 'D': 282 case 'h': 283 case 'b': 284 case 'B': 285 if (percent == 1) 286 percent = 0; 287 else 288 return (1); 289 break; 290 case TAB: /* previous state must be start or letter */ 291 case BLANK: 292 case DELIM1: 293 case DELIM2: 294 if (percent == 1) 295 return (1); 296 break; 297 default: 298 return (1); 299 } 300 } 301 return (percent); 302 } 303 304 int 305 ckdate_val(char *fmt, char *input) 306 { 307 char ltrl, dfl; 308 int valid = 1; /* time of day string is valid for format */ 309 310 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 311 return (4); 312 313 if (fmt == NULL) 314 fmt = DEFAULT; 315 ltrl = '\0'; 316 while (*fmt && valid) { 317 if ((*fmt) == '%') { 318 fmt++; 319 switch (*fmt) { 320 case 'd': 321 input = p_date(input, LD, UD, STDIG); 322 if (!input) 323 valid = 0; 324 break; 325 326 case 'e': 327 input = p_eday(input, LD2, UD); 328 if (!input) 329 valid = 0; 330 break; 331 332 case 'm': 333 input = p_date(input, LM, UM, STDIG); 334 if (!input) 335 valid = 0; 336 break; 337 338 case 'y': 339 input = p_date(input, LY, UY, STDIG); 340 if (!input) 341 valid = 0; 342 break; 343 344 case 'Y': 345 input = p_date(input, LCY, UCY, CCYY); 346 if (!input) 347 valid = 0; 348 break; 349 350 case 'D': 351 input = p_date(input, LM, UM, STDIG); 352 if (!input) { 353 valid = 0; 354 break; 355 } 356 input = p_dlm(input, DELIM1); 357 if (!input) { 358 valid = 0; 359 break; 360 } 361 input = p_date(input, LD, UD, STDIG); 362 if (!input) { 363 valid = 0; 364 break; 365 } 366 input = p_dlm(input, DELIM1); 367 if (!input) { 368 valid = 0; 369 break; 370 } 371 input = p_date(input, LY, UY, STDIG); 372 if (!input) 373 valid = 0; 374 break; 375 376 case 'h': 377 case 'b': 378 input = p_month(input, 'a'); 379 if (!input) 380 valid = 0; 381 break; 382 383 case 'B': 384 input = p_month(input, 'f'); 385 if (!input) 386 valid = 0; 387 break; 388 389 default: 390 (void) sscanf(input, "%1c", <rl); 391 input++; 392 } 393 } else { 394 dfl = '\0'; 395 (void) sscanf(input, "%1c", &dfl); 396 input++; 397 } 398 fmt++; 399 } /* end of while fmt and valid */ 400 401 if ((*fmt == NULL) && ((input != NULL) && *input != 0)) { 402 if (*input != NULL) 403 valid = 0; 404 } 405 return ((valid == 0)); 406 } 407 408 int 409 ckdate(char *date, char *fmt, char *defstr, char *error, char *help, 410 char *prompt) 411 { 412 char defmesg[MSGSIZ]; 413 char input[MAX_INPUT]; 414 char *ept, end[128]; 415 416 ept = end; 417 *ept = '\0'; 418 419 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 420 return (4); 421 422 setmsg(defmesg, fmt); 423 (void) sprintf(ept, "[?,q]"); 424 425 if (!prompt) 426 prompt = PROMPT; 427 428 start: 429 putprmpt(stderr, prompt, NULL, defstr); 430 if (getinput(input)) 431 return (1); 432 433 if (!strlen(input)) { 434 if (defstr) { 435 (void) strcpy(date, defstr); 436 return (0); 437 } 438 puterror(stderr, defmesg, error); 439 goto start; 440 } else if (strcmp(input, "?") == 0) { 441 puthelp(stderr, defmesg, help); 442 goto start; 443 } else if (ckquit && strcmp(input, "q") == 0) { 444 return (3); 445 } else if (ckdate_val(fmt, input)) { 446 puterror(stderr, defmesg, error); 447 goto start; 448 } 449 (void) strcpy(date, input); 450 return (0); 451 } 452