Fixed some issues found by winapi_check.
[wine/dcerpc.git] / dlls / oleaut32 / parsedt.c
blob57eb33d9f08231e921521574b166487ecf8d5ce1
1 /*
2 PostgreSQL Data Base Management System (formerly known as Postgres, then
3 as Postgres95).
5 Copyright (c) 1994-7 Regents of the University of California
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose, without fee, and without a written agreement
9 is hereby granted, provided that the above copyright notice and this
10 paragraph and the following two paragraphs appear in all copies.
12 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
13 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
14 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
15 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
16 POSSIBILITY OF SUCH DAMAGE.
18 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
22 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 /*-------------------------------------------------------------------------
27 * dt.c--
28 * Functions for the built-in type "dt".
30 * Copyright (c) 1994, Regents of the University of California
33 *-------------------------------------------------------------------------
35 #include <time.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <math.h>
39 #include <string.h>
40 #include <sys/types.h>
41 #include <limits.h>
42 #include <sys/timeb.h>
44 #include "parsedt.h"
46 static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
47 static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
48 static int DecodeNumber(int flen, char *field,
49 int fmask, int *tmask, struct tm * tm, double *fsec);
50 static int DecodeNumberField(int len, char *str,
51 int fmask, int *tmask, struct tm * tm, double *fsec);
52 static int DecodeSpecial(int field, char *lowtoken, int *val);
53 static int DecodeTime(char *str, int fmask, int *tmask,
54 struct tm * tm, double *fsec);
55 static int DecodeTimezone(char *str, int *tzp);
57 #define USE_DATE_CACHE 1
58 #define ROUND_ALL 0
60 static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
62 static const char * const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
63 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
65 static const char * const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
66 "Thursday", "Friday", "Saturday", NULL};
68 /* those three vars are useless, and not even initialized, so
69 * I'd rather remove them all (EPP)
71 int DateStyle;
72 bool EuroDates;
73 int CTimeZone;
75 #define UTIME_MINYEAR (1901)
76 #define UTIME_MINMONTH (12)
77 #define UTIME_MINDAY (14)
78 #define UTIME_MAXYEAR (2038)
79 #define UTIME_MAXMONTH (01)
80 #define UTIME_MAXDAY (18)
82 /* Assumes month in 1..12. Note tm_mon is 0..11 */
83 #define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
84 || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
85 || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
86 && ((y < UTIME_MAXYEAR) \
87 || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
88 || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
93 /*****************************************************************************
94 * PRIVATE ROUTINES *
95 *****************************************************************************/
97 /* definitions for squeezing values into "value" */
98 #define ABS_SIGNBIT (char) 0200
99 #define VALMASK (char) 0177
100 #define NEG(n) ((n)|ABS_SIGNBIT)
101 #define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
102 #define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
103 #define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
106 * to keep this table reasonably small, we divide the lexval for TZ and DTZ
107 * entries by 10 and truncate the text field at MAXTOKLEN characters.
108 * the text field is not guaranteed to be NULL-terminated.
110 static datetkn datetktbl[] = {
111 /* text token lexval */
112 {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
113 {"acsst", DTZ, 63}, /* Cent. Australia */
114 {"acst", TZ, 57}, /* Cent. Australia */
115 {DA_D, ADBC, AD}, /* "ad" for years >= 0 */
116 {"abstime", IGNOREFIELD, 0}, /* "abstime" for pre-v6.1 "Invalid
117 * Abstime" */
118 {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
119 {"aesst", DTZ, 66}, /* E. Australia */
120 {"aest", TZ, 60}, /* Australia Eastern Std Time */
121 {"ahst", TZ, 60}, /* Alaska-Hawaii Std Time */
122 {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
123 {"am", AMPM, AM},
124 {"apr", MONTH, 4},
125 {"april", MONTH, 4},
126 {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
127 {"at", IGNOREFIELD, 0}, /* "at" (throwaway) */
128 {"aug", MONTH, 8},
129 {"august", MONTH, 8},
130 {"awsst", DTZ, 54}, /* W. Australia */
131 {"awst", TZ, 48}, /* W. Australia */
132 {DB_C, ADBC, BC}, /* "bc" for years < 0 */
133 {"bst", TZ, 6}, /* British Summer Time */
134 {"bt", TZ, 18}, /* Baghdad Time */
135 {"cadt", DTZ, 63}, /* Central Australian DST */
136 {"cast", TZ, 57}, /* Central Australian ST */
137 {"cat", TZ, NEG(60)}, /* Central Alaska Time */
138 {"cct", TZ, 48}, /* China Coast */
139 {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */
140 {"cet", TZ, 6}, /* Central European Time */
141 {"cetdst", DTZ, 12}, /* Central European Dayl.Time */
142 {"cst", TZ, NEG(36)}, /* Central Standard Time */
143 {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
144 {"dec", MONTH, 12},
145 {"december", MONTH, 12},
146 {"dnt", TZ, 6}, /* Dansk Normal Tid */
147 {"dow", RESERV, DTK_DOW}, /* day of week */
148 {"doy", RESERV, DTK_DOY}, /* day of year */
149 {"dst", DTZMOD, 6},
150 {"east", TZ, NEG(60)}, /* East Australian Std Time */
151 {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
152 {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
153 {"eetdst", DTZ, 18}, /* Eastern Europe */
154 {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
155 #if USE_AUSTRALIAN_RULES
156 {"est", TZ, 60}, /* Australia Eastern Std Time */
157 #else
158 {"est", TZ, NEG(30)}, /* Eastern Standard Time */
159 #endif
160 {"feb", MONTH, 2},
161 {"february", MONTH, 2},
162 {"fri", DOW, 5},
163 {"friday", DOW, 5},
164 {"fst", TZ, 6}, /* French Summer Time */
165 {"fwt", DTZ, 12}, /* French Winter Time */
166 {"gmt", TZ, 0}, /* Greenwish Mean Time */
167 {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
168 {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
169 {"hmt", DTZ, 18}, /* Hellas ? ? */
170 {"hst", TZ, NEG(60)}, /* Hawaii Std Time */
171 {"idle", TZ, 72}, /* Intl. Date Line, East */
172 {"idlw", TZ, NEG(72)}, /* Intl. Date Line,, est */
173 {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
174 {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid
175 * time */
176 {"ist", TZ, 12}, /* Israel */
177 {"it", TZ, 22}, /* Iran Time */
178 {"jan", MONTH, 1},
179 {"january", MONTH, 1},
180 {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
181 {"jt", TZ, 45}, /* Java Time */
182 {"jul", MONTH, 7},
183 {"july", MONTH, 7},
184 {"jun", MONTH, 6},
185 {"june", MONTH, 6},
186 {"kst", TZ, 54}, /* Korea Standard Time */
187 {"ligt", TZ, 60}, /* From Melbourne, Australia */
188 {"mar", MONTH, 3},
189 {"march", MONTH, 3},
190 {"may", MONTH, 5},
191 {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
192 {"mest", DTZ, 12}, /* Middle Europe Summer Time */
193 {"met", TZ, 6}, /* Middle Europe Time */
194 {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */
195 {"mewt", TZ, 6}, /* Middle Europe Winter Time */
196 {"mez", TZ, 6}, /* Middle Europe Zone */
197 {"mon", DOW, 1},
198 {"monday", DOW, 1},
199 {"mst", TZ, NEG(42)}, /* Mountain Standard Time */
200 {"mt", TZ, 51}, /* Moluccas Time */
201 {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
202 {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
203 {"nor", TZ, 6}, /* Norway Standard Time */
204 {"nov", MONTH, 11},
205 {"november", MONTH, 11},
206 {NOW, RESERV, DTK_NOW}, /* current transaction time */
207 {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */
208 {"nt", TZ, NEG(66)}, /* Nome Time */
209 {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */
210 {"nzst", TZ, 72}, /* New Zealand Standard Time */
211 {"nzt", TZ, 72}, /* New Zealand Time */
212 {"oct", MONTH, 10},
213 {"october", MONTH, 10},
214 {"on", IGNOREFIELD, 0}, /* "on" (throwaway) */
215 {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
216 {"pm", AMPM, PM},
217 {"pst", TZ, NEG(48)}, /* Pacific Standard Time */
218 {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
219 {"sast", TZ, 57}, /* South Australian Std Time */
220 {"sat", DOW, 6},
221 {"saturday", DOW, 6},
222 {"sep", MONTH, 9},
223 {"sept", MONTH, 9},
224 {"september", MONTH, 9},
225 {"set", TZ, NEG(6)}, /* Seychelles Time ?? */
226 {"sst", DTZ, 12}, /* Swedish Summer Time */
227 {"sun", DOW, 0},
228 {"sunday", DOW, 0},
229 {"swt", TZ, 6}, /* Swedish Winter Time */
230 {"thu", DOW, 4},
231 {"thur", DOW, 4},
232 {"thurs", DOW, 4},
233 {"thursday", DOW, 4},
234 {TODAY, RESERV, DTK_TODAY}, /* midnight */
235 {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
236 {"tue", DOW, 2},
237 {"tues", DOW, 2},
238 {"tuesday", DOW, 2},
239 {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
240 * time */
241 {"ut", TZ, 0},
242 {"utc", TZ, 0},
243 {"wadt", DTZ, 48}, /* West Australian DST */
244 {"wast", TZ, 42}, /* West Australian Std Time */
245 {"wat", TZ, NEG(6)}, /* West Africa Time */
246 {"wdt", DTZ, 54}, /* West Australian DST */
247 {"wed", DOW, 3},
248 {"wednesday", DOW, 3},
249 {"weds", DOW, 3},
250 {"wet", TZ, 0}, /* Western Europe */
251 {"wetdst", DTZ, 6}, /* Western Europe */
252 {"wst", TZ, 48}, /* West Australian Std Time */
253 {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
254 {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
255 {"yst", TZ, NEG(54)}, /* Yukon Standard Time */
256 {"zp4", TZ, NEG(24)}, /* GMT +4 hours. */
257 {"zp5", TZ, NEG(30)}, /* GMT +5 hours. */
258 {"zp6", TZ, NEG(36)}, /* GMT +6 hours. */
259 {"z", RESERV, DTK_ZULU}, /* 00:00:00 */
260 {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */
263 static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
267 #if USE_DATE_CACHE
268 datetkn *datecache[MAXDATEFIELDS] = {NULL};
270 datetkn *deltacache[MAXDATEFIELDS] = {NULL};
272 #endif
276 * Calendar time to Julian date conversions.
277 * Julian date is commonly used in astronomical applications,
278 * since it is numerically accurate and computationally simple.
279 * The algorithms here will accurately convert between Julian day
280 * and calendar date for all non-negative Julian days
281 * (i.e. from Nov 23, -4713 on).
283 * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
284 * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
286 * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
287 * now at Aerospace Corp. (hi, Henry!)
289 * These routines will be used by other date/time packages - tgl 97/02/25
292 /* Set the minimum year to one greater than the year of the first valid day
293 * to avoid having to check year and day both. - tgl 97/05/08
296 #define JULIAN_MINYEAR (-4713)
297 #define JULIAN_MINMONTH (11)
298 #define JULIAN_MINDAY (23)
300 #define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
301 || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
302 || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
305 date2j(int y, int m, int d)
307 int m12 = (m - 14) / 12;
309 return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
310 - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
311 } /* date2j() */
313 void
314 j2date(int jd, int *year, int *month, int *day)
316 int j,
321 int i,
325 l = jd + 68569;
326 n = (4 * l) / 146097;
327 l -= (146097 * n + 3) / 4;
328 i = (4000 * (l + 1)) / 1461001;
329 l += 31 - (1461 * i) / 4;
330 j = (80 * l) / 2447;
331 d = l - (2447 * j) / 80;
332 l = j / 11;
333 m = (j + 2) - (12 * l);
334 y = 100 * (n - 49) + i + l;
336 *year = y;
337 *month = m;
338 *day = d;
339 return;
340 } /* j2date() */
346 * parse and convert date in timestr (the normal interface)
348 * Returns the number of seconds since epoch (J2000)
351 /* ParseDateTime()
352 * Break string into tokens based on a date/time context.
355 ParseDateTime(char *timestr, char *lowstr,
356 char **field, int *ftype, int maxfields, int *numfields)
358 int nf = 0;
359 char *cp = timestr;
360 char *lp = lowstr;
362 #ifdef DATEDEBUG
363 printf("ParseDateTime- input string is %s\n", timestr);
364 #endif
365 /* outer loop through fields */
366 while (*cp != '\0')
368 field[nf] = lp;
370 /* leading digit? then date or time */
371 if (isdigit(*cp) || (*cp == '.'))
373 *lp++ = *cp++;
374 while (isdigit(*cp))
375 *lp++ = *cp++;
376 /* time field? */
377 if (*cp == ':')
379 ftype[nf] = DTK_TIME;
380 while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
381 *lp++ = *cp++;
384 /* date field? allow embedded text month */
385 else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
387 ftype[nf] = DTK_DATE;
388 while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
389 *lp++ = tolower(*cp++);
394 * otherwise, number only and will determine year, month, or
395 * day later
397 else
398 ftype[nf] = DTK_NUMBER;
403 * text? then date string, month, day of week, special, or
404 * timezone
406 else if (isalpha(*cp))
408 ftype[nf] = DTK_STRING;
409 *lp++ = tolower(*cp++);
410 while (isalpha(*cp))
411 *lp++ = tolower(*cp++);
413 /* full date string with leading text month? */
414 if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
416 ftype[nf] = DTK_DATE;
417 while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
418 *lp++ = tolower(*cp++);
421 /* skip leading spaces */
423 else if (isspace(*cp))
425 cp++;
426 continue;
428 /* sign? then special or numeric timezone */
430 else if ((*cp == '+') || (*cp == '-'))
432 *lp++ = *cp++;
433 /* soak up leading whitespace */
434 while (isspace(*cp))
435 cp++;
436 /* numeric timezone? */
437 if (isdigit(*cp))
439 ftype[nf] = DTK_TZ;
440 *lp++ = *cp++;
441 while (isdigit(*cp) || (*cp == ':'))
442 *lp++ = *cp++;
444 /* special? */
446 else if (isalpha(*cp))
448 ftype[nf] = DTK_SPECIAL;
449 *lp++ = tolower(*cp++);
450 while (isalpha(*cp))
451 *lp++ = tolower(*cp++);
453 /* otherwise something wrong... */
455 else
456 return -1;
458 /* ignore punctuation but use as delimiter */
460 else if (ispunct(*cp))
462 cp++;
463 continue;
466 else
467 return -1;
469 /* force in a delimiter */
470 *lp++ = '\0';
471 nf++;
472 if (nf > MAXDATEFIELDS)
473 return -1;
474 #ifdef DATEDEBUG
475 printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
476 #endif
479 *numfields = nf;
481 return 0;
482 } /* ParseDateTime() */
485 /* DecodeDateTime()
486 * Interpret previously parsed fields for general date and time.
487 * Return 0 if full date, 1 if only time, and -1 if problems.
488 * External format(s):
489 * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
490 * "Fri Feb-7-1997 15:23:27"
491 * "Feb-7-1997 15:23:27"
492 * "2-7-1997 15:23:27"
493 * "1997-2-7 15:23:27"
494 * "1997.038 15:23:27" (day of year 1-366)
495 * Also supports input in compact time:
496 * "970207 152327"
497 * "97038 152327"
499 * Use the system-provided functions to get the current time zone
500 * if not specified in the input string.
501 * If the date is outside the time_t system-supported time range,
502 * then assume GMT time zone. - tgl 97/05/27
505 DecodeDateTime(char **field, int *ftype, int nf,
506 int *dtype, struct tm * tm, double *fsec, int *tzp)
508 int fmask = 0,
509 tmask,
510 type;
511 int i;
512 int flen,
513 val;
514 int mer = HR24;
515 int bc = FALSE;
517 *dtype = DTK_DATE;
518 tm->tm_hour = 0;
519 tm->tm_min = 0;
520 tm->tm_sec = 0;
521 *fsec = 0;
522 tm->tm_isdst = -1; /* don't know daylight savings time status
523 * apriori */
524 if (tzp != NULL)
525 *tzp = 0;
527 for (i = 0; i < nf; i++)
529 #ifdef DATEDEBUG
530 printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
531 #endif
532 switch (ftype[i])
534 case DTK_DATE:
535 if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
536 return -1;
537 break;
539 case DTK_TIME:
540 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
541 return -1;
544 * check upper limit on hours; other limits checked in
545 * DecodeTime()
547 if (tm->tm_hour > 23)
548 return -1;
549 break;
551 case DTK_TZ:
552 if (tzp == NULL)
553 return -1;
554 if (DecodeTimezone(field[i], tzp) != 0)
555 return -1;
556 tmask = DTK_M(TZ);
557 break;
559 case DTK_NUMBER:
560 flen = strlen(field[i]);
562 if (flen > 4)
564 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
565 return -1;
568 else
570 if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
571 return -1;
573 break;
575 case DTK_STRING:
576 case DTK_SPECIAL:
577 type = DecodeSpecial(i, field[i], &val);
578 #ifdef DATEDEBUG
579 printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
580 #endif
581 if (type == IGNOREFIELD)
582 continue;
584 tmask = DTK_M(type);
585 switch (type)
587 case RESERV:
588 #ifdef DATEDEBUG
589 printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
590 #endif
591 switch (val)
594 default:
595 *dtype = val;
598 break;
600 case MONTH:
601 #ifdef DATEDEBUG
602 printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
603 #endif
604 /* tm_mon is 0->11, so need to subtract one from value in table */
605 tm->tm_mon = val-1;
606 break;
609 * daylight savings time modifier (solves "MET
610 * DST" syntax)
612 case DTZMOD:
613 tmask |= DTK_M(DTZ);
614 tm->tm_isdst = 1;
615 if (tzp == NULL)
616 return -1;
617 *tzp += val * 60;
618 break;
620 case DTZ:
623 * set mask for TZ here _or_ check for DTZ later
624 * when getting default timezone
626 tmask |= DTK_M(TZ);
627 tm->tm_isdst = 1;
628 if (tzp == NULL)
629 return -1;
630 *tzp = val * 60;
631 break;
633 case TZ:
634 tm->tm_isdst = 0;
635 if (tzp == NULL)
636 return -1;
637 *tzp = val * 60;
638 break;
640 case IGNOREFIELD:
641 break;
643 case AMPM:
644 mer = val;
645 break;
647 case ADBC:
648 bc = (val == BC);
649 break;
651 case DOW:
652 tm->tm_wday = val;
653 break;
655 default:
656 return -1;
658 break;
660 default:
661 return -1;
664 #ifdef DATEDEBUG
665 printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
666 i, field[i], fmask, tmask, val);
667 #endif
669 if (tmask & fmask)
670 return -1;
671 fmask |= tmask;
674 /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
675 if (bc)
676 tm->tm_year = -(tm->tm_year - 1);
678 if ((mer != HR24) && (tm->tm_hour > 12))
679 return -1;
680 if ((mer == AM) && (tm->tm_hour == 12))
681 tm->tm_hour = 0;
682 else if ((mer == PM) && (tm->tm_hour != 12))
683 tm->tm_hour += 12;
685 /* If parsing a time string into a date, all date parts are unset.
686 Win2k defaults these to 30 dec, 1899 so: */
687 if (tm->tm_year == 0 && tm->tm_mon == 0 && tm->tm_mday == 0 && fmask == DTK_TIME_M) {
688 tm->tm_year = 1899;
689 tm->tm_mon = 11; /* December, as tm_mon is 0..11 */
690 tm->tm_mday = 30;
694 #ifdef DATEDEBUG
695 printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
696 printf(" set y%04d m%02d d%02d", tm->tm_year, (tm->tm_mon+1), tm->tm_mday);
697 printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
698 #endif
700 if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
701 return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
703 /* timezone not specified? then find local timezone if possible */
704 if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
705 && (tzp != NULL) && (!(fmask & DTK_M(TZ))))
709 * daylight savings time modifier but no standard timezone? then
710 * error
712 if (fmask & DTK_M(DTZMOD))
713 return -1;
715 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon+1, tm->tm_mday))
717 /* FIXME: The code below is not correct */
718 #if 0 /* defined(USE_POSIX_TIME) */
719 tm->tm_year -= 1900;
720 tm->tm_mon -= 1;
721 tm->tm_isdst = -1;
722 mktime(tm);
723 tm->tm_year += 1900;
724 tm->tm_mon += 1;
726 #if 0 /* defined(HAVE_INT_TIMEZONE) */
727 *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
729 #else /* !HAVE_INT_TIMEZONE */
730 *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
731 #endif
733 #else /* !USE_POSIX_TIME */
734 *tzp = CTimeZone;
735 #endif
737 else
739 tm->tm_isdst = 0;
740 *tzp = 0;
744 return 0;
745 } /* DecodeDateTime() */
748 /* DecodeTimeOnly()
749 * Interpret parsed string as time fields only.
752 DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
754 int fmask,
755 tmask,
756 type;
757 int i;
758 int flen,
759 val;
760 int mer = HR24;
762 *dtype = DTK_TIME;
763 tm->tm_hour = 0;
764 tm->tm_min = 0;
765 tm->tm_sec = 0;
766 tm->tm_isdst = -1; /* don't know daylight savings time status
767 * apriori */
768 *fsec = 0;
770 fmask = DTK_DATE_M;
772 for (i = 0; i < nf; i++)
774 #ifdef DATEDEBUG
775 printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
776 #endif
777 switch (ftype[i])
779 case DTK_TIME:
780 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
781 return -1;
782 break;
784 case DTK_NUMBER:
785 flen = strlen(field[i]);
787 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
788 return -1;
789 break;
791 case DTK_STRING:
792 case DTK_SPECIAL:
793 type = DecodeSpecial(i, field[i], &val);
794 #ifdef DATEDEBUG
795 printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
796 #endif
797 if (type == IGNOREFIELD)
798 continue;
800 tmask = DTK_M(type);
801 switch (type)
803 case RESERV:
804 #ifdef DATEDEBUG
805 printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
806 #endif
807 switch (val)
810 default:
811 return -1;
814 break;
816 case IGNOREFIELD:
817 break;
819 case AMPM:
820 mer = val;
821 break;
823 default:
824 return -1;
826 break;
828 default:
829 return -1;
832 if (tmask & fmask)
833 return -1;
834 fmask |= tmask;
836 #ifdef DATEDEBUG
837 printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
838 #endif
841 #ifdef DATEDEBUG
842 printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
843 printf(" %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
844 #endif
846 if ((mer != HR24) && (tm->tm_hour > 12))
847 return -1;
848 if ((mer == AM) && (tm->tm_hour == 12))
849 tm->tm_hour = 0;
850 else if ((mer == PM) && (tm->tm_hour != 12))
851 tm->tm_hour += 12;
853 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
854 return -1;
856 return 0;
857 } /* DecodeTimeOnly() */
860 /* DecodeDate()
861 * Decode date string which includes delimiters.
862 * Insist on a complete set of fields.
864 static int
865 DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
867 double fsec;
869 int nf = 0;
870 int i,
871 len;
872 int type,
873 val,
874 dmask = 0;
875 char *field[MAXDATEFIELDS];
877 /* parse this string... */
878 while ((*str != '\0') && (nf < MAXDATEFIELDS))
880 /* skip field separators */
881 while (!isalnum(*str))
882 str++;
884 field[nf] = str;
885 if (isdigit(*str))
887 while (isdigit(*str))
888 str++;
890 else if (isalpha(*str))
892 while (isalpha(*str))
893 str++;
896 if (*str != '\0')
897 *str++ = '\0';
898 nf++;
901 /* don't allow too many fields */
902 if (nf > 3)
903 return -1;
905 *tmask = 0;
907 /* look first for text fields, since that will be unambiguous month */
908 for (i = 0; i < nf; i++)
910 if (isalpha(*field[i]))
912 type = DecodeSpecial(i, field[i], &val);
913 if (type == IGNOREFIELD)
914 continue;
916 dmask = DTK_M(type);
917 switch (type)
919 case MONTH:
920 #ifdef DATEDEBUG
921 printf("DecodeDate- month field %s value is %d\n", field[i], val);
922 #endif
923 /* tm_mon is 0->11, so need to subtract one from value in table */
924 tm->tm_mon = val-1;
925 break;
927 default:
928 #ifdef DATEDEBUG
929 printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
930 #endif
931 return -1;
933 if (fmask & dmask)
934 return -1;
936 fmask |= dmask;
937 *tmask |= dmask;
939 /* mark this field as being completed */
940 field[i] = NULL;
944 /* now pick up remaining numeric fields */
945 for (i = 0; i < nf; i++)
947 if (field[i] == NULL)
948 continue;
950 if ((len = strlen(field[i])) <= 0)
951 return -1;
953 if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
954 return -1;
956 if (fmask & dmask)
957 return -1;
959 fmask |= dmask;
960 *tmask |= dmask;
963 return 0;
964 } /* DecodeDate() */
967 /* DecodeTime()
968 * Decode time string which includes delimiters.
969 * Only check the lower limit on hours, since this same code
970 * can be used to represent time spans.
972 static int
973 DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
975 char *cp;
977 *tmask = DTK_TIME_M;
979 tm->tm_hour = strtol(str, &cp, 10);
980 if (*cp != ':')
981 return -1;
982 str = cp + 1;
983 tm->tm_min = strtol(str, &cp, 10);
984 if (*cp == '\0')
986 tm->tm_sec = 0;
987 *fsec = 0;
990 else if (*cp != ':')
992 return -1;
995 else
997 str = cp + 1;
998 tm->tm_sec = strtol(str, &cp, 10);
999 if (*cp == '\0')
1000 *fsec = 0;
1001 else if (*cp == '.')
1003 str = cp;
1004 *fsec = strtod(str, &cp);
1005 if (cp == str)
1006 return -1;
1008 else
1009 return -1;
1012 /* do a sanity check */
1013 if ((tm->tm_hour < 0)
1014 || (tm->tm_min < 0) || (tm->tm_min > 59)
1015 || (tm->tm_sec < 0) || (tm->tm_sec > 59))
1016 return -1;
1018 return 0;
1019 } /* DecodeTime() */
1022 /* DecodeNumber()
1023 * Interpret numeric field as a date value in context.
1025 static int
1026 DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1028 int val;
1029 char *cp;
1031 *tmask = 0;
1033 val = strtol(str, &cp, 10);
1034 if (cp == str)
1035 return -1;
1036 if (*cp == '.')
1038 *fsec = strtod(cp, &cp);
1039 if (*cp != '\0')
1040 return -1;
1043 #ifdef DATEDEBUG
1044 printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
1045 #endif
1047 /* enough digits to be unequivocal year? */
1048 if (flen == 4)
1050 #ifdef DATEDEBUG
1051 printf("DecodeNumber- match %d (%s) as year\n", val, str);
1052 #endif
1053 *tmask = DTK_M(YEAR);
1055 /* already have a year? then see if we can substitute... */
1056 if (fmask & DTK_M(YEAR))
1058 if ((!(fmask & DTK_M(DAY)))
1059 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
1061 #ifdef DATEDEBUG
1062 printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
1063 #endif
1064 tm->tm_mday = tm->tm_year;
1065 *tmask = DTK_M(DAY);
1069 tm->tm_year = val;
1071 /* special case day of year? */
1073 else if ((flen == 3) && (fmask & DTK_M(YEAR))
1074 && ((val >= 1) && (val <= 366)))
1076 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1077 tm->tm_yday = val;
1078 j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
1079 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1081 /* already have year? then could be month */
1083 else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
1084 && ((val >= 1) && (val <= 12)))
1086 #ifdef DATEDEBUG
1087 printf("DecodeNumber- match %d (%s) as month\n", val, str);
1088 #endif
1089 *tmask = DTK_M(MONTH);
1090 /* tm_mon is 0..11 */
1091 tm->tm_mon = val-1;
1093 /* no year and EuroDates enabled? then could be day */
1095 else if ((EuroDates || (fmask & DTK_M(MONTH)))
1096 && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
1097 && ((val >= 1) && (val <= 31)))
1099 #ifdef DATEDEBUG
1100 printf("DecodeNumber- match %d (%s) as day\n", val, str);
1101 #endif
1102 *tmask = DTK_M(DAY);
1103 tm->tm_mday = val;
1106 else if ((!(fmask & DTK_M(MONTH)))
1107 && ((val >= 1) && (val <= 12)))
1109 #ifdef DATEDEBUG
1110 printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
1111 #endif
1112 *tmask = DTK_M(MONTH);
1113 /* tm_mon is 0..11 */
1114 tm->tm_mon = val-1;
1117 else if ((!(fmask & DTK_M(DAY)))
1118 && ((val >= 1) && (val <= 31)))
1120 #ifdef DATEDEBUG
1121 printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
1122 #endif
1123 *tmask = DTK_M(DAY);
1124 tm->tm_mday = val;
1127 else if (!(fmask & DTK_M(YEAR)))
1129 #ifdef DATEDEBUG
1130 printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
1131 #endif
1132 *tmask = DTK_M(YEAR);
1133 tm->tm_year = val;
1134 if (tm->tm_year < 70)
1135 tm->tm_year += 2000;
1136 else if (tm->tm_year < 100)
1137 tm->tm_year += 1900;
1140 else
1141 return -1;
1143 return 0;
1144 } /* DecodeNumber() */
1147 /* DecodeNumberField()
1148 * Interpret numeric string as a concatenated date field.
1150 static int
1151 DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1153 char *cp;
1155 /* yyyymmdd? */
1156 if (len == 8)
1158 #ifdef DATEDEBUG
1159 printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1160 #endif
1162 *tmask = DTK_DATE_M;
1164 tm->tm_mday = atoi(str + 6);
1165 *(str + 6) = '\0';
1166 tm->tm_mon = atoi(str + 4) - 1; /* tm_mon is 0..11 */
1167 *(str + 4) = '\0';
1168 tm->tm_year = atoi(str + 0);
1170 /* yymmdd or hhmmss? */
1172 else if (len == 6)
1174 #ifdef DATEDEBUG
1175 printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1176 #endif
1177 if (fmask & DTK_DATE_M)
1179 #ifdef DATEDEBUG
1180 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1181 #endif
1182 *tmask = DTK_TIME_M;
1183 tm->tm_sec = atoi(str + 4);
1184 *(str + 4) = '\0';
1185 tm->tm_min = atoi(str + 2);
1186 *(str + 2) = '\0';
1187 tm->tm_hour = atoi(str + 0);
1190 else
1192 #ifdef DATEDEBUG
1193 printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1194 #endif
1195 *tmask = DTK_DATE_M;
1196 tm->tm_mday = atoi(str + 4);
1197 *(str + 4) = '\0';
1198 tm->tm_mon = atoi(str + 2) - 1; /* tm_mon is 0..11 */
1199 *(str + 2) = '\0';
1200 tm->tm_year = atoi(str + 0);
1204 else if (strchr(str, '.') != NULL)
1206 #ifdef DATEDEBUG
1207 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1208 #endif
1209 *tmask = DTK_TIME_M;
1210 tm->tm_sec = strtod((str + 4), &cp);
1211 if (cp == (str + 4))
1212 return -1;
1213 if (*cp == '.')
1214 *fsec = strtod(cp, NULL);
1215 *(str + 4) = '\0';
1216 tm->tm_min = strtod((str + 2), &cp);
1217 *(str + 2) = '\0';
1218 tm->tm_hour = strtod((str + 0), &cp);
1221 else
1222 return -1;
1224 return 0;
1225 } /* DecodeNumberField() */
1228 /* DecodeTimezone()
1229 * Interpret string as a numeric timezone.
1231 static int
1232 DecodeTimezone(char *str, int *tzp)
1234 int tz;
1235 int hr,
1236 min;
1237 char *cp;
1238 int len;
1240 /* assume leading character is "+" or "-" */
1241 hr = strtol((str + 1), &cp, 10);
1243 /* explicit delimiter? */
1244 if (*cp == ':')
1246 min = strtol((cp + 1), &cp, 10);
1248 /* otherwise, might have run things together... */
1250 else if ((*cp == '\0') && ((len = strlen(str)) > 3))
1252 min = strtol((str + len - 2), &cp, 10);
1253 *(str + len - 2) = '\0';
1254 hr = strtol((str + 1), &cp, 10);
1257 else
1258 min = 0;
1260 tz = (hr * 60 + min) * 60;
1261 if (*str == '-')
1262 tz = -tz;
1264 *tzp = -tz;
1265 return *cp != '\0';
1266 } /* DecodeTimezone() */
1269 /* DecodeSpecial()
1270 * Decode text string using lookup table.
1271 * Implement a cache lookup since it is likely that dates
1272 * will be related in format.
1274 static int
1275 DecodeSpecial(int field, char *lowtoken, int *val)
1277 int type;
1278 datetkn *tp;
1280 #if USE_DATE_CACHE
1281 if ((datecache[field] != NULL)
1282 && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
1283 tp = datecache[field];
1284 else
1286 #endif
1287 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
1288 #if USE_DATE_CACHE
1290 datecache[field] = tp;
1291 #endif
1292 if (tp == NULL)
1294 type = IGNOREFIELD;
1295 *val = 0;
1297 else
1299 type = tp->type;
1300 switch (type)
1302 case TZ:
1303 case DTZ:
1304 case DTZMOD:
1305 *val = FROMVAL(tp);
1306 break;
1308 default:
1309 *val = tp->value;
1310 break;
1314 return type;
1315 } /* DecodeSpecial() */
1319 /* datebsearch()
1320 * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
1321 * is WAY faster than the generic bsearch().
1323 static datetkn *
1324 datebsearch(char *key, datetkn *base, unsigned int nel)
1326 datetkn *last = base + nel - 1,
1327 *position;
1328 int result;
1330 while (last >= base)
1332 position = base + ((last - base) >> 1);
1333 result = key[0] - position->token[0];
1334 if (result == 0)
1336 result = strncmp(key, position->token, TOKMAXLEN);
1337 if (result == 0)
1338 return position;
1340 if (result < 0)
1341 last = position - 1;
1342 else
1343 base = position + 1;
1345 return NULL;