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 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 32 */ 33 34 /*LINTLIBRARY*/ 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <ctype.h> 39 #include <limits.h> 40 #include <sys/types.h> 41 #include <stdlib.h> 42 #include "libadm.h" 43 44 static int fmtcheck(char *); 45 46 #define PROMPT "Enter the time of day" 47 #define ERRMSG "Please enter the time of day. Format is" 48 #define DEFAULT "%H:%M" 49 50 #define TLEN 3 51 #define LH 00 52 #define UH 23 53 #define USH 12 54 #define LM 00 55 #define UM 59 56 #define LS 00 57 #define US 59 58 #define DELIM1 ':' 59 #define BLANK ' ' 60 #define TAB ' ' 61 62 static void 63 setmsg(char *msg, char *fmt, size_t sz) 64 { 65 if (fmt == NULL) 66 fmt = DEFAULT; 67 (void) snprintf(msg, sz, "%s <%s>.", ERRMSG, fmt); 68 } 69 70 static char * 71 p_ndig(char *string, int *value) 72 { 73 char *ptr; 74 int accum = 0; 75 int n = 2; 76 77 if (!string) 78 return (0); 79 for (ptr = string; *ptr && n > 0; n--, ptr++) { 80 if (! isdigit((unsigned char)*ptr)) 81 return (NULL); 82 accum = (10 * accum) + (*ptr - '0'); 83 } 84 if (n) 85 return (NULL); 86 *value = accum; 87 return (ptr); 88 } 89 90 static char * 91 p_time(char *string, int llim, int ulim) 92 { 93 char *ptr; 94 int begin = -1; 95 if (!(ptr = p_ndig(string, &begin))) 96 return (NULL); 97 if (begin >= llim && begin <= ulim) 98 return (ptr); 99 else return (NULL); 100 } 101 102 /* p_meridian will parse the string for the meridian - AM/PM or am/pm */ 103 104 static char * 105 p_meridian(char *string) 106 { 107 static char *middle[] = { "AM", "PM", "am", "pm" }; 108 int legit, n; 109 char mid[TLEN]; 110 111 legit = 0; 112 n = 0; 113 mid[2] = '\0'; 114 (void) sscanf(string, "%2s", mid); 115 while (!(legit) && (n < 4)) { 116 if ((strncmp(mid, middle[n], 2)) == 0) 117 legit = 1; /* found legitimate string */ 118 n++; 119 } 120 if (legit) 121 return (string+2); 122 return (NULL); 123 } 124 125 static char * 126 p_delim(char *string, char dchoice) 127 { 128 char dlm; 129 130 if (! string) 131 return (NULL); 132 (void) sscanf(string, "%1c", &dlm); 133 return ((dlm == dchoice) ? string + 1 : NULL); 134 } 135 136 int 137 cktime_val(char *fmt, char *input) 138 { 139 char ltrl, dfl; 140 int valid = 1; /* time of day string is valid for format */ 141 142 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 143 return (4); 144 145 if (fmt == NULL) 146 fmt = DEFAULT; 147 ltrl = '\0'; 148 while (*fmt && valid) { 149 if ((*fmt) == '%') { 150 switch (*++fmt) { 151 case 'H': 152 input = p_time(input, LH, UH); 153 if (!input) 154 valid = 0; 155 break; 156 157 case 'M': 158 input = p_time(input, LM, UM); 159 if (!input) 160 valid = 0; 161 break; 162 163 case 'S': 164 input = p_time(input, LS, US); 165 if (!input) 166 valid = 0; 167 break; 168 169 case 'T': 170 input = p_time(input, LH, UH); 171 if (!input) { 172 valid = 0; 173 break; 174 } 175 176 input = p_delim(input, DELIM1); 177 if (!input) { 178 valid = 0; 179 break; 180 } 181 input = p_time(input, LM, UM); 182 if (!input) { 183 valid = 0; 184 break; 185 } 186 input = p_delim(input, DELIM1); 187 if (!input) { 188 valid = 0; 189 break; 190 } 191 input = p_time(input, LS, US); 192 if (!input) 193 valid = 0; 194 break; 195 196 case 'R': 197 input = p_time(input, LH, UH); 198 if (!input) { 199 valid = 0; 200 break; 201 } 202 input = p_delim(input, DELIM1); 203 if (!input) { 204 valid = 0; 205 break; 206 } 207 input = p_time(input, LM, UM); 208 if (!input) { 209 valid = 0; 210 break; 211 } 212 break; 213 214 case 'r': 215 input = p_time(input, LH, USH); 216 if (!input) { 217 valid = 0; 218 break; 219 } 220 input = p_delim(input, DELIM1); 221 if (!input) { 222 valid = 0; 223 break; 224 } 225 input = p_time(input, LM, UM); 226 if (!input) { 227 valid = 0; 228 break; 229 } 230 input = p_delim(input, DELIM1); 231 if (!input) { 232 valid = 0; 233 break; 234 } 235 input = p_time(input, LS, US); 236 if (!input) { 237 valid = 0; 238 break; 239 } 240 input = p_delim(input, BLANK); 241 if (!input) { 242 valid = 0; 243 break; 244 } 245 input = p_meridian(input); 246 if (!input) 247 valid = 0; 248 break; 249 250 case 'I': 251 input = p_time(input, LH, USH); 252 if (!input) 253 valid = 0; 254 break; 255 256 case 'p': 257 input = p_meridian(input); 258 if (!input) 259 valid = 0; 260 break; 261 262 default: 263 (void) sscanf(input++, "%1c", <rl); 264 } 265 } else { 266 dfl = '\0'; 267 (void) sscanf(input, "%1c", &dfl); 268 input++; 269 } 270 fmt++; 271 } 272 273 if (!(*fmt) && (input) && (*input)) 274 valid = 0; 275 276 return ((valid == 0)); 277 } 278 279 int 280 cktime_err(char *fmt, char *error) 281 { 282 char defmesg[128]; 283 284 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 285 return (4); 286 setmsg(defmesg, fmt, sizeof (defmesg)); 287 puterror(stdout, defmesg, error); 288 return (0); 289 } 290 291 int 292 cktime_hlp(char *fmt, char *help) 293 { 294 char defmesg[128]; 295 296 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 297 return (4); 298 setmsg(defmesg, fmt, sizeof (defmesg)); 299 puthelp(stdout, defmesg, help); 300 return (0); 301 } 302 303 /* 304 * A little state machine that checks out the format to 305 * make sure it is acceptable. 306 * return value 1: NG 307 * return value 0: OK 308 */ 309 int 310 fmtcheck(char *fmt) 311 { 312 int percent = 0; 313 314 while (*fmt) { 315 switch (*fmt++) { 316 case '%': /* previous state must be start or letter */ 317 if (percent == 0) 318 percent = 1; 319 else 320 return (1); 321 break; 322 case 'H': /* previous state must be "%" */ 323 case 'M': 324 case 'S': 325 case 'T': 326 case 'R': 327 case 'r': 328 case 'I': 329 case 'p': 330 if (percent == 1) 331 percent = 0; 332 else 333 return (1); 334 break; 335 case TAB: /* previous state must be start or letter */ 336 case BLANK: 337 case DELIM1: 338 if (percent == 1) 339 return (1); 340 break; 341 default: 342 return (1); 343 } 344 } 345 return (percent); 346 } 347 348 int 349 cktime(char *tod, char *fmt, char *defstr, char *error, char *help, 350 char *prompt) 351 { 352 char input[MAX_INPUT], 353 defmesg[128]; 354 355 if ((fmt != NULL) && (fmtcheck(fmt) == 1)) 356 return (4); 357 358 if (fmt == NULL) 359 fmt = DEFAULT; 360 setmsg(defmesg, fmt, sizeof (defmesg)); 361 if (!prompt) 362 prompt = "Enter a time of day"; 363 364 start: 365 putprmpt(stderr, prompt, NULL, defstr); 366 if (getinput(input)) 367 return (1); 368 369 if (!strlen(input)) { 370 if (defstr) { 371 (void) strcpy(tod, defstr); 372 return (0); 373 } 374 puterror(stderr, defmesg, error); 375 goto start; 376 } 377 if (strcmp(input, "?") == 0) { 378 puthelp(stderr, defmesg, help); 379 goto start; 380 } 381 if (ckquit && (strcmp(input, "q") == 0)) 382 return (3); 383 384 if (cktime_val(fmt, input)) { 385 puterror(stderr, defmesg, error); 386 goto start; 387 } 388 (void) strcpy(tod, input); 389 return (0); 390 } 391