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