Added stubs for AccessCheckByType, AddAuditAccessAce,
[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 /* those two vars are useless, and not even initialized, so
61  * I'd rather remove them all (EPP)
62  */
63 bool    EuroDates;
64 int     CTimeZone;
65
66 #define UTIME_MINYEAR (1901)
67 #define UTIME_MINMONTH (12)
68 #define UTIME_MINDAY (14)
69 #define UTIME_MAXYEAR (2038)
70 #define UTIME_MAXMONTH (01)
71 #define UTIME_MAXDAY (18)
72
73 /* Assumes month in 1..12. Note tm_mon is 0..11 */
74 #define IS_VALID_UTIME(y,m,d) (((y > UTIME_MINYEAR) \
75  || ((y == UTIME_MINYEAR) && ((m > UTIME_MINMONTH) \
76   || ((m == UTIME_MINMONTH) && (d >= UTIME_MINDAY))))) \
77  && ((y < UTIME_MAXYEAR) \
78  || ((y == UTIME_MAXYEAR) && ((m < UTIME_MAXMONTH) \
79   || ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
80
81
82
83
84 /*****************************************************************************
85  *       PRIVATE ROUTINES                                                                                                                *
86  *****************************************************************************/
87
88 /* definitions for squeezing values into "value" */
89 #define ABS_SIGNBIT             (char) 0200
90 #define VALMASK                 (char) 0177
91 #define NEG(n)                  ((n)|ABS_SIGNBIT)
92 #define SIGNEDCHAR(c)   ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
93 #define FROMVAL(tp)             (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
94 #define TOVAL(tp, v)    ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
95
96 /*
97  * to keep this table reasonably small, we divide the lexval for TZ and DTZ
98  * entries by 10 and truncate the text field at MAXTOKLEN characters.
99  * the text field is not guaranteed to be NULL-terminated.
100  */
101 static datetkn datetktbl[] = {
102 /*              text                    token   lexval */
103         {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
104         {"acsst", DTZ, 63},                     /* Cent. Australia */
105         {"acst", TZ, 57},                       /* Cent. Australia */
106         {DA_D, ADBC, AD},                       /* "ad" for years >= 0 */
107         {"abstime", IGNOREFIELD, 0},            /* "abstime" for pre-v6.1 "Invalid
108                                                                  * Abstime" */
109         {"adt", DTZ, NEG(18)},          /* Atlantic Daylight Time */
110         {"aesst", DTZ, 66},                     /* E. Australia */
111         {"aest", TZ, 60},                       /* Australia Eastern Std Time */
112         {"ahst", TZ, 60},                       /* Alaska-Hawaii Std Time */
113         {"allballs", RESERV, DTK_ZULU},         /* 00:00:00 */
114         {"am", AMPM, AM},
115         {"apr", MONTH, 4},
116         {"april", MONTH, 4},
117         {"ast", TZ, NEG(24)},           /* Atlantic Std Time (Canada) */
118         {"at", IGNOREFIELD, 0},                 /* "at" (throwaway) */
119         {"aug", MONTH, 8},
120         {"august", MONTH, 8},
121         {"awsst", DTZ, 54},                     /* W. Australia */
122         {"awst", TZ, 48},                       /* W. Australia */
123         {DB_C, ADBC, BC},                       /* "bc" for years < 0 */
124         {"bst", TZ, 6},                         /* British Summer Time */
125         {"bt", TZ, 18},                         /* Baghdad Time */
126         {"cadt", DTZ, 63},                      /* Central Australian DST */
127         {"cast", TZ, 57},                       /* Central Australian ST */
128         {"cat", TZ, NEG(60)},           /* Central Alaska Time */
129         {"cct", TZ, 48},                        /* China Coast */
130         {"cdt", DTZ, NEG(30)},          /* Central Daylight Time */
131         {"cet", TZ, 6},                         /* Central European Time */
132         {"cetdst", DTZ, 12},            /* Central European Dayl.Time */
133         {"cst", TZ, NEG(36)},           /* Central Standard Time */
134         {DCURRENT, RESERV, DTK_CURRENT},        /* "current" is always now */
135         {"dec", MONTH, 12},
136         {"december", MONTH, 12},
137         {"dnt", TZ, 6},                         /* Dansk Normal Tid */
138         {"dow", RESERV, DTK_DOW},       /* day of week */
139         {"doy", RESERV, DTK_DOY},       /* day of year */
140         {"dst", DTZMOD, 6},
141         {"east", TZ, NEG(60)},          /* East Australian Std Time */
142         {"edt", DTZ, NEG(24)},          /* Eastern Daylight Time */
143         {"eet", TZ, 12},                        /* East. Europe, USSR Zone 1 */
144         {"eetdst", DTZ, 18},            /* Eastern Europe */
145         {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
146 #if USE_AUSTRALIAN_RULES
147         {"est", TZ, 60},                        /* Australia Eastern Std Time */
148 #else
149         {"est", TZ, NEG(30)},           /* Eastern Standard Time */
150 #endif
151         {"feb", MONTH, 2},
152         {"february", MONTH, 2},
153         {"fri", DOW, 5},
154         {"friday", DOW, 5},
155         {"fst", TZ, 6},                         /* French Summer Time */
156         {"fwt", DTZ, 12},                       /* French Winter Time  */
157         {"gmt", TZ, 0},                         /* Greenwish Mean Time */
158         {"gst", TZ, 60},                        /* Guam Std Time, USSR Zone 9 */
159         {"hdt", DTZ, NEG(54)},          /* Hawaii/Alaska */
160         {"hmt", DTZ, 18},                       /* Hellas ? ? */
161         {"hst", TZ, NEG(60)},           /* Hawaii Std Time */
162         {"idle", TZ, 72},                       /* Intl. Date Line, East */
163         {"idlw", TZ, NEG(72)},          /* Intl. Date Line,,    est */
164         {LATE, RESERV, DTK_LATE},       /* "infinity" reserved for "late time" */
165         {INVALID, RESERV, DTK_INVALID},         /* "invalid" reserved for invalid
166                                                                                  * time */
167         {"ist", TZ, 12},                        /* Israel */
168         {"it", TZ, 22},                         /* Iran Time */
169         {"jan", MONTH, 1},
170         {"january", MONTH, 1},
171         {"jst", TZ, 54},                        /* Japan Std Time,USSR Zone 8 */
172         {"jt", TZ, 45},                         /* Java Time */
173         {"jul", MONTH, 7},
174         {"july", MONTH, 7},
175         {"jun", MONTH, 6},
176         {"june", MONTH, 6},
177         {"kst", TZ, 54},                        /* Korea Standard Time */
178         {"ligt", TZ, 60},                       /* From Melbourne, Australia */
179         {"mar", MONTH, 3},
180         {"march", MONTH, 3},
181         {"may", MONTH, 5},
182         {"mdt", DTZ, NEG(36)},          /* Mountain Daylight Time */
183         {"mest", DTZ, 12},                      /* Middle Europe Summer Time */
184         {"met", TZ, 6},                         /* Middle Europe Time */
185         {"metdst", DTZ, 12},            /* Middle Europe Daylight Time */
186         {"mewt", TZ, 6},                        /* Middle Europe Winter Time */
187         {"mez", TZ, 6},                         /* Middle Europe Zone */
188         {"mon", DOW, 1},
189         {"monday", DOW, 1},
190         {"mst", TZ, NEG(42)},           /* Mountain Standard Time */
191         {"mt", TZ, 51},                         /* Moluccas Time */
192         {"ndt", DTZ, NEG(15)},          /* Nfld. Daylight Time */
193         {"nft", TZ, NEG(21)},           /* Newfoundland Standard Time */
194         {"nor", TZ, 6},                         /* Norway Standard Time */
195         {"nov", MONTH, 11},
196         {"november", MONTH, 11},
197         {NOW, RESERV, DTK_NOW},         /* current transaction time */
198         {"nst", TZ, NEG(21)},           /* Nfld. Standard Time */
199         {"nt", TZ, NEG(66)},            /* Nome Time */
200         {"nzdt", DTZ, 78},                      /* New Zealand Daylight Time */
201         {"nzst", TZ, 72},                       /* New Zealand Standard Time */
202         {"nzt", TZ, 72},                        /* New Zealand Time */
203         {"oct", MONTH, 10},
204         {"october", MONTH, 10},
205         {"on", IGNOREFIELD, 0},                 /* "on" (throwaway) */
206         {"pdt", DTZ, NEG(42)},          /* Pacific Daylight Time */
207         {"pm", AMPM, PM},
208         {"pst", TZ, NEG(48)},           /* Pacific Standard Time */
209         {"sadt", DTZ, 63},                      /* S. Australian Dayl. Time */
210         {"sast", TZ, 57},                       /* South Australian Std Time */
211         {"sat", DOW, 6},
212         {"saturday", DOW, 6},
213         {"sep", MONTH, 9},
214         {"sept", MONTH, 9},
215         {"september", MONTH, 9},
216         {"set", TZ, NEG(6)},            /* Seychelles Time ?? */
217         {"sst", DTZ, 12},                       /* Swedish Summer Time */
218         {"sun", DOW, 0},
219         {"sunday", DOW, 0},
220         {"swt", TZ, 6},                         /* Swedish Winter Time  */
221         {"thu", DOW, 4},
222         {"thur", DOW, 4},
223         {"thurs", DOW, 4},
224         {"thursday", DOW, 4},
225         {TODAY, RESERV, DTK_TODAY}, /* midnight */
226         {TOMORROW, RESERV, DTK_TOMORROW},       /* tomorrow midnight */
227         {"tue", DOW, 2},
228         {"tues", DOW, 2},
229         {"tuesday", DOW, 2},
230         {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
231                                                                                  * time */
232         {"ut", TZ, 0},
233         {"utc", TZ, 0},
234         {"wadt", DTZ, 48},                      /* West Australian DST */
235         {"wast", TZ, 42},                       /* West Australian Std Time */
236         {"wat", TZ, NEG(6)},            /* West Africa Time */
237         {"wdt", DTZ, 54},                       /* West Australian DST */
238         {"wed", DOW, 3},
239         {"wednesday", DOW, 3},
240         {"weds", DOW, 3},
241         {"wet", TZ, 0},                         /* Western Europe */
242         {"wetdst", DTZ, 6},                     /* Western Europe */
243         {"wst", TZ, 48},                        /* West Australian Std Time */
244         {"ydt", DTZ, NEG(48)},          /* Yukon Daylight Time */
245         {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
246         {"yst", TZ, NEG(54)},           /* Yukon Standard Time */
247         {"zp4", TZ, NEG(24)},           /* GMT +4  hours. */
248         {"zp5", TZ, NEG(30)},           /* GMT +5  hours. */
249         {"zp6", TZ, NEG(36)},           /* GMT +6  hours. */
250         {"z", RESERV, DTK_ZULU},        /* 00:00:00 */
251         {ZULU, RESERV, DTK_ZULU},       /* 00:00:00 */
252 };
253
254 static unsigned int szdatetktbl = sizeof(datetktbl) / sizeof(datetktbl[0]);
255
256
257
258 #if USE_DATE_CACHE
259 datetkn    *datecache[MAXDATEFIELDS] = {NULL};
260
261 datetkn    *deltacache[MAXDATEFIELDS] = {NULL};
262
263 #endif
264
265
266 /*
267  * Calendar time to Julian date conversions.
268  * Julian date is commonly used in astronomical applications,
269  *      since it is numerically accurate and computationally simple.
270  * The algorithms here will accurately convert between Julian day
271  *      and calendar date for all non-negative Julian days
272  *      (i.e. from Nov 23, -4713 on).
273  *
274  * Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
275  *      University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
276  *
277  * Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
278  *      now at Aerospace Corp. (hi, Henry!)
279  *
280  * These routines will be used by other date/time packages - tgl 97/02/25
281  */
282
283 /* Set the minimum year to one greater than the year of the first valid day
284  *      to avoid having to check year and day both. - tgl 97/05/08
285  */
286
287 #define JULIAN_MINYEAR (-4713)
288 #define JULIAN_MINMONTH (11)
289 #define JULIAN_MINDAY (23)
290
291 #define IS_VALID_JULIAN(y,m,d) ((y > JULIAN_MINYEAR) \
292  || ((y == JULIAN_MINYEAR) && ((m > JULIAN_MINMONTH) \
293   || ((m == JULIAN_MINMONTH) && (d >= JULIAN_MINDAY)))))
294
295 int
296 date2j(int y, int m, int d)
297 {
298         int                     m12 = (m - 14) / 12;
299
300         return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
301                         - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
302 }       /* date2j() */
303
304 void
305 j2date(int jd, int *year, int *month, int *day)
306 {
307         int                     j,
308                                 y,
309                                 m,
310                                 d;
311
312         int                     i,
313                                 l,
314                                 n;
315
316         l = jd + 68569;
317         n = (4 * l) / 146097;
318         l -= (146097 * n + 3) / 4;
319         i = (4000 * (l + 1)) / 1461001;
320         l += 31 - (1461 * i) / 4;
321         j = (80 * l) / 2447;
322         d = l - (2447 * j) / 80;
323         l = j / 11;
324         m = (j + 2) - (12 * l);
325         y = 100 * (n - 49) + i + l;
326
327         *year = y;
328         *month = m;
329         *day = d;
330         return;
331 }       /* j2date() */
332
333
334
335
336 /*
337  * parse and convert date in timestr (the normal interface)
338  *
339  * Returns the number of seconds since epoch (J2000)
340  */
341
342 /* ParseDateTime()
343  * Break string into tokens based on a date/time context.
344  */
345 int
346 ParseDateTime(char *timestr, char *lowstr,
347                           char **field, int *ftype, int maxfields, int *numfields)
348 {
349         int                     nf = 0;
350         char       *cp = timestr;
351         char       *lp = lowstr;
352
353 #ifdef DATEDEBUG
354         printf("ParseDateTime- input string is %s\n", timestr);
355 #endif
356         /* outer loop through fields */
357         while (*cp != '\0')
358         {
359                 field[nf] = lp;
360
361                 /* leading digit? then date or time */
362                 if (isdigit(*cp) || (*cp == '.'))
363                 {
364                         *lp++ = *cp++;
365                         while (isdigit(*cp))
366                                 *lp++ = *cp++;
367                         /* time field? */
368                         if (*cp == ':')
369                         {
370                                 ftype[nf] = DTK_TIME;
371                                 while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
372                                         *lp++ = *cp++;
373
374                         }
375                         /* date field? allow embedded text month */
376                         else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
377                         {
378                                 ftype[nf] = DTK_DATE;
379                                 while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
380                                         *lp++ = tolower(*cp++);
381
382                         }
383
384                         /*
385                          * otherwise, number only and will determine year, month, or
386                          * day later
387                          */
388                         else
389                                 ftype[nf] = DTK_NUMBER;
390
391                 }
392
393                 /*
394                  * text? then date string, month, day of week, special, or
395                  * timezone
396                  */
397                 else if (isalpha(*cp))
398                 {
399                         ftype[nf] = DTK_STRING;
400                         *lp++ = tolower(*cp++);
401                         while (isalpha(*cp))
402                                 *lp++ = tolower(*cp++);
403
404                         /* full date string with leading text month? */
405                         if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
406                         {
407                                 ftype[nf] = DTK_DATE;
408                                 while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
409                                         *lp++ = tolower(*cp++);
410                         }
411
412                         /* skip leading spaces */
413                 }
414                 else if (isspace(*cp))
415                 {
416                         cp++;
417                         continue;
418
419                         /* sign? then special or numeric timezone */
420                 }
421                 else if ((*cp == '+') || (*cp == '-'))
422                 {
423                         *lp++ = *cp++;
424                         /* soak up leading whitespace */
425                         while (isspace(*cp))
426                                 cp++;
427                         /* numeric timezone? */
428                         if (isdigit(*cp))
429                         {
430                                 ftype[nf] = DTK_TZ;
431                                 *lp++ = *cp++;
432                                 while (isdigit(*cp) || (*cp == ':'))
433                                         *lp++ = *cp++;
434
435                                 /* special? */
436                         }
437                         else if (isalpha(*cp))
438                         {
439                                 ftype[nf] = DTK_SPECIAL;
440                                 *lp++ = tolower(*cp++);
441                                 while (isalpha(*cp))
442                                         *lp++ = tolower(*cp++);
443
444                                 /* otherwise something wrong... */
445                         }
446                         else
447                                 return -1;
448
449                         /* ignore punctuation but use as delimiter */
450                 }
451                 else if (ispunct(*cp))
452                 {
453                         cp++;
454                         continue;
455
456                 }
457                 else
458                         return -1;
459
460                 /* force in a delimiter */
461                 *lp++ = '\0';
462                 nf++;
463                 if (nf > MAXDATEFIELDS)
464                         return -1;
465 #ifdef DATEDEBUG
466                 printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
467 #endif
468         }
469
470         *numfields = nf;
471
472         return 0;
473 }       /* ParseDateTime() */
474
475
476 /* DecodeDateTime()
477  * Interpret previously parsed fields for general date and time.
478  * Return 0 if full date, 1 if only time, and -1 if problems.
479  *              External format(s):
480  *                              "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
481  *                              "Fri Feb-7-1997 15:23:27"
482  *                              "Feb-7-1997 15:23:27"
483  *                              "2-7-1997 15:23:27"
484  *                              "1997-2-7 15:23:27"
485  *                              "1997.038 15:23:27"             (day of year 1-366)
486  *              Also supports input in compact time:
487  *                              "970207 152327"
488  *                              "97038 152327"
489  *
490  * Use the system-provided functions to get the current time zone
491  *      if not specified in the input string.
492  * If the date is outside the time_t system-supported time range,
493  *      then assume GMT time zone. - tgl 97/05/27
494  */
495 int
496 DecodeDateTime(char **field, int *ftype, int nf,
497                            int *dtype, struct tm * tm, double *fsec, int *tzp)
498 {
499         int                     fmask = 0,
500                                 tmask,
501                                 type;
502         int                     i;
503         int                     flen,
504                                 val;
505         int                     mer = HR24;
506         int                     bc = FALSE;
507
508         *dtype = DTK_DATE;
509         tm->tm_hour = 0;
510         tm->tm_min = 0;
511         tm->tm_sec = 0;
512         *fsec = 0;
513         tm->tm_isdst = -1;                      /* don't know daylight savings time status
514                                                                  * apriori */
515         if (tzp != NULL)
516                 *tzp = 0;
517
518         for (i = 0; i < nf; i++)
519         {
520 #ifdef DATEDEBUG
521                 printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
522 #endif
523                 switch (ftype[i])
524                 {
525                         case DTK_DATE:
526                                 if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
527                                         return -1;
528                                 break;
529
530                         case DTK_TIME:
531                                 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
532                                         return -1;
533
534                                 /*
535                                  * check upper limit on hours; other limits checked in
536                                  * DecodeTime()
537                                  */
538                                 if (tm->tm_hour > 23)
539                                         return -1;
540                                 break;
541
542                         case DTK_TZ:
543                                 if (tzp == NULL)
544                                         return -1;
545                                 if (DecodeTimezone(field[i], tzp) != 0)
546                                         return -1;
547                                 tmask = DTK_M(TZ);
548                                 break;
549
550                         case DTK_NUMBER:
551                                 flen = strlen(field[i]);
552
553                                 if (flen > 4)
554                                 {
555                                         if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
556                                                 return -1;
557
558                                 }
559                                 else
560                                 {
561                                         if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
562                                                 return -1;
563                                 }
564                                 break;
565
566                         case DTK_STRING:
567                         case DTK_SPECIAL:
568                                 type = DecodeSpecial(i, field[i], &val);
569 #ifdef DATEDEBUG
570                                 printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
571 #endif
572                                 if (type == IGNOREFIELD)
573                                         continue;
574
575                                 tmask = DTK_M(type);
576                                 switch (type)
577                                 {
578                                         case RESERV:
579 #ifdef DATEDEBUG
580                                                 printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
581 #endif
582                                                 switch (val)
583                                                 {
584
585                                                         default:
586                                                                 *dtype = val;
587                                                 }
588
589                                                 break;
590
591                                         case MONTH:
592 #ifdef DATEDEBUG
593                                                 printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
594 #endif
595                         /* tm_mon is 0->11, so need to subtract one from value in table */
596                                                 tm->tm_mon = val-1;
597                                                 break;
598
599                                                 /*
600                                                  * daylight savings time modifier (solves "MET
601                                                  * DST" syntax)
602                                                  */
603                                         case DTZMOD:
604                                                 tmask |= DTK_M(DTZ);
605                                                 tm->tm_isdst = 1;
606                                                 if (tzp == NULL)
607                                                         return -1;
608                                                 *tzp += val * 60;
609                                                 break;
610
611                                         case DTZ:
612
613                                                 /*
614                                                  * set mask for TZ here _or_ check for DTZ later
615                                                  * when getting default timezone
616                                                  */
617                                                 tmask |= DTK_M(TZ);
618                                                 tm->tm_isdst = 1;
619                                                 if (tzp == NULL)
620                                                         return -1;
621                                                 *tzp = val * 60;
622                                                 break;
623
624                                         case TZ:
625                                                 tm->tm_isdst = 0;
626                                                 if (tzp == NULL)
627                                                         return -1;
628                                                 *tzp = val * 60;
629                                                 break;
630
631                                         case IGNOREFIELD:
632                                                 break;
633
634                                         case AMPM:
635                                                 mer = val;
636                                                 break;
637
638                                         case ADBC:
639                                                 bc = (val == BC);
640                                                 break;
641
642                                         case DOW:
643                                                 tm->tm_wday = val;
644                                                 break;
645
646                                         default:
647                                                 return -1;
648                                 }
649                                 break;
650
651                         default:
652                                 return -1;
653                 }
654
655 #ifdef DATEDEBUG
656                 printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
657                            i, field[i], fmask, tmask, val);
658 #endif
659
660                 if (tmask & fmask)
661                         return -1;
662                 fmask |= tmask;
663         }
664
665         /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
666         if (bc)
667                 tm->tm_year = -(tm->tm_year - 1);
668
669         if ((mer != HR24) && (tm->tm_hour > 12))
670                 return -1;
671         if ((mer == AM) && (tm->tm_hour == 12))
672                 tm->tm_hour = 0;
673         else if ((mer == PM) && (tm->tm_hour != 12))
674                 tm->tm_hour += 12;
675
676     /* If parsing a time string into a date, all date parts are unset.
677        Win2k defaults these to 30 dec, 1899 so:                        */
678     if (tm->tm_year == 0 && tm->tm_mon == 0 && tm->tm_mday == 0 && fmask == DTK_TIME_M) {
679         tm->tm_year  = 1899;
680         tm->tm_mon   = 11; /* December, as tm_mon is 0..11 */
681         tm->tm_mday  = 30;
682     }
683
684
685 #ifdef DATEDEBUG
686         printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
687         printf(" set y%04d m%02d d%02d", tm->tm_year, (tm->tm_mon+1), tm->tm_mday);
688         printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
689 #endif
690
691         if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
692                 return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
693
694         /* timezone not specified? then find local timezone if possible */
695         if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
696                 && (tzp != NULL) && (!(fmask & DTK_M(TZ))))
697         {
698
699                 /*
700                  * daylight savings time modifier but no standard timezone? then
701                  * error
702                  */
703                 if (fmask & DTK_M(DTZMOD))
704                         return -1;
705
706                 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon+1, tm->tm_mday))
707                 {
708                         /* FIXME: The code below is not correct */
709 #if 0 /* defined(USE_POSIX_TIME) */
710                         tm->tm_year -= 1900;
711                         tm->tm_mon -= 1;
712                         tm->tm_isdst = -1;
713                         mktime(tm);
714                         tm->tm_year += 1900;
715                         tm->tm_mon += 1;
716
717 #if 0 /* defined(HAVE_INT_TIMEZONE) */
718                         *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
719
720 #else                                                   /* !HAVE_INT_TIMEZONE */
721                         *tzp = -(tm->tm_gmtoff);        /* tm_gmtoff is Sun/DEC-ism */
722 #endif
723
724 #else                                                   /* !USE_POSIX_TIME */
725                         *tzp = CTimeZone;
726 #endif
727                 }
728                 else
729                 {
730                         tm->tm_isdst = 0;
731                         *tzp = 0;
732                 }
733         }
734
735         return 0;
736 }       /* DecodeDateTime() */
737
738
739 /* DecodeTimeOnly()
740  * Interpret parsed string as time fields only.
741  */
742 int
743 DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
744 {
745         int                     fmask,
746                                 tmask,
747                                 type;
748         int                     i;
749         int                     flen,
750                                 val;
751         int                     mer = HR24;
752
753         *dtype = DTK_TIME;
754         tm->tm_hour = 0;
755         tm->tm_min = 0;
756         tm->tm_sec = 0;
757         tm->tm_isdst = -1;                      /* don't know daylight savings time status
758                                                                  * apriori */
759         *fsec = 0;
760
761         fmask = DTK_DATE_M;
762
763         for (i = 0; i < nf; i++)
764         {
765 #ifdef DATEDEBUG
766                 printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
767 #endif
768                 switch (ftype[i])
769                 {
770                         case DTK_TIME:
771                                 if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
772                                         return -1;
773                                 break;
774
775                         case DTK_NUMBER:
776                                 flen = strlen(field[i]);
777
778                                 if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
779                                         return -1;
780                                 break;
781
782                         case DTK_STRING:
783                         case DTK_SPECIAL:
784                                 type = DecodeSpecial(i, field[i], &val);
785 #ifdef DATEDEBUG
786                                 printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
787 #endif
788                                 if (type == IGNOREFIELD)
789                                         continue;
790
791                                 tmask = DTK_M(type);
792                                 switch (type)
793                                 {
794                                         case RESERV:
795 #ifdef DATEDEBUG
796                                                 printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
797 #endif
798                                                 switch (val)
799                                                 {
800
801                                                         default:
802                                                                 return -1;
803                                                 }
804
805                                                 break;
806
807                                         case IGNOREFIELD:
808                                                 break;
809
810                                         case AMPM:
811                                                 mer = val;
812                                                 break;
813
814                                         default:
815                                                 return -1;
816                                 }
817                                 break;
818
819                         default:
820                                 return -1;
821                 }
822
823                 if (tmask & fmask)
824                         return -1;
825                 fmask |= tmask;
826
827 #ifdef DATEDEBUG
828                 printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
829 #endif
830         }
831
832 #ifdef DATEDEBUG
833         printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
834         printf(" %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
835 #endif
836
837         if ((mer != HR24) && (tm->tm_hour > 12))
838                 return -1;
839         if ((mer == AM) && (tm->tm_hour == 12))
840                 tm->tm_hour = 0;
841         else if ((mer == PM) && (tm->tm_hour != 12))
842                 tm->tm_hour += 12;
843
844         if ((fmask & DTK_TIME_M) != DTK_TIME_M)
845                 return -1;
846
847         return 0;
848 }       /* DecodeTimeOnly() */
849
850
851 /* DecodeDate()
852  * Decode date string which includes delimiters.
853  * Insist on a complete set of fields.
854  */
855 static int
856 DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
857 {
858         double          fsec;
859
860         int                     nf = 0;
861         int                     i,
862                                 len;
863         int                     type,
864                                 val,
865                                 dmask = 0;
866         char       *field[MAXDATEFIELDS];
867
868         /* parse this string... */
869         while ((*str != '\0') && (nf < MAXDATEFIELDS))
870         {
871                 /* skip field separators */
872                 while (!isalnum(*str))
873                         str++;
874
875                 field[nf] = str;
876                 if (isdigit(*str))
877                 {
878                         while (isdigit(*str))
879                                 str++;
880                 }
881                 else if (isalpha(*str))
882                 {
883                         while (isalpha(*str))
884                                 str++;
885                 }
886
887                 if (*str != '\0')
888                         *str++ = '\0';
889                 nf++;
890         }
891
892         /* don't allow too many fields */
893         if (nf > 3)
894                 return -1;
895
896         *tmask = 0;
897
898         /* look first for text fields, since that will be unambiguous month */
899         for (i = 0; i < nf; i++)
900         {
901                 if (isalpha(*field[i]))
902                 {
903                         type = DecodeSpecial(i, field[i], &val);
904                         if (type == IGNOREFIELD)
905                                 continue;
906
907                         dmask = DTK_M(type);
908                         switch (type)
909                         {
910                                 case MONTH:
911 #ifdef DATEDEBUG
912                                         printf("DecodeDate- month field %s value is %d\n", field[i], val);
913 #endif
914                     /* tm_mon is 0->11, so need to subtract one from value in table */
915                                         tm->tm_mon = val-1;
916                                         break;
917
918                                 default:
919 #ifdef DATEDEBUG
920                                         printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
921 #endif
922                                         return -1;
923                         }
924                         if (fmask & dmask)
925                                 return -1;
926
927                         fmask |= dmask;
928                         *tmask |= dmask;
929
930                         /* mark this field as being completed */
931                         field[i] = NULL;
932                 }
933         }
934
935         /* now pick up remaining numeric fields */
936         for (i = 0; i < nf; i++)
937         {
938                 if (field[i] == NULL)
939                         continue;
940
941                 if ((len = strlen(field[i])) <= 0)
942                         return -1;
943
944                 if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
945                         return -1;
946
947                 if (fmask & dmask)
948                         return -1;
949
950                 fmask |= dmask;
951                 *tmask |= dmask;
952         }
953
954         return 0;
955 }       /* DecodeDate() */
956
957
958 /* DecodeTime()
959  * Decode time string which includes delimiters.
960  * Only check the lower limit on hours, since this same code
961  *      can be used to represent time spans.
962  */
963 static int
964 DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
965 {
966         char       *cp;
967
968         *tmask = DTK_TIME_M;
969
970         tm->tm_hour = strtol(str, &cp, 10);
971         if (*cp != ':')
972                 return -1;
973         str = cp + 1;
974         tm->tm_min = strtol(str, &cp, 10);
975         if (*cp == '\0')
976         {
977                 tm->tm_sec = 0;
978                 *fsec = 0;
979
980         }
981         else if (*cp != ':')
982         {
983                 return -1;
984
985         }
986         else
987         {
988                 str = cp + 1;
989                 tm->tm_sec = strtol(str, &cp, 10);
990                 if (*cp == '\0')
991                         *fsec = 0;
992                 else if (*cp == '.')
993                 {
994                         str = cp;
995                         *fsec = strtod(str, &cp);
996                         if (cp == str)
997                                 return -1;
998                 }
999                 else
1000                         return -1;
1001         }
1002
1003         /* do a sanity check */
1004         if ((tm->tm_hour < 0)
1005                 || (tm->tm_min < 0) || (tm->tm_min > 59)
1006                 || (tm->tm_sec < 0) || (tm->tm_sec > 59))
1007                 return -1;
1008
1009         return 0;
1010 }       /* DecodeTime() */
1011
1012
1013 /* DecodeNumber()
1014  * Interpret numeric field as a date value in context.
1015  */
1016 static int
1017 DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1018 {
1019         int                     val;
1020         char       *cp;
1021
1022         *tmask = 0;
1023
1024         val = strtol(str, &cp, 10);
1025         if (cp == str)
1026                 return -1;
1027         if (*cp == '.')
1028         {
1029                 *fsec = strtod(cp, &cp);
1030                 if (*cp != '\0')
1031                         return -1;
1032         }
1033
1034 #ifdef DATEDEBUG
1035         printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
1036 #endif
1037
1038         /* enough digits to be unequivocal year? */
1039         if (flen == 4)
1040         {
1041 #ifdef DATEDEBUG
1042                 printf("DecodeNumber- match %d (%s) as year\n", val, str);
1043 #endif
1044                 *tmask = DTK_M(YEAR);
1045
1046                 /* already have a year? then see if we can substitute... */
1047                 if (fmask & DTK_M(YEAR))
1048                 {
1049                         if ((!(fmask & DTK_M(DAY)))
1050                                 && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
1051                         {
1052 #ifdef DATEDEBUG
1053                                 printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
1054 #endif
1055                                 tm->tm_mday = tm->tm_year;
1056                                 *tmask = DTK_M(DAY);
1057                         }
1058                 }
1059
1060                 tm->tm_year = val;
1061
1062                 /* special case day of year? */
1063         }
1064         else if ((flen == 3) && (fmask & DTK_M(YEAR))
1065                          && ((val >= 1) && (val <= 366)))
1066         {
1067                 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
1068                 tm->tm_yday = val;
1069                 j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
1070                            &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1071
1072                 /* already have year? then could be month */
1073         }
1074         else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
1075                          && ((val >= 1) && (val <= 12)))
1076         {
1077 #ifdef DATEDEBUG
1078                 printf("DecodeNumber- match %d (%s) as month\n", val, str);
1079 #endif
1080                 *tmask = DTK_M(MONTH);
1081         /* tm_mon is 0..11 */
1082                 tm->tm_mon = val-1;
1083
1084                 /* no year and EuroDates enabled? then could be day */
1085         }
1086         else if ((EuroDates || (fmask & DTK_M(MONTH)))
1087                          && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
1088                          && ((val >= 1) && (val <= 31)))
1089         {
1090 #ifdef DATEDEBUG
1091                 printf("DecodeNumber- match %d (%s) as day\n", val, str);
1092 #endif
1093                 *tmask = DTK_M(DAY);
1094                 tm->tm_mday = val;
1095
1096         }
1097         else if ((!(fmask & DTK_M(MONTH)))
1098                          && ((val >= 1) && (val <= 12)))
1099         {
1100 #ifdef DATEDEBUG
1101                 printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
1102 #endif
1103                 *tmask = DTK_M(MONTH);
1104         /* tm_mon is 0..11 */
1105                 tm->tm_mon = val-1;
1106
1107         }
1108         else if ((!(fmask & DTK_M(DAY)))
1109                          && ((val >= 1) && (val <= 31)))
1110         {
1111 #ifdef DATEDEBUG
1112                 printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
1113 #endif
1114                 *tmask = DTK_M(DAY);
1115                 tm->tm_mday = val;
1116
1117         }
1118         else if (!(fmask & DTK_M(YEAR)))
1119         {
1120 #ifdef DATEDEBUG
1121                 printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
1122 #endif
1123                 *tmask = DTK_M(YEAR);
1124                 tm->tm_year = val;
1125                 if (tm->tm_year < 70)
1126                         tm->tm_year += 2000;
1127                 else if (tm->tm_year < 100)
1128                         tm->tm_year += 1900;
1129
1130         }
1131         else
1132                 return -1;
1133
1134         return 0;
1135 }       /* DecodeNumber() */
1136
1137
1138 /* DecodeNumberField()
1139  * Interpret numeric string as a concatenated date field.
1140  */
1141 static int
1142 DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
1143 {
1144         char       *cp;
1145
1146         /* yyyymmdd? */
1147         if (len == 8)
1148         {
1149 #ifdef DATEDEBUG
1150                 printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1151 #endif
1152
1153                 *tmask = DTK_DATE_M;
1154
1155                 tm->tm_mday = atoi(str + 6);
1156                 *(str + 6) = '\0';
1157                 tm->tm_mon = atoi(str + 4) - 1;  /* tm_mon is 0..11 */
1158                 *(str + 4) = '\0';
1159                 tm->tm_year = atoi(str + 0);
1160
1161                 /* yymmdd or hhmmss? */
1162         }
1163         else if (len == 6)
1164         {
1165 #ifdef DATEDEBUG
1166                 printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1167 #endif
1168                 if (fmask & DTK_DATE_M)
1169                 {
1170 #ifdef DATEDEBUG
1171                         printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1172 #endif
1173                         *tmask = DTK_TIME_M;
1174                         tm->tm_sec = atoi(str + 4);
1175                         *(str + 4) = '\0';
1176                         tm->tm_min = atoi(str + 2);
1177                         *(str + 2) = '\0';
1178                         tm->tm_hour = atoi(str + 0);
1179
1180                 }
1181                 else
1182                 {
1183 #ifdef DATEDEBUG
1184                         printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1185 #endif
1186                         *tmask = DTK_DATE_M;
1187                         tm->tm_mday = atoi(str + 4);
1188                         *(str + 4) = '\0';
1189                         tm->tm_mon = atoi(str + 2) - 1; /* tm_mon is 0..11 */
1190                         *(str + 2) = '\0';
1191                         tm->tm_year = atoi(str + 0);
1192                 }
1193
1194         }
1195         else if (strchr(str, '.') != NULL)
1196         {
1197 #ifdef DATEDEBUG
1198                 printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
1199 #endif
1200                 *tmask = DTK_TIME_M;
1201                 tm->tm_sec = strtod((str + 4), &cp);
1202                 if (cp == (str + 4))
1203                         return -1;
1204                 if (*cp == '.')
1205                         *fsec = strtod(cp, NULL);
1206                 *(str + 4) = '\0';
1207                 tm->tm_min = strtod((str + 2), &cp);
1208                 *(str + 2) = '\0';
1209                 tm->tm_hour = strtod((str + 0), &cp);
1210
1211         }
1212         else
1213                 return -1;
1214
1215         return 0;
1216 }       /* DecodeNumberField() */
1217
1218
1219 /* DecodeTimezone()
1220  * Interpret string as a numeric timezone.
1221  */
1222 static int
1223 DecodeTimezone(char *str, int *tzp)
1224 {
1225         int                     tz;
1226         int                     hr,
1227                                 min;
1228         char       *cp;
1229         int                     len;
1230
1231         /* assume leading character is "+" or "-" */
1232         hr = strtol((str + 1), &cp, 10);
1233
1234         /* explicit delimiter? */
1235         if (*cp == ':')
1236         {
1237                 min = strtol((cp + 1), &cp, 10);
1238
1239                 /* otherwise, might have run things together... */
1240         }
1241         else if ((*cp == '\0') && ((len = strlen(str)) > 3))
1242         {
1243                 min = strtol((str + len - 2), &cp, 10);
1244                 *(str + len - 2) = '\0';
1245                 hr = strtol((str + 1), &cp, 10);
1246
1247         }
1248         else
1249                 min = 0;
1250
1251         tz = (hr * 60 + min) * 60;
1252         if (*str == '-')
1253                 tz = -tz;
1254
1255         *tzp = -tz;
1256         return *cp != '\0';
1257 }       /* DecodeTimezone() */
1258
1259
1260 /* DecodeSpecial()
1261  * Decode text string using lookup table.
1262  * Implement a cache lookup since it is likely that dates
1263  *      will be related in format.
1264  */
1265 static int
1266 DecodeSpecial(int field, char *lowtoken, int *val)
1267 {
1268         int                     type;
1269         datetkn    *tp;
1270
1271 #if USE_DATE_CACHE
1272         if ((datecache[field] != NULL)
1273                 && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
1274                 tp = datecache[field];
1275         else
1276         {
1277 #endif
1278                 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
1279 #if USE_DATE_CACHE
1280         }
1281         datecache[field] = tp;
1282 #endif
1283         if (tp == NULL)
1284         {
1285                 type = IGNOREFIELD;
1286                 *val = 0;
1287         }
1288         else
1289         {
1290                 type = tp->type;
1291                 switch (type)
1292                 {
1293                         case TZ:
1294                         case DTZ:
1295                         case DTZMOD:
1296                                 *val = FROMVAL(tp);
1297                                 break;
1298
1299                         default:
1300                                 *val = tp->value;
1301                                 break;
1302                 }
1303         }
1304
1305         return type;
1306 }       /* DecodeSpecial() */
1307
1308
1309
1310 /* datebsearch()
1311  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
1312  * is WAY faster than the generic bsearch().
1313  */
1314 static datetkn *
1315 datebsearch(char *key, datetkn *base, unsigned int nel)
1316 {
1317         datetkn    *last = base + nel - 1,
1318                            *position;
1319         int                     result;
1320
1321         while (last >= base)
1322         {
1323                 position = base + ((last - base) >> 1);
1324                 result = key[0] - position->token[0];
1325                 if (result == 0)
1326                 {
1327                         result = strncmp(key, position->token, TOKMAXLEN);
1328                         if (result == 0)
1329                                 return position;
1330                 }
1331                 if (result < 0)
1332                         last = position - 1;
1333                 else
1334                         base = position + 1;
1335         }
1336         return NULL;
1337 }