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 int begin = -1; 119 int iday = 0; 120 int idaymax = 2; 121 122 if (*string == BLANK) { 123 string++; 124 idaymax--; 125 } 126 copy = string; 127 while (isdigit((unsigned char)*copy) && (iday < idaymax)) { 128 copy++; 129 iday++; 130 } 131 if (iday == 1) { 132 llim = 1; 133 ulim = 9; 134 } else if (iday == 2) { 135 llim = 10; 136 ulim = 31; 137 } 138 if (iday == 0) 139 return (NULL); 140 141 if (!(ptr = p_ndigit(string, &begin, iday))) 142 return (NULL); 143 144 if (begin >= llim && begin <= ulim) 145 return (ptr); 146 else 147 return (NULL); 148 } 149 150 /* p_month will parse the string for the month - abbr. form i.e. JAN - DEC */ 151 152 static char * 153 p_month(char *string, char mnabr) 154 { 155 static char *fmonth[] = { 156 "JANUARY", "FEBRUARY", "MARCH", "APRIL", 157 "MAY", "JUNE", "JULY", "AUGUST", 158 "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" 159 }; 160 static char *amonth[] = { 161 "JAN", "FEB", "MAR", "APR", "MAY", "JUN", 162 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" 163 }; 164 int ichng, icnt; 165 char *mnth[12]; 166 char *copy; 167 char mletter[MLIM]; 168 int mlen; 169 int imnth = 0; 170 int legit = 0; 171 int n = 0; 172 173 if (mnabr == 'a') { 174 mlen = 3; 175 for (icnt = 0; icnt < 12; icnt++) 176 mnth[icnt] = amonth[icnt]; 177 } else { 178 mlen = 9; 179 for (icnt = 0; icnt < 12; icnt++) 180 mnth[icnt] = fmonth[icnt]; 181 } 182 183 copy = string; 184 185 while (((islower((unsigned char)*copy)) || 186 (isupper((unsigned char)*copy))) && (imnth < mlen)) { 187 mletter[imnth] = toupper((unsigned char)*copy++); 188 imnth++; 189 } 190 mletter[imnth] = '\0'; 191 while (!(legit) && (n < 12)) { 192 if (strncmp(mletter, mnth[n], 193 (imnth = (int)strlen(mnth[n]))) == 0) 194 legit = 1; /* found legitimate string */ 195 n++; 196 } 197 if (legit) { 198 for (ichng = 0; ichng < imnth; ichng++) { 199 *string = toupper((unsigned char)*string); 200 string++; 201 } 202 203 return (string); 204 /* 205 * I know this causes side effects, but it's less 206 * code than adding in a copy for string and using that 207 */ 208 } else 209 return (NULL); 210 } 211 212 static char * 213 p_dlm(char *string, char dchoice) 214 { 215 char dlm; 216 217 218 if (! string) 219 return (NULL); 220 (void) sscanf(string, "%1c", &dlm); 221 if (dchoice == '/') 222 return (((dlm == DELIM1) || (dlm == DELIM2)) ? string+1 : NULL); 223 else 224 return ((dlm == dchoice) ? string + 1 : NULL); 225 } 226 227 int 228 ckdate_err(char *fmt, char *error) 229 { 230 char defmesg[MSGSIZ]; 231 232 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 233 return (4); 234 setmsg(defmesg, fmt, MSGSIZ); 235 puterror(stdout, defmesg, error); 236 return (0); 237 } 238 239 int 240 ckdate_hlp(char *fmt, char *help) 241 { 242 char defmesg[MSGSIZ]; 243 244 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 245 return (4); 246 setmsg(defmesg, fmt, MSGSIZ); 247 puthelp(stdout, defmesg, help); 248 return (0); 249 } 250 251 /* 252 * A little state machine that checks out the format to 253 * make sure it is acceptable. 254 * return value 1: NG 255 * return value 0: OK 256 */ 257 static int 258 fmtcheck(char *fmt) 259 { 260 int percent = 0; 261 262 while (*fmt) { 263 switch (*fmt++) { 264 case '%': /* previous state must be start or letter */ 265 if (percent == 0) 266 percent = 1; 267 else 268 return (1); 269 break; 270 case 'd': /* previous state must be "%" */ 271 case 'e': 272 case 'm': 273 case 'y': 274 case 'Y': 275 case 'D': 276 case 'h': 277 case 'b': 278 case 'B': 279 if (percent == 1) 280 percent = 0; 281 else 282 return (1); 283 break; 284 case TAB: /* previous state must be start or letter */ 285 case BLANK: 286 case DELIM1: 287 case DELIM2: 288 if (percent == 1) 289 return (1); 290 break; 291 default: 292 return (1); 293 } 294 } 295 return (percent); 296 } 297 298 int 299 ckdate_val(char *fmt, char *input) 300 { 301 char ltrl, dfl; 302 int valid = 1; /* time of day string is valid for format */ 303 304 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 305 return (4); 306 307 if (fmt == NULL) 308 fmt = DEFAULT; 309 ltrl = '\0'; 310 while (*fmt && valid) { 311 if ((*fmt) == '%') { 312 fmt++; 313 switch (*fmt) { 314 case 'd': 315 input = p_date(input, LD, UD, STDIG); 316 if (!input) 317 valid = 0; 318 break; 319 320 case 'e': 321 input = p_eday(input, LD2, UD); 322 if (!input) 323 valid = 0; 324 break; 325 326 case 'm': 327 input = p_date(input, LM, UM, STDIG); 328 if (!input) 329 valid = 0; 330 break; 331 332 case 'y': 333 input = p_date(input, LY, UY, STDIG); 334 if (!input) 335 valid = 0; 336 break; 337 338 case 'Y': 339 input = p_date(input, LCY, UCY, CCYY); 340 if (!input) 341 valid = 0; 342 break; 343 344 case 'D': 345 input = p_date(input, LM, UM, STDIG); 346 if (!input) { 347 valid = 0; 348 break; 349 } 350 input = p_dlm(input, DELIM1); 351 if (!input) { 352 valid = 0; 353 break; 354 } 355 input = p_date(input, LD, UD, STDIG); 356 if (!input) { 357 valid = 0; 358 break; 359 } 360 input = p_dlm(input, DELIM1); 361 if (!input) { 362 valid = 0; 363 break; 364 } 365 input = p_date(input, LY, UY, STDIG); 366 if (!input) 367 valid = 0; 368 break; 369 370 case 'h': 371 case 'b': 372 input = p_month(input, 'a'); 373 if (!input) 374 valid = 0; 375 break; 376 377 case 'B': 378 input = p_month(input, 'f'); 379 if (!input) 380 valid = 0; 381 break; 382 383 default: 384 (void) sscanf(input, "%1c", <rl); 385 input++; 386 } 387 } else { 388 dfl = '\0'; 389 (void) sscanf(input, "%1c", &dfl); 390 input++; 391 } 392 fmt++; 393 } /* end of while fmt and valid */ 394 395 if ((*fmt == '\0') && ((input != NULL) && *input != '\0')) { 396 valid = 0; 397 } 398 return ((valid == 0)); 399 } 400 401 int 402 ckdate(char *date, char *fmt, char *defstr, char *error, char *help, 403 char *prompt) 404 { 405 char defmesg[MSGSIZ]; 406 char input[MAX_INPUT]; 407 char *ept, end[128]; 408 409 ept = end; 410 *ept = '\0'; 411 412 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 413 return (4); 414 415 setmsg(defmesg, fmt, MSGSIZ); 416 (void) sprintf(ept, "[?,q]"); 417 418 if (!prompt) 419 prompt = PROMPT; 420 421 start: 422 putprmpt(stderr, prompt, NULL, defstr); 423 if (getinput(input)) 424 return (1); 425 426 if (!strlen(input)) { 427 if (defstr) { 428 (void) strcpy(date, defstr); 429 return (0); 430 } 431 puterror(stderr, defmesg, error); 432 goto start; 433 } else if (strcmp(input, "?") == 0) { 434 puthelp(stderr, defmesg, help); 435 goto start; 436 } else if (ckquit && strcmp(input, "q") == 0) { 437 return (3); 438 } else if (ckdate_val(fmt, input)) { 439 puterror(stderr, defmesg, error); 440 goto start; 441 } 442 (void) strcpy(date, input); 443 return (0); 444 } 445