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