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
setmsg(char * msg,char * fmt,size_t sz)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 *
p_ndigit(char * string,int * value,int n)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 *
p_date(char * string,int llim,int ulim,int ndig)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 *
p_eday(char * string,int llim,int ulim)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 *
p_month(char * string,char mnabr)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 *
p_dlm(char * string,char dchoice)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
ckdate_err(char * fmt,char * error)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
ckdate_hlp(char * fmt,char * help)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
fmtcheck(char * fmt)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
ckdate_val(char * fmt,char * input)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
ckdate(char * date,char * fmt,char * defstr,char * error,char * help,char * prompt)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