|
|
1.1 root 1: /* time.c
2: Parse a time string into a uuconf_timespan structure.
3:
4: Copyright (C) 1992 Ian Lance Taylor
5:
6: This file is part of the Taylor UUCP uuconf library.
7:
8: This library is free software; you can redistribute it and/or
9: modify it under the terms of the GNU Library General Public License
10: as published by the Free Software Foundation; either version 2 of
11: the License, or (at your option) any later version.
12:
13: This library is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16: Library General Public License for more details.
17:
18: You should have received a copy of the GNU Library General Public
19: License along with this library; if not, write to the Free Software
20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucnfi.h"
27:
28: #if USE_RCS_ID
29: const char _uuconf_time_rcsid[] = "$Id: time.c,v 1.1 93/07/30 08:07:59 bin Exp Locker: bin $";
30: #endif
31:
32: #include <ctype.h>
33: #include <errno.h>
34:
35: static int itadd_span P((struct sglobal *qglobal, int istart, int iend,
36: long ival, int cretry,
37: int (*picmp) P((long, long)),
38: struct uuconf_timespan **pqspan,
39: pointer pblock));
40: static int itnew P((struct sglobal *qglobal, struct uuconf_timespan **pqset,
41: struct uuconf_timespan *qnext, int istart, int iend,
42: long ival, int cretry, pointer pblock));
43:
44: /* An array of weekday abbreviations. The code below assumes that
45: each one starts with a lower case letter. */
46:
47: static const struct
48: {
49: const char *zname;
50: int imin;
51: int imax;
52: } asTdays[] =
53: {
54: { "any", 0, 6 },
55: { "wk", 1, 5 },
56: { "su", 0, 0 },
57: { "mo", 1, 1 },
58: { "tu", 2, 2 },
59: { "we", 3, 3 },
60: { "th", 4, 4 },
61: { "fr", 5, 5 },
62: { "sa", 6, 6 },
63: { "never", -1, -2 },
64: { NULL, 0, 0 }
65: };
66:
67: /* Parse a time string and add it to a span list. This function is
68: given the value, the retry time, and the comparison function to
69: use. */
70:
71: int
72: _uuconf_itime_parse (qglobal, ztime, ival, cretry, picmp, pqspan, pblock)
73: struct sglobal *qglobal;
74: char *ztime;
75: long ival;
76: int cretry;
77: int (*picmp) P((long, long));
78: struct uuconf_timespan **pqspan;
79: pointer pblock;
80: {
81: struct uuconf_timespan *qlist;
82: char bfirst;
83: const char *z;
84:
85: qlist = *pqspan;
86: if (qlist == (struct uuconf_timespan *) &_uuconf_unset)
87: qlist = NULL;
88:
89: /* Expand the string using a timetable. Keep rechecking the string
90: until it does not match. */
91: while (TRUE)
92: {
93: char **pz;
94: char *zfound;
95:
96: bfirst = *ztime;
97: if (isupper (BUCHAR (bfirst)))
98: bfirst = tolower (BUCHAR (bfirst));
99:
100: zfound = NULL;
101: pz = qglobal->qprocess->pztimetables;
102:
103: /* We want the last timetable to have been defined with this
104: name, so we always look through the entire table. */
105: while (*pz != NULL)
106: {
107: if ((bfirst == (*pz)[0]
108: || (isupper (BUCHAR ((*pz)[0]))
109: && bfirst == tolower (BUCHAR ((*pz)[0]))))
110: && strcasecmp (ztime, *pz) == 0)
111: zfound = pz[1];
112: pz += 2;
113: }
114: if (zfound == NULL)
115: break;
116: ztime = zfound;
117: }
118:
119: /* Look through the time string. */
120: z = ztime;
121: while (*z != '\0')
122: {
123: int iday;
124: boolean afday[7];
125: int istart, iend;
126:
127: if (*z == ',' || *z == '|')
128: ++z;
129: if (*z == '\0' || *z == ';')
130: break;
131:
132: for (iday = 0; iday < 7; iday++)
133: afday[iday] = FALSE;
134:
135: /* Get the days. */
136: do
137: {
138: bfirst = *z;
139: if (isupper (BUCHAR (bfirst)))
140: bfirst = tolower (BUCHAR (bfirst));
141: for (iday = 0; asTdays[iday].zname != NULL; iday++)
142: {
143: size_t clen;
144:
145: if (bfirst != asTdays[iday].zname[0])
146: continue;
147:
148: clen = strlen (asTdays[iday].zname);
149: if (strncasecmp (z, asTdays[iday].zname, clen) == 0)
150: {
151: int iset;
152:
153: for (iset = asTdays[iday].imin;
154: iset <= asTdays[iday].imax;
155: iset++)
156: afday[iset] = TRUE;
157: z += clen;
158: break;
159: }
160: }
161: if (asTdays[iday].zname == NULL)
162: return UUCONF_SYNTAX_ERROR;
163: }
164: while (isalpha (BUCHAR (*z)));
165:
166: /* Get the hours. */
167: if (! isdigit (BUCHAR (*z)))
168: {
169: istart = 0;
170: iend = 24 * 60;
171: }
172: else
173: {
174: char *zendnum;
175:
176: istart = (int) strtol ((char *) z, &zendnum, 10);
177: if (*zendnum != '-' || ! isdigit (BUCHAR (zendnum[1])))
178: return UUCONF_SYNTAX_ERROR;
179: z = zendnum + 1;
180: iend = (int) strtol ((char *) z, &zendnum, 10);
181: z = zendnum;
182:
183: istart = (istart / 100) * 60 + istart % 100;
184: iend = (iend / 100) * 60 + iend % 100;
185: }
186:
187: /* Add the times we've found onto the list. */
188: for (iday = 0; iday < 7; iday++)
189: {
190: if (afday[iday])
191: {
192: int iminute, iret;
193:
194: iminute = iday * 24 * 60;
195: if (istart < iend)
196: iret = itadd_span (qglobal, iminute + istart,
197: iminute + iend, ival, cretry, picmp,
198: &qlist, pblock);
199: else
200: {
201: /* Wrap around midnight. */
202: iret = itadd_span (qglobal, iminute, iminute + iend,
203: ival, cretry, picmp, &qlist, pblock);
204: if (iret == UUCONF_SUCCESS)
205: iret = itadd_span (qglobal, iminute + istart,
206: iminute + 24 * 60, ival, cretry,
207: picmp, &qlist, pblock);
208: }
209:
210: if (iret != UUCONF_SUCCESS)
211: return iret;
212: }
213: }
214: }
215:
216: *pqspan = qlist;
217:
218: return UUCONF_SUCCESS;
219: }
220:
221: /* Add a time span to an existing list of time spans. We keep the
222: list sorted by time to make this operation easier. This modifies
223: the existing list, and returns the modified version. It takes a
224: comparison function which should return < 0 if the first argument
225: should take precedence over the second argument and == 0 if they
226: are the same (for grades this is igradecmp; for sizes it is minus
227: (the binary operator)). */
228:
229: static int
230: itadd_span (qglobal, istart, iend, ival, cretry, picmp, pqspan, pblock)
231: struct sglobal *qglobal;
232: int istart;
233: int iend;
234: long ival;
235: int cretry;
236: int (*picmp) P((long, long));
237: struct uuconf_timespan **pqspan;
238: pointer pblock;
239: {
240: struct uuconf_timespan **pq;
241: int iret;
242:
243: /* istart < iend */
244: for (pq = pqspan; *pq != NULL; pq = &(*pq)->uuconf_qnext)
245: {
246: int icmp;
247:
248: /* Invariant: PREV (*pq) == NULL || PREV (*pq)->iend <= istart */
249: /* istart < iend && (*pq)->istart < (*pq)->iend */
250:
251: if (iend <= (*pq)->uuconf_istart)
252: {
253: /* istart < iend <= (*pq)->istart < (*pq)->iend */
254: /* No overlap, and we're at the right spot. See if we can
255: combine these spans. */
256: if (iend == (*pq)->uuconf_istart
257: && cretry == (*pq)->uuconf_cretry
258: && (*picmp) (ival, (*pq)->uuconf_ival) == 0)
259: {
260: (*pq)->uuconf_istart = istart;
261: return UUCONF_SUCCESS;
262: }
263: /* We couldn't combine them. */
264: break;
265: }
266:
267: if ((*pq)->uuconf_iend <= istart)
268: {
269: /* (*pq)->istart < (*pq)->iend <= istart < iend */
270: /* No overlap. Try attaching this span. */
271: if ((*pq)->uuconf_iend == istart
272: && (*pq)->uuconf_cretry == cretry
273: && ((*pq)->uuconf_qnext == NULL
274: || iend <= (*pq)->uuconf_qnext->uuconf_istart)
275: && (*picmp) (ival, (*pq)->uuconf_ival) == 0)
276: {
277: (*pq)->uuconf_iend = iend;
278: return UUCONF_SUCCESS;
279: }
280: /* Couldn't attach; keep looking for the right spot. We
281: might be able to combine part of the new span onto an
282: existing span, but it's probably not worth it. */
283: continue;
284: }
285:
286: /* istart < iend
287: && (*pq)->istart < (*pq)->iend
288: && istart < (*pq)->iend
289: && (*pq)->istart < iend */
290: /* Overlap. */
291:
292: icmp = (*picmp) (ival, (*pq)->uuconf_ival);
293:
294: if (icmp == 0)
295: {
296: /* Just expand the old span to include the new span. */
297: if (istart < (*pq)->uuconf_istart)
298: (*pq)->uuconf_istart = istart;
299: if ((*pq)->uuconf_iend >= iend)
300: return UUCONF_SUCCESS;
301: if ((*pq)->uuconf_qnext == NULL
302: || iend <= (*pq)->uuconf_qnext->uuconf_istart)
303: {
304: (*pq)->uuconf_iend = iend;
305: return UUCONF_SUCCESS;
306: }
307: /* The span we are adding overlaps the next span as well.
308: Expand the old span up to the next old span, and keep
309: trying to add the new span. */
310: (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart;
311: istart = (*pq)->uuconf_iend;
312: }
313: else if (icmp < 0)
314: {
315: /* Replace the old span with the new span. */
316: if ((*pq)->uuconf_istart < istart)
317: {
318: /* Save the initial portion of the old span. */
319: iret = itnew (qglobal, pq, *pq, (*pq)->uuconf_istart, istart,
320: (*pq)->uuconf_ival, (*pq)->uuconf_cretry,
321: pblock);
322: if (iret != UUCONF_SUCCESS)
323: return iret;
324: pq = &(*pq)->uuconf_qnext;
325: }
326: if (iend < (*pq)->uuconf_iend)
327: {
328: /* Save the final portion of the old span. */
329: iret = itnew (qglobal, &(*pq)->uuconf_qnext,
330: (*pq)->uuconf_qnext, iend, (*pq)->uuconf_iend,
331: (*pq)->uuconf_ival, (*pq)->uuconf_cretry,
332: pblock);
333: if (iret != UUCONF_SUCCESS)
334: return iret;
335: }
336: (*pq)->uuconf_ival = ival;
337: (*pq)->uuconf_istart = istart;
338: (*pq)->uuconf_cretry = cretry;
339: if ((*pq)->uuconf_qnext == NULL
340: || iend <= (*pq)->uuconf_qnext->uuconf_istart)
341: {
342: (*pq)->uuconf_iend = iend;
343: return UUCONF_SUCCESS;
344: }
345: /* Move this span up to the next one, and keep trying to add
346: the new span. */
347: (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart;
348: istart = (*pq)->uuconf_iend;
349: }
350: else
351: {
352: /* Leave the old span untouched. */
353: if (istart < (*pq)->uuconf_istart)
354: {
355: /* Put in the initial portion of the new span. */
356: iret = itnew (qglobal, pq, *pq, istart, (*pq)->uuconf_istart,
357: ival, cretry, pblock);
358: if (iret != UUCONF_SUCCESS)
359: return iret;
360: pq = &(*pq)->uuconf_qnext;
361: }
362: if (iend <= (*pq)->uuconf_iend)
363: return UUCONF_SUCCESS;
364: /* Keep trying to add the new span. */
365: istart = (*pq)->uuconf_iend;
366: }
367: }
368:
369: /* This is the spot for the new span, and there's no overlap. */
370:
371: return itnew (qglobal, pq, *pq, istart, iend, ival, cretry, pblock);
372: }
373:
374: /* A utility function to create a new uuconf_timespan structure. */
375:
376: static int
377: itnew (qglobal, pqset, qnext, istart, iend, ival, cretry, pblock)
378: struct sglobal *qglobal;
379: struct uuconf_timespan **pqset;
380: struct uuconf_timespan *qnext;
381: int istart;
382: int iend;
383: long ival;
384: int cretry;
385: pointer pblock;
386: {
387: register struct uuconf_timespan *qnew;
388:
389: qnew = ((struct uuconf_timespan *)
390: uuconf_malloc (pblock, sizeof (struct uuconf_timespan)));
391: if (qnew == NULL)
392: {
393: qglobal->ierrno = errno;
394: return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
395: }
396:
397: qnew->uuconf_qnext = qnext;
398: qnew->uuconf_istart = istart;
399: qnew->uuconf_iend = iend;
400: qnew->uuconf_ival = ival;
401: qnew->uuconf_cretry = cretry;
402:
403: *pqset = qnew;
404:
405: return UUCONF_SUCCESS;
406: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.