Spelling fixes.
[wine] / dlls / oleaut32 / parsedt.c
1 /*
2 PostgreSQL Data Base Management System (formerly known as Postgres, then
3 as Postgres95).
4
5 Copyright (c) 1994-7 Regents of the University of California
6
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.
11
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.
17
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.
23 */
24
25 /*-------------------------------------------------------------------------
26  *
27  * dt.c--
28  *        Functions for the built-in type "dt".
29  *
30  * Copyright (c) 1994, Regents of the University of California
31  *
32  *
33  *-------------------------------------------------------------------------
34  */
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>
43
44 #include "parsedt.h"
45
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);
56
57 #define USE_DATE_CACHE 1
58 #define ROUND_ALL 0
59
60 static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
61
62 static const char * const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
63 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
64
65 static const char * const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
66 "Thursday", "Friday", "Saturday", NULL};
67
68 /* those three vars are useless, and not even initialized, so
69  * I'd rather remove them all (EPP)
70  */
71 int     DateStyle;
72 bool    EuroDates;
73 int     CTimeZone;
74
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)
81
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))))))
89
90
91
92
93 /*****************************************************************************
94  *       PRIVATE ROUTINES                                                                                                                *
95  *****************************************************************************/
96
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))
104
105 /*
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.
109  */
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 */
261 };
262
263 static unsigned int szdatetktbl = sizeof(datetktbl) / sizeof(datetktbl[0]);
264
265
266
267 #if USE_DATE_CACHE
268 datetkn    *datecache[MAXDATEFIELDS] = {NULL};
269
270 datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
271
272 #endif
273
274
275 /*
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).
282  *
283  * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
284  *      University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
285  *
286  * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
287  *      now at Aerospace Corp. (hi, Henry!)
288  *
289  * These routines will be used by other date/time packages - tgl 97/02/25
290  */
291
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
294  */
295
296 #define JULIAN_MINYEAR (-4713)
297 #define JULIAN_MINMONTH (11)
298 #define JULIAN_MINDAY (23)
299
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)))))
303
304 int
305 date2j(int y, int m, int d)
306 {
307         int                     m12 = (m - 14) / 12;
308
309         return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
310                         - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
311 }       /* date2j() */
312
313 void
314 j2date(int jd, int *year, int *month, int *day)
315 {
316         int                     j,
317                                 y,
318                                 m,
319                                 d;
320
321         int                     i,
322                                 l,
323                                 n;
324
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;
335
336         *year = y;
337         *month = m;
338         *day = d;
339         return;
340 }       /* j2date() */
341
342
343
344
345 /*
346  * parse and convert date in timestr (the normal interface)
347  *
348  * Returns the number of seconds since epoch (J2000)
349  */
350
351 /* ParseDateTime()
352  * Break string into tokens based on a date/time context.
353  */
354 int
355 ParseDateTime(char *timestr, char *lowstr,
356                           char **field, int *ftype, int maxfields, int *numfields)
357 {
358         int                     nf = 0;
359         char       *cp = timestr;
360         char       *lp = lowstr;
361
362 #ifdef DATEDEBUG
363         printf("ParseDateTime- input string is %s\n", timestr);
364 #endif
365         /* outer loop through fields */
366         while (*cp != '\0')
367         {
368                 field[nf] = lp;
369
370                 /* leading digit? then date or time */
371                 if (isdigit(*cp) || (*cp == '.'))
372                 {
373                         *lp++ = *cp++;
374                         while (isdigit(*cp))
375                                 *lp++ = *cp++;
376                         /* time field? */
377                         if (*cp == ':')
378                         {
379                                 ftype[nf] = DTK_TIME;
380                                 while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
381                                         *lp++ = *cp++;
382
383                         }
384                         /* date field? allow embedded text month */
385                         else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
386                         {
387                                 ftype[nf] = DTK_DATE;
388                                 while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
389                                         *lp++ = tolower(*cp++);
390
391                         }
392
393                         /*
394                          * otherwise, number only and will determine year, month, or
395                          * day later
396                          */
397                         else
398                                 ftype[nf] = DTK_NUMBER;
399
400                 }
401
402                 /*
403                  * text? then date string, month, day of week, special, or
404                  * timezone
405                  */
406                 else if (isalpha(*cp))
407                 {
408                         ftype[nf] = DTK_STRING;
409                         *lp++ = tolower(*cp++);
410                         while (isalpha(*cp))
411                                 *lp++ = tolower(*cp++);
412
413                         /* full date string with leading text month? */
414                         if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
415                         {
416                                 ftype[nf] = DTK_DATE;
417                                 while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
418                                         *lp++ = tolower(*cp++);
419                         }
420
421                         /* skip leading spaces */
422                 }
423                 else if (isspace(*cp))
424                 {
425                         cp++;
426                         continue;
427
428                         /* sign? then special or numeric timezone */
429                 }
430                 else if ((*cp == '+') || (*cp == '-'))
431                 {
432                         *lp++ = *cp++;
433                         /* soak up leading whitespace */
434                         while (isspace(*cp))
435                                 cp++;
436                         /* numeric timezone? */
437                         if (isdigit(*cp))
438                         {
439                                 ftype[nf] = DTK_TZ;
440                                 *lp++ = *cp++;
441                                 while (isdigit(*cp) || (*cp == ':'))
442                                         *lp++ = *cp++;
443
444                                 /* special? */
445                         }
446                         else if (isalpha(*cp))
447                         {
448                                 ftype[nf] = DTK_SPECIAL;
449                                 *lp++ = tolower(*cp++);
450                                 while (isalpha(*cp))
451                                         *lp++ = tolower(*cp++);
452
453                                 /* otherwise something wrong... */
454                         }
455                         else
456                                 return -1;
457
458                         /* ignore punctuation but use as delimiter */
459                 }
460                 else if (ispunct(*cp))
461                 {
462                         cp++;
463                         continue;
464
465                 }
466                 else
467                         return -1;
468
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
477         }
478
479         *numfields = nf;
480
481         return 0;
482 }       /* ParseDateTime() */
483
484
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"
498  *
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
503  */
504 int
505 DecodeDateTime(char **field, int *ftype, int nf,
506                            int *dtype, struct tm * tm, double *fsec, int *tzp)
507 {
508         int                     fmask = 0,
509                                 tmask,
510                                 type;
511         int                     i;
512         int                     flen,
513                                 val;
514         int                     mer = HR24;
515         int                     bc = FALSE;
516
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;
526
527         for (i = 0; i < nf; i++)
528         {
529 #ifdef DATEDEBUG
530                 printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
531 #endif
532                 switch (ftype[i])
533                 {
534                         case DTK_DATE:
535                                 if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
536                                         return -1;
537                                 break;
538
539                         case DTK_TIME:
540                                 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
541                                         return -1;
542
543                                 /*
544                                  * check upper limit on hours; other limits checked in
545                                  * DecodeTime()
546                                  */
547                                 if (tm->tm_hour > 23)
548                                         return -1;
549                                 break;
550
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;
558
559                         case DTK_NUMBER:
560                                 flen = strlen(field[i]);
561
562                                 if (flen > 4)
563                                 {
564                                         if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
565                                                 return -1;
566
567                                 }
568                                 else
569                                 {
570                                         if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
571                                                 return -1;
572                                 }
573                                 break;
574
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;
583
584                                 tmask = DTK_M(type);
585                                 switch (type)
586                                 {
587                                         case RESERV:
588 #ifdef DATEDEBUG
589                                                 printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
590 #endif
591                                                 switch (val)
592                                                 {
593
594                                                         default:
595                                                                 *dtype = val;
596                                                 }
597
598                                                 break;
599
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;
607
608                                                 /*
609                                                  * daylight savings time modifier (solves "MET
610                                                  * DST" syntax)
611                                                  */
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;
619
620                                         case DTZ:
621
622                                                 /*
623                                                  * set mask for TZ here _or_ check for DTZ later
624                                                  * when getting default timezone
625                                                  */
626                                                 tmask |= DTK_M(TZ);
627                                                 tm->tm_isdst = 1;
628                                                 if (tzp == NULL)
629                                                         return -1;
630                                                 *tzp = val * 60;
631                                                 break;
632
633                                         case TZ:
634                                                 tm->tm_isdst = 0;
635                                                 if (tzp == NULL)
636                                                         return -1;
637                                                 *tzp = val * 60;
638                                                 break;
639
640                                         case IGNOREFIELD:
641                                                 break;
642
643                                         case AMPM:
644                                                 mer = val;
645                                                 break;
646
647                                         case ADBC:
648                                                 bc = (val == BC);
649                                                 break;
650
651                                         case DOW:
652                                                 tm->tm_wday = val;
653                                                 break;
654
655                                         default:
656                                                 return -1;
657                                 }
658                                 break;
659
660                         default:
661                                 return -1;
662                 }
663
664 #ifdef DATEDEBUG
665                 printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
666                            i, field[i], fmask, tmask, val);
667 #endif
668
669                 if (tmask & fmask)
670                         return -1;
671                 fmask |= tmask;
672         }
673
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);
677
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;
684
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;
691     }
692
693
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
699
700         if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
701                 return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
702
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))))
706         {
707
708                 /*
709                  * daylight savings time modifier but no standard timezone? then
710                  * error
711                  */
712                 if (fmask & DTK_M(DTZMOD))
713                         return -1;
714
715                 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon+1, tm->tm_mday))
716                 {
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;
725
726 #if 0 /* defined(HAVE_INT_TIMEZONE) */
727                         *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
728
729 #else                                                   /* !HAVE_INT_TIMEZONE */
730                         *tzp = -(tm->tm_gmtoff);        /* tm_gmtoff is Sun/DEC-ism */
731 #endif
732
733 #else                                                   /* !USE_POSIX_TIME */
734                         *tzp = CTimeZone;
735 #endif
736                 }
737                 else
738                 {
739                         tm->tm_isdst = 0;
740                         *tzp = 0;
741                 }
742         }
743
744         return 0;
745 }       /* DecodeDateTime() */
746
747
748 /* DecodeTimeOnly()
749  * Interpret parsed string as time fields only.
750  */
751 int
752 DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
753 {
754         int                     fmask,
755                                 tmask,
756                                 type;
757         int                     i;
758         int                     flen,
759                                 val;
760         int                     mer = HR24;
761
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;
769
770         fmask = DTK_DATE_M;
771
772         for (i = 0; i < nf; i++)
773         {
774 #ifdef DATEDEBUG
775                 printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
776 #endif
777                 switch (ftype[i])
778                 {
779                         case DTK_TIME:
780                                 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
781                                         return -1;
782                                 break;
783
784                         case DTK_NUMBER:
785                                 flen = strlen(field[i]);
786
787                                 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
788                                         return -1;
789                                 break;
790
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;
799
800                                 tmask = DTK_M(type);
801                                 switch (type)
802                                 {
803                                         case RESERV:
804 #ifdef DATEDEBUG
805                                                 printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
806 #endif
807                                                 switch (val)
808                                                 {
809
810                                                         default:
811                                                                 return -1;
812                                                 }
813
814                                                 break;
815
816                                         case IGNOREFIELD:
817                                                 break;
818
819                                         case AMPM:
820                                                 mer = val;
821                                                 break;
822
823                                         default:
824                                                 return -1;
825                                 }
826                                 break;
827
828                         default:
829                                 return -1;
830                 }
831
832                 if (tmask & fmask)
833                         return -1;
834                 fmask |= tmask;
835
836 #ifdef DATEDEBUG
837                 printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
838 #endif
839         }
840
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
845
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;
852
853         if ((fmask & DTK_TIME_M) != DTK_TIME_M)
854                 return -1;
855
856         return 0;
857 }       /* DecodeTimeOnly() */
858
859
860 /* DecodeDate()
861  * Decode date string which includes delimiters.
862  * Insist on a complete set of fields.
863  */
864 static int
865 DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
866 {
867         double          fsec;
868
869         int                     nf = 0;
870         int                     i,
871                                 len;
872         int                     type,
873                                 val,
874                                 dmask = 0;
875         char       *field[MAXDATEFIELDS];
876
877         /* parse this string... */
878         while ((*str != '\0') && (nf < MAXDATEFIELDS))
879         {
880                 /* skip field separators */
881                 while (!isalnum(*str))
882                         str++;
883
884                 field[nf] = str;
885                 if (isdigit(*str))
886                 {
887                         while (isdigit(*str))
888                                 str++;
889                 }
890                 else if (isalpha(*str))
891                 {
892                         while (isalpha(*str))
893                                 str++;
894                 }
895
896                 if (*str != '\0')
897                         *str++ = '\0';
898                 nf++;
899         }
900
901         /* don't allow too many fields */
902         if (nf > 3)
903                 return -1;
904
905         *tmask = 0;
906
907         /* look first for text fields, since that will be unambiguous month */
908         for (i = 0; i < nf; i++)
909         {
910                 if (isalpha(*field[i]))
911                 {
912                         type = DecodeSpecial(i, field[i], &val);
913                         if (type == IGNOREFIELD)
914                                 continue;
915
916                         dmask = DTK_M(type);
917                         switch (type)
918                         {
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;
926
927                                 default:
928 #ifdef DATEDEBUG
929                                         printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
930 #endif
931                                         return -1;
932                         }
933                         if (fmask & dmask)
934                                 return -1;
935
936                         fmask |= dmask;
937                         *tmask |= dmask;
938
939                         /* mark this field as being completed */
940                         field[i] = NULL;
941                 }
942         }
943
944         /* now pick up remaining numeric fields */
945         for (i = 0; i < nf; i++)
946         {
947                 if (field[i] == NULL)
948                         continue;
949
950                 if ((len = strlen(field[i])) <= 0)
951                         return -1;
952
953                 if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
954                         return -1;
955
956                 if (fmask & dmask)
957                         return -1;
958
959                 fmask |= dmask;
960                 *tmask |= dmask;
961         }
962
963         return 0;
964 }       /* DecodeDate() */
965
966
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.
971  */
972 static int
973 DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
974 {
975         char       *cp;
976
977         *tmask = DTK_TIME_M;
978
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')
985         {
986                 tm->tm_sec = 0;
987                 *fsec = 0;
988
989         }
990         else if (*cp != ':')
991         {
992                 return -1;
993
994         }
995         else
996         {
997                 str = cp + 1;
998                 tm->tm_sec = strtol(str, &cp, 10);
999                 if (*cp == '\0')
1000                         *fsec = 0;
1001                 else if (*cp == '.')
1002                 {
1003                         str = cp;
1004                         *fsec = strtod(str, &cp);
1005                         if (cp == str)
1006                                 return -1;
1007                 }
1008                 else
1009                         return -1;
1010         }
1011
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;
1017
1018         return 0;
1019 }       /* DecodeTime() */
1020
1021
1022 /* DecodeNumber()
1023  * Interpret numeric field as a date value in context.
1024  */
1025 static int
1026 DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1027 {
1028         int                     val;
1029         char       *cp;
1030
1031         *tmask = 0;
1032
1033         val = strtol(str, &cp, 10);
1034         if (cp == str)
1035                 return -1;
1036         if (*cp == '.')
1037         {
1038                 *fsec = strtod(cp, &cp);
1039                 if (*cp != '\0')
1040                         return -1;
1041         }
1042
1043 #ifdef DATEDEBUG
1044         printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
1045 #endif
1046
1047         /* enough digits to be unequivocal year? */
1048         if (flen == 4)
1049         {
1050 #ifdef DATEDEBUG
1051                 printf("DecodeNumber- match %d (%s) as year\n", val, str);
1052 #endif
1053                 *tmask = DTK_M(YEAR);
1054
1055                 /* already have a year? then see if we can substitute... */
1056                 if (fmask & DTK_M(YEAR))
1057                 {
1058                         if ((!(fmask & DTK_M(DAY)))
1059                                 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
1060                         {
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);
1066                         }
1067                 }
1068
1069                 tm->tm_year = val;
1070
1071                 /* special case day of year? */
1072         }
1073         else if ((flen == 3) && (fmask & DTK_M(YEAR))
1074                          && ((val >= 1) && (val <= 366)))
1075         {
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);
1080
1081                 /* already have year? then could be month */
1082         }
1083         else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
1084                          && ((val >= 1) && (val <= 12)))
1085         {
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;
1092
1093                 /* no year and EuroDates enabled? then could be day */
1094         }
1095         else if ((EuroDates || (fmask & DTK_M(MONTH)))
1096                          && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
1097                          && ((val >= 1) && (val <= 31)))
1098         {
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;
1104
1105         }
1106         else if ((!(fmask & DTK_M(MONTH)))
1107                          && ((val >= 1) && (val <= 12)))
1108         {
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;
1115
1116         }
1117         else if ((!(fmask & DTK_M(DAY)))
1118                          && ((val >= 1) && (val <= 31)))
1119         {
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;
1125
1126         }
1127         else if (!(fmask & DTK_M(YEAR)))
1128         {
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;
1138
1139         }
1140         else
1141                 return -1;
1142
1143         return 0;
1144 }       /* DecodeNumber() */
1145
1146
1147 /* DecodeNumberField()
1148  * Interpret numeric string as a concatenated date field.
1149  */
1150 static int
1151 DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1152 {
1153         char       *cp;
1154
1155         /* yyyymmdd? */
1156         if (len == 8)
1157         {
1158 #ifdef DATEDEBUG
1159                 printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1160 #endif
1161
1162                 *tmask = DTK_DATE_M;
1163
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);
1169
1170                 /* yymmdd or hhmmss? */
1171         }
1172         else if (len == 6)
1173         {
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)
1178                 {
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);
1188
1189                 }
1190                 else
1191                 {
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);
1201                 }
1202
1203         }
1204         else if (strchr(str, '.') != NULL)
1205         {
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);
1219
1220         }
1221         else
1222                 return -1;
1223
1224         return 0;
1225 }       /* DecodeNumberField() */
1226
1227
1228 /* DecodeTimezone()
1229  * Interpret string as a numeric timezone.
1230  */
1231 static int
1232 DecodeTimezone(char *str, int *tzp)
1233 {
1234         int                     tz;
1235         int                     hr,
1236                                 min;
1237         char       *cp;
1238         int                     len;
1239
1240         /* assume leading character is "+" or "-" */
1241         hr = strtol((str + 1), &cp, 10);
1242
1243         /* explicit delimiter? */
1244         if (*cp == ':')
1245         {
1246                 min = strtol((cp + 1), &cp, 10);
1247
1248                 /* otherwise, might have run things together... */
1249         }
1250         else if ((*cp == '\0') && ((len = strlen(str)) > 3))
1251         {
1252                 min = strtol((str + len - 2), &cp, 10);
1253                 *(str + len - 2) = '\0';
1254                 hr = strtol((str + 1), &cp, 10);
1255
1256         }
1257         else
1258                 min = 0;
1259
1260         tz = (hr * 60 + min) * 60;
1261         if (*str == '-')
1262                 tz = -tz;
1263
1264         *tzp = -tz;
1265         return *cp != '\0';
1266 }       /* DecodeTimezone() */
1267
1268
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.
1273  */
1274 static int
1275 DecodeSpecial(int field, char *lowtoken, int *val)
1276 {
1277         int                     type;
1278         datetkn    *tp;
1279
1280 #if USE_DATE_CACHE
1281         if ((datecache[field] != NULL)
1282                 && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
1283                 tp = datecache[field];
1284         else
1285         {
1286 #endif
1287                 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
1288 #if USE_DATE_CACHE
1289         }
1290         datecache[field] = tp;
1291 #endif
1292         if (tp == NULL)
1293         {
1294                 type = IGNOREFIELD;
1295                 *val = 0;
1296         }
1297         else
1298         {
1299                 type = tp->type;
1300                 switch (type)
1301                 {
1302                         case TZ:
1303                         case DTZ:
1304                         case DTZMOD:
1305                                 *val = FROMVAL(tp);
1306                                 break;
1307
1308                         default:
1309                                 *val = tp->value;
1310                                 break;
1311                 }
1312         }
1313
1314         return type;
1315 }       /* DecodeSpecial() */
1316
1317
1318
1319 /* datebsearch()
1320  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
1321  * is WAY faster than the generic bsearch().
1322  */
1323 static datetkn *
1324 datebsearch(char *key, datetkn *base, unsigned int nel)
1325 {
1326         datetkn    *last = base + nel - 1,
1327                            *position;
1328         int                     result;
1329
1330         while (last >= base)
1331         {
1332                 position = base + ((last - base) >> 1);
1333                 result = key[0] - position->token[0];
1334                 if (result == 0)
1335                 {
1336                         result = strncmp(key, position->token, TOKMAXLEN);
1337                         if (result == 0)
1338                                 return position;
1339                 }
1340                 if (result < 0)
1341                         last = position - 1;
1342                 else
1343                         base = position + 1;
1344         }
1345         return NULL;
1346 }