1 /*
2 		 Copyright (c) 1991, 1992, 1995 Simon Marshall
3 
4 		   If you still end up late, don't blame me!
5 
6   Permission to use, copy, modify, distribute, and sell this software and its
7        documentation for any purpose and without fee is hereby granted,
8     provided that the above copyright notice appear in all copies and that
9 	both that copyright notice and this permission notice appear in
10 			   supporting documentation.
11 
12   This software is provided AS IS with no warranties of any kind.  The author
13     shall have no liability with respect to the infringement of copyrights,
14      trade secrets or any patents by this file or any part thereof.  In no
15       event will the author be liable for any lost revenue or profits or
16 	      other special, indirect and consequential damages.
17 */
18 
19 /*
20  * Parse times.
21  */
22 
23 
24 
25 #include "xalarm.h"
26 #include "dates.h"
27 
28 #define		VALUE(ch)	((int) (ch) - (int) '0')
29 #define		INSTRING(ch, s)	(((ch) != '\0') and (index ((s), (ch))))
30 
31 
32 long		TimeToMilliSeconds();
33 Boolean		ParseTimeString();
34 extern time_t	time();
35 extern struct tm *localtime();
36 
37 
38 
39 extern AlarmData xalarm;
40 
41 
42 
43 /*
44  * Convert the string into milliseconds, or INVALID if
45  * not recognised.
46  * Recognises quite a lot, really, but doesn't like non absolute times
47  * having "am" or "pm" etc.
48  */
49 
TimeToMilliSeconds(timestr)50 long TimeToMilliSeconds (timestr)
51   String   timestr;
52 {
53     Boolean 	in24hrformat;
54     int 	hours, minutes, seconds;
55     time_t 	abstime;
56     struct tm  *now;
57 
58     if (not ParseTimeString (timestr, &hours, &minutes, &in24hrformat))
59 	return ((long) INVALID);
60 
61     if ((*timestr == '+') or (STREQUAL (timestr, NOW)))
62 	seconds = (hours * SECSIN1HR) + (minutes * SECSIN1MIN);
63     else {
64 	(void) time (&abstime);
65 	now = localtime (&abstime);
66 	seconds = ((hours - now->tm_hour) * SECSIN1HR) +
67 	    ((minutes - now->tm_min) * SECSIN1MIN) - now->tm_sec;
68 	if ((seconds < 0) and (not in24hrformat))
69 	    seconds += (12 * SECSIN1HR);
70     }
71 
72     if ((xalarm.dateout > 0) or ((xalarm.dateout == 0) and (seconds >= 0)))
73 	return ((long) seconds * MSECSIN1SEC);
74     else {
75 	ADDERROR (TIMEPASSED, (String) NULL);
76 	return ((long) INVALID);
77     }
78 }
79 
80 
81 
82 /*
83  * Parse that string.  Robbed and hacked from xcal (3.2) by Peter
84  * Collinson et al.
85  */
86 
ParseTimeString(str,hrs,mins,in24hrf)87 Boolean ParseTimeString (str, hrs, mins, in24hrf)
88   String    str;
89   int 	   *hrs, *mins;
90   Boolean  *in24hrf;
91 {
92     enum      {Hhmm, hHmm, hh_mm, hhMm, hhmM, AmPm, aMpM} state;
93     Boolean   relative, finished = False;
94     int       numdigits = 0;
95     char     *s = str, badtime[TEXT];
96 
97     RESETERROR ();
98 
99     if (relative = (*str == '+'))
100 	str++;
101     else if (STREQUAL (str, NOW)) {
102 	*hrs = *mins = 0;
103 	return (True);
104     } else if (STREQUAL (str, NOON)) {
105 	*hrs = 12;
106 	*mins = 0;
107 	return (*in24hrf = True);
108     }
109 
110     while (*s != '\0')
111 	if (isdigit (*s++))
112 	    numdigits++;
113 
114     if (relative)
115 	switch (numdigits) {
116 	 case 1: state = hhmM; break;
117 	 case 2: state = hhMm; break;
118 	 case 3: state = hHmm; break;
119 	 case 4: state = Hhmm; break;
120 	 default:
121 	    (void) sprintf (badtime, "just %d", numdigits);
122 	    ADDERROR (WRONGNUMDIGITS, badtime);
123 	    return (False);
124 	}
125     else
126 	switch (numdigits) {
127 	 case 1:
128 	 case 2:
129 	 case 4: state = Hhmm; break;
130 	 case 3: state = hHmm; break;
131 	 default:
132 	    (void) sprintf (badtime, "just %d", numdigits);
133 	    ADDERROR (WRONGNUMDIGITS, badtime);
134 	    return (False);
135 	}
136 
137     *hrs = *mins = 0;
138     *in24hrf = False;
139 
140     while (not finished)
141 	switch (state) {
142 	 case Hhmm:
143 	    if (isdigit (*str)) {
144 		*hrs = VALUE (*str++);
145 		state = hHmm;
146 		continue;
147 	    } else {
148 		ADDERROR (UNRECOGNISED, str);
149 		return (False);
150 	    }
151 	 case hHmm:
152 	    if (isdigit (*str)) {
153 		*hrs = *hrs*10 + VALUE (*str++);
154 		state = hh_mm;
155 		continue;
156 	    }
157 	 case hh_mm:
158 	    if (INSTRING (*str, ".:-")) {
159 		state = hhMm;
160 		str++;
161 		continue;
162 	    }
163 	 case hhMm:
164 	    if (isdigit (*str)) {
165 		*mins = VALUE (*str++);
166 		state = hhmM;
167 		continue;
168 	    }
169 	 case hhmM:
170 	    if (isdigit (*str)) {
171 		*mins = *mins*10 + VALUE (*str++);
172 		state = AmPm;
173 		continue;
174 	    }
175 	 case AmPm:
176 	    if (*str == '\0') {
177 		*in24hrf = (*hrs > 12) or ((*hrs < 10) and (numdigits % 2 == 0));
178 		finished = True;
179 		continue;
180 	    } else if (relative) {
181 		ADDERROR (UNRECOGNISED, str);
182 		return (False);
183 	    }
184 
185 	    if (INSTRING (*str, "Aa")) {
186 		if (*hrs == 12)
187 		    *hrs = 0;
188 		state = aMpM;
189 		continue;
190 	    } else if (INSTRING (*str, "Pp")) {
191 		    if (*hrs < 12)
192 			*hrs = *hrs + 12;
193 		    state = aMpM;
194 		    continue;
195 		}
196 	    ADDERROR (EXPECTEDAMPM, str);
197 	    return (False);
198 	 case aMpM:
199 	    str++;
200 	    if (INSTRING (*str, "Mm")) {
201 		*in24hrf = finished = True;
202 		str++;
203 	    } else {
204 		ADDERROR (EXPECTEDAMPM, str);
205 		return (False);
206 	    }
207 	}
208 
209     if ((*hrs < 24) and (*mins < 60) and (*str == '\0'))
210 	return (True);
211     else {
212 	if (*hrs >= 24) {
213 	    (void) sprintf (badtime, "%d", *hrs);
214 	    ADDERROR (BADHOURS, badtime);
215 	} else if (*mins >= 60) {
216 	    (void) sprintf (badtime, "%d", *mins);
217 	    ADDERROR (BADMINUTES, badtime);
218 	} else {
219 	    ADDERROR (UNRECOGNISED, str);
220 	}
221 	return (False);
222     }
223 }
224