xref: /illumos-gate/usr/src/lib/libadm/common/cktime.c (revision c61ea5668634a215fd1c9000beb7f6d2853b3468)
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", &ltrl);
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