os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclGetDate.y
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclGetDate.y --
sl@0
     3
 *
sl@0
     4
 *	Contains yacc grammar for parsing date and time strings.
sl@0
     5
 *	The output of this file should be the file tclDate.c which
sl@0
     6
 *	is used directly in the Tcl sources.
sl@0
     7
 *
sl@0
     8
 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
sl@0
     9
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
sl@0
    10
 *
sl@0
    11
 * See the file "license.terms" for information on usage and redistribution
sl@0
    12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    13
 *
sl@0
    14
 * RCS: @(#) $Id: tclGetDate.y,v 1.18.4.2 2005/11/04 20:15:09 kennykb Exp $
sl@0
    15
 */
sl@0
    16
sl@0
    17
%{
sl@0
    18
/* 
sl@0
    19
 * tclDate.c --
sl@0
    20
 *
sl@0
    21
 *	This file is generated from a yacc grammar defined in
sl@0
    22
 *	the file tclGetDate.y.  It should not be edited directly.
sl@0
    23
 *
sl@0
    24
 * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
sl@0
    25
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
sl@0
    26
 *
sl@0
    27
 * See the file "license.terms" for information on usage and redistribution
sl@0
    28
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    29
 *
sl@0
    30
 * SCCSID
sl@0
    31
 */
sl@0
    32
sl@0
    33
#include "tclInt.h"
sl@0
    34
#include "tclPort.h"
sl@0
    35
sl@0
    36
#if defined(MAC_TCL) && !defined(TCL_MAC_USE_MSL_EPOCH)
sl@0
    37
#   define EPOCH           1904
sl@0
    38
#   define START_OF_TIME   1904
sl@0
    39
#   define END_OF_TIME     2039
sl@0
    40
#else
sl@0
    41
#   define EPOCH           1970
sl@0
    42
#   define START_OF_TIME   1902
sl@0
    43
#   define END_OF_TIME     2037
sl@0
    44
#endif
sl@0
    45
sl@0
    46
/*
sl@0
    47
 * The offset of tm_year of struct tm returned by localtime, gmtime, etc.
sl@0
    48
 * I don't know how universal this is; K&R II, the NetBSD manpages, and
sl@0
    49
 * ../compat/strftime.c all agree that tm_year is the year-1900.  However,
sl@0
    50
 * some systems may have a different value.  This #define should be the
sl@0
    51
 * same as in ../compat/strftime.c.
sl@0
    52
 */
sl@0
    53
#define TM_YEAR_BASE 1900
sl@0
    54
sl@0
    55
#define HOUR(x)         ((int) (60 * x))
sl@0
    56
#define SECSPERDAY      (24L * 60L * 60L)
sl@0
    57
#define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
sl@0
    58
sl@0
    59
/*
sl@0
    60
 *  An entry in the lexical lookup table.
sl@0
    61
 */
sl@0
    62
typedef struct _TABLE {
sl@0
    63
    char        *name;
sl@0
    64
    int         type;
sl@0
    65
    time_t      value;
sl@0
    66
} TABLE;
sl@0
    67
sl@0
    68
sl@0
    69
/*
sl@0
    70
 *  Daylight-savings mode:  on, off, or not yet known.
sl@0
    71
 */
sl@0
    72
typedef enum _DSTMODE {
sl@0
    73
    DSTon, DSToff, DSTmaybe
sl@0
    74
} DSTMODE;
sl@0
    75
sl@0
    76
/*
sl@0
    77
 *  Meridian:  am, pm, or 24-hour style.
sl@0
    78
 */
sl@0
    79
typedef enum _MERIDIAN {
sl@0
    80
    MERam, MERpm, MER24
sl@0
    81
} MERIDIAN;
sl@0
    82
sl@0
    83
sl@0
    84
/*
sl@0
    85
 *  Global variables.  We could get rid of most of these by using a good
sl@0
    86
 *  union as the yacc stack.  (This routine was originally written before
sl@0
    87
 *  yacc had the %union construct.)  Maybe someday; right now we only use
sl@0
    88
 *  the %union very rarely.
sl@0
    89
 */
sl@0
    90
static char     *yyInput;
sl@0
    91
static DSTMODE  yyDSTmode;
sl@0
    92
static time_t   yyDayOrdinal;
sl@0
    93
static time_t   yyDayNumber;
sl@0
    94
static time_t   yyMonthOrdinal;
sl@0
    95
static int      yyHaveDate;
sl@0
    96
static int      yyHaveDay;
sl@0
    97
static int      yyHaveOrdinalMonth;
sl@0
    98
static int      yyHaveRel;
sl@0
    99
static int      yyHaveTime;
sl@0
   100
static int      yyHaveZone;
sl@0
   101
static time_t   yyTimezone;
sl@0
   102
static time_t   yyDay;
sl@0
   103
static time_t   yyHour;
sl@0
   104
static time_t   yyMinutes;
sl@0
   105
static time_t   yyMonth;
sl@0
   106
static time_t   yySeconds;
sl@0
   107
static time_t   yyYear;
sl@0
   108
static MERIDIAN yyMeridian;
sl@0
   109
static time_t   yyRelMonth;
sl@0
   110
static time_t   yyRelDay;
sl@0
   111
static time_t   yyRelSeconds;
sl@0
   112
static time_t  *yyRelPointer;
sl@0
   113
sl@0
   114
/*
sl@0
   115
 * Prototypes of internal functions.
sl@0
   116
 */
sl@0
   117
static void	yyerror _ANSI_ARGS_((char *s));
sl@0
   118
static time_t	ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes,
sl@0
   119
		    time_t Seconds, MERIDIAN Meridian));
sl@0
   120
static int	Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year,
sl@0
   121
		    time_t Hours, time_t Minutes, time_t Seconds,
sl@0
   122
		    MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr));
sl@0
   123
static time_t	DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future));
sl@0
   124
static time_t	NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal,
sl@0
   125
		    time_t DayNumber));
sl@0
   126
static time_t   NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal,
sl@0
   127
                    time_t MonthNumber));
sl@0
   128
static int	RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth,
sl@0
   129
		    time_t *TimePtr));
sl@0
   130
static int	RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay,
sl@0
   131
		    time_t *TimePtr));
sl@0
   132
static int	LookupWord _ANSI_ARGS_((char *buff));
sl@0
   133
static int	yylex _ANSI_ARGS_((void));
sl@0
   134
sl@0
   135
int
sl@0
   136
yyparse _ANSI_ARGS_((void));
sl@0
   137
%}
sl@0
   138
sl@0
   139
%union {
sl@0
   140
    time_t              Number;
sl@0
   141
    enum _MERIDIAN      Meridian;
sl@0
   142
}
sl@0
   143
sl@0
   144
%token  tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
sl@0
   145
%token  tSTARDATE tSEC_UNIT tSNUMBER tUNUMBER tZONE tEPOCH tDST tISOBASE
sl@0
   146
%token  tDAY_UNIT tNEXT
sl@0
   147
sl@0
   148
%type   <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT tDST
sl@0
   149
%type   <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE tISOBASE tDAY_UNIT
sl@0
   150
%type   <Number>        unit sign tNEXT tSTARDATE
sl@0
   151
%type   <Meridian>      tMERIDIAN o_merid
sl@0
   152
sl@0
   153
%%
sl@0
   154
sl@0
   155
spec    : /* NULL */
sl@0
   156
        | spec item
sl@0
   157
        ;
sl@0
   158
sl@0
   159
item    : time {
sl@0
   160
            yyHaveTime++;
sl@0
   161
        }
sl@0
   162
        | zone {
sl@0
   163
            yyHaveZone++;
sl@0
   164
        }
sl@0
   165
        | date {
sl@0
   166
            yyHaveDate++;
sl@0
   167
        }
sl@0
   168
        | ordMonth {
sl@0
   169
            yyHaveOrdinalMonth++;
sl@0
   170
        }
sl@0
   171
        | day {
sl@0
   172
            yyHaveDay++;
sl@0
   173
        }
sl@0
   174
        | relspec {
sl@0
   175
            yyHaveRel++;
sl@0
   176
        }
sl@0
   177
        | iso {
sl@0
   178
	    yyHaveTime++;
sl@0
   179
	    yyHaveDate++;
sl@0
   180
	}
sl@0
   181
        | trek {
sl@0
   182
	    yyHaveTime++;
sl@0
   183
	    yyHaveDate++;
sl@0
   184
	    yyHaveRel++;
sl@0
   185
        }
sl@0
   186
        | number
sl@0
   187
        ;
sl@0
   188
sl@0
   189
time    : tUNUMBER tMERIDIAN {
sl@0
   190
            yyHour = $1;
sl@0
   191
            yyMinutes = 0;
sl@0
   192
            yySeconds = 0;
sl@0
   193
            yyMeridian = $2;
sl@0
   194
        }
sl@0
   195
        | tUNUMBER ':' tUNUMBER o_merid {
sl@0
   196
            yyHour = $1;
sl@0
   197
            yyMinutes = $3;
sl@0
   198
            yySeconds = 0;
sl@0
   199
            yyMeridian = $4;
sl@0
   200
        }
sl@0
   201
        | tUNUMBER ':' tUNUMBER '-' tUNUMBER {
sl@0
   202
            yyHour = $1;
sl@0
   203
            yyMinutes = $3;
sl@0
   204
            yyMeridian = MER24;
sl@0
   205
            yyDSTmode = DSToff;
sl@0
   206
            yyTimezone = ($5 % 100 + ($5 / 100) * 60);
sl@0
   207
        }
sl@0
   208
        | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
sl@0
   209
            yyHour = $1;
sl@0
   210
            yyMinutes = $3;
sl@0
   211
            yySeconds = $5;
sl@0
   212
            yyMeridian = $6;
sl@0
   213
        }
sl@0
   214
        | tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER {
sl@0
   215
            yyHour = $1;
sl@0
   216
            yyMinutes = $3;
sl@0
   217
            yySeconds = $5;
sl@0
   218
            yyMeridian = MER24;
sl@0
   219
            yyDSTmode = DSToff;
sl@0
   220
            yyTimezone = ($7 % 100 + ($7 / 100) * 60);
sl@0
   221
        }
sl@0
   222
        ;
sl@0
   223
sl@0
   224
zone    : tZONE tDST {
sl@0
   225
            yyTimezone = $1;
sl@0
   226
            yyDSTmode = DSTon;
sl@0
   227
        }
sl@0
   228
        | tZONE {
sl@0
   229
            yyTimezone = $1;
sl@0
   230
            yyDSTmode = DSToff;
sl@0
   231
        }
sl@0
   232
        | tDAYZONE {
sl@0
   233
            yyTimezone = $1;
sl@0
   234
            yyDSTmode = DSTon;
sl@0
   235
        }
sl@0
   236
        ;
sl@0
   237
sl@0
   238
day     : tDAY {
sl@0
   239
            yyDayOrdinal = 1;
sl@0
   240
            yyDayNumber = $1;
sl@0
   241
        }
sl@0
   242
        | tDAY ',' {
sl@0
   243
            yyDayOrdinal = 1;
sl@0
   244
            yyDayNumber = $1;
sl@0
   245
        }
sl@0
   246
        | tUNUMBER tDAY {
sl@0
   247
            yyDayOrdinal = $1;
sl@0
   248
            yyDayNumber = $2;
sl@0
   249
        }
sl@0
   250
        | sign tUNUMBER tDAY {
sl@0
   251
            yyDayOrdinal = $1 * $2;
sl@0
   252
            yyDayNumber = $3;
sl@0
   253
        }
sl@0
   254
        | tNEXT tDAY {
sl@0
   255
            yyDayOrdinal = 2;
sl@0
   256
            yyDayNumber = $2;
sl@0
   257
        }
sl@0
   258
        ;
sl@0
   259
sl@0
   260
date    : tUNUMBER '/' tUNUMBER {
sl@0
   261
            yyMonth = $1;
sl@0
   262
            yyDay = $3;
sl@0
   263
        }
sl@0
   264
        | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
sl@0
   265
            yyMonth = $1;
sl@0
   266
            yyDay = $3;
sl@0
   267
            yyYear = $5;
sl@0
   268
        }
sl@0
   269
        | tISOBASE {
sl@0
   270
	    yyYear = $1 / 10000;
sl@0
   271
	    yyMonth = ($1 % 10000)/100;
sl@0
   272
	    yyDay = $1 % 100;
sl@0
   273
	}
sl@0
   274
        | tUNUMBER '-' tMONTH '-' tUNUMBER {
sl@0
   275
	    yyDay = $1;
sl@0
   276
	    yyMonth = $3;
sl@0
   277
	    yyYear = $5;
sl@0
   278
	}
sl@0
   279
        | tUNUMBER '-' tUNUMBER '-' tUNUMBER {
sl@0
   280
            yyMonth = $3;
sl@0
   281
            yyDay = $5;
sl@0
   282
            yyYear = $1;
sl@0
   283
        }
sl@0
   284
        | tMONTH tUNUMBER {
sl@0
   285
            yyMonth = $1;
sl@0
   286
            yyDay = $2;
sl@0
   287
        }
sl@0
   288
        | tMONTH tUNUMBER ',' tUNUMBER {
sl@0
   289
            yyMonth = $1;
sl@0
   290
            yyDay = $2;
sl@0
   291
            yyYear = $4;
sl@0
   292
        }
sl@0
   293
        | tUNUMBER tMONTH {
sl@0
   294
            yyMonth = $2;
sl@0
   295
            yyDay = $1;
sl@0
   296
        }
sl@0
   297
        | tEPOCH {
sl@0
   298
	    yyMonth = 1;
sl@0
   299
	    yyDay = 1;
sl@0
   300
	    yyYear = EPOCH;
sl@0
   301
	}
sl@0
   302
        | tUNUMBER tMONTH tUNUMBER {
sl@0
   303
            yyMonth = $2;
sl@0
   304
            yyDay = $1;
sl@0
   305
            yyYear = $3;
sl@0
   306
        }
sl@0
   307
        ;
sl@0
   308
sl@0
   309
ordMonth: tNEXT tMONTH {
sl@0
   310
	    yyMonthOrdinal = 1;
sl@0
   311
	    yyMonth = $2;
sl@0
   312
	}
sl@0
   313
        | tNEXT tUNUMBER tMONTH {
sl@0
   314
	    yyMonthOrdinal = $2;
sl@0
   315
	    yyMonth = $3;
sl@0
   316
	}
sl@0
   317
        ;
sl@0
   318
sl@0
   319
iso     : tISOBASE tZONE tISOBASE {
sl@0
   320
            if ($2 != HOUR(- 7)) YYABORT;
sl@0
   321
	    yyYear = $1 / 10000;
sl@0
   322
	    yyMonth = ($1 % 10000)/100;
sl@0
   323
	    yyDay = $1 % 100;
sl@0
   324
	    yyHour = $3 / 10000;
sl@0
   325
	    yyMinutes = ($3 % 10000)/100;
sl@0
   326
	    yySeconds = $3 % 100;
sl@0
   327
        }
sl@0
   328
        | tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER {
sl@0
   329
            if ($2 != HOUR(- 7)) YYABORT;
sl@0
   330
	    yyYear = $1 / 10000;
sl@0
   331
	    yyMonth = ($1 % 10000)/100;
sl@0
   332
	    yyDay = $1 % 100;
sl@0
   333
	    yyHour = $3;
sl@0
   334
	    yyMinutes = $5;
sl@0
   335
	    yySeconds = $7;
sl@0
   336
        }
sl@0
   337
	| tISOBASE tISOBASE {
sl@0
   338
	    yyYear = $1 / 10000;
sl@0
   339
	    yyMonth = ($1 % 10000)/100;
sl@0
   340
	    yyDay = $1 % 100;
sl@0
   341
	    yyHour = $2 / 10000;
sl@0
   342
	    yyMinutes = ($2 % 10000)/100;
sl@0
   343
	    yySeconds = $2 % 100;
sl@0
   344
        }
sl@0
   345
        ;
sl@0
   346
sl@0
   347
trek    : tSTARDATE tUNUMBER '.' tUNUMBER {
sl@0
   348
            /*
sl@0
   349
	     * Offset computed year by -377 so that the returned years will
sl@0
   350
	     * be in a range accessible with a 32 bit clock seconds value
sl@0
   351
	     */
sl@0
   352
            yyYear = $2/1000 + 2323 - 377;
sl@0
   353
            yyDay  = 1;
sl@0
   354
	    yyMonth = 1;
sl@0
   355
	    yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000;
sl@0
   356
	    yyRelSeconds += $4 * 144 * 60;
sl@0
   357
        }
sl@0
   358
        ;
sl@0
   359
sl@0
   360
relspec : relunits tAGO {
sl@0
   361
	    yyRelSeconds *= -1;
sl@0
   362
	    yyRelMonth *= -1;
sl@0
   363
	    yyRelDay *= -1;
sl@0
   364
	}
sl@0
   365
	| relunits
sl@0
   366
	;
sl@0
   367
relunits : sign tUNUMBER unit  { *yyRelPointer += $1 * $2 * $3; }
sl@0
   368
        | tUNUMBER unit        { *yyRelPointer += $1 * $2; }
sl@0
   369
        | tNEXT unit           { *yyRelPointer += $2; }
sl@0
   370
        | tNEXT tUNUMBER unit  { *yyRelPointer += $2 * $3; }
sl@0
   371
        | unit                 { *yyRelPointer += $1; }
sl@0
   372
        ;
sl@0
   373
sign    : '-'            { $$ = -1; }
sl@0
   374
        | '+'            { $$ =  1; }
sl@0
   375
        ;
sl@0
   376
unit    : tSEC_UNIT      { $$ = $1; yyRelPointer = &yyRelSeconds; }
sl@0
   377
        | tDAY_UNIT      { $$ = $1; yyRelPointer = &yyRelDay; }
sl@0
   378
        | tMONTH_UNIT    { $$ = $1; yyRelPointer = &yyRelMonth; }
sl@0
   379
        ;
sl@0
   380
sl@0
   381
number  : tUNUMBER
sl@0
   382
    {
sl@0
   383
	if (yyHaveTime && yyHaveDate && !yyHaveRel) {
sl@0
   384
	    yyYear = $1;
sl@0
   385
	} else {
sl@0
   386
	    yyHaveTime++;
sl@0
   387
	    if ($1 < 100) {
sl@0
   388
		yyHour = $1;
sl@0
   389
		yyMinutes = 0;
sl@0
   390
	    } else {
sl@0
   391
		yyHour = $1 / 100;
sl@0
   392
		yyMinutes = $1 % 100;
sl@0
   393
	    }
sl@0
   394
	    yySeconds = 0;
sl@0
   395
	    yyMeridian = MER24;
sl@0
   396
	}
sl@0
   397
    }
sl@0
   398
;
sl@0
   399
sl@0
   400
o_merid : /* NULL */ {
sl@0
   401
            $$ = MER24;
sl@0
   402
        }
sl@0
   403
        | tMERIDIAN {
sl@0
   404
            $$ = $1;
sl@0
   405
        }
sl@0
   406
        ;
sl@0
   407
sl@0
   408
%%
sl@0
   409
sl@0
   410
/*
sl@0
   411
 * Month and day table.
sl@0
   412
 */
sl@0
   413
static TABLE    MonthDayTable[] = {
sl@0
   414
    { "january",        tMONTH,  1 },
sl@0
   415
    { "february",       tMONTH,  2 },
sl@0
   416
    { "march",          tMONTH,  3 },
sl@0
   417
    { "april",          tMONTH,  4 },
sl@0
   418
    { "may",            tMONTH,  5 },
sl@0
   419
    { "june",           tMONTH,  6 },
sl@0
   420
    { "july",           tMONTH,  7 },
sl@0
   421
    { "august",         tMONTH,  8 },
sl@0
   422
    { "september",      tMONTH,  9 },
sl@0
   423
    { "sept",           tMONTH,  9 },
sl@0
   424
    { "october",        tMONTH, 10 },
sl@0
   425
    { "november",       tMONTH, 11 },
sl@0
   426
    { "december",       tMONTH, 12 },
sl@0
   427
    { "sunday",         tDAY, 0 },
sl@0
   428
    { "monday",         tDAY, 1 },
sl@0
   429
    { "tuesday",        tDAY, 2 },
sl@0
   430
    { "tues",           tDAY, 2 },
sl@0
   431
    { "wednesday",      tDAY, 3 },
sl@0
   432
    { "wednes",         tDAY, 3 },
sl@0
   433
    { "thursday",       tDAY, 4 },
sl@0
   434
    { "thur",           tDAY, 4 },
sl@0
   435
    { "thurs",          tDAY, 4 },
sl@0
   436
    { "friday",         tDAY, 5 },
sl@0
   437
    { "saturday",       tDAY, 6 },
sl@0
   438
    { NULL }
sl@0
   439
};
sl@0
   440
sl@0
   441
/*
sl@0
   442
 * Time units table.
sl@0
   443
 */
sl@0
   444
static TABLE    UnitsTable[] = {
sl@0
   445
    { "year",           tMONTH_UNIT,    12 },
sl@0
   446
    { "month",          tMONTH_UNIT,     1 },
sl@0
   447
    { "fortnight",      tDAY_UNIT,      14 },
sl@0
   448
    { "week",           tDAY_UNIT,       7 },
sl@0
   449
    { "day",            tDAY_UNIT,       1 },
sl@0
   450
    { "hour",           tSEC_UNIT, 60 * 60 },
sl@0
   451
    { "minute",         tSEC_UNIT,      60 },
sl@0
   452
    { "min",            tSEC_UNIT,      60 },
sl@0
   453
    { "second",         tSEC_UNIT,       1 },
sl@0
   454
    { "sec",            tSEC_UNIT,       1 },
sl@0
   455
    { NULL }
sl@0
   456
};
sl@0
   457
sl@0
   458
/*
sl@0
   459
 * Assorted relative-time words.
sl@0
   460
 */
sl@0
   461
static TABLE    OtherTable[] = {
sl@0
   462
    { "tomorrow",       tDAY_UNIT,      1 },
sl@0
   463
    { "yesterday",      tDAY_UNIT,     -1 },
sl@0
   464
    { "today",          tDAY_UNIT,      0 },
sl@0
   465
    { "now",            tSEC_UNIT,      0 },
sl@0
   466
    { "last",           tUNUMBER,      -1 },
sl@0
   467
    { "this",           tSEC_UNIT,      0 },
sl@0
   468
    { "next",           tNEXT,          1 },
sl@0
   469
#if 0
sl@0
   470
    { "first",          tUNUMBER,       1 },
sl@0
   471
    { "second",         tUNUMBER,       2 },
sl@0
   472
    { "third",          tUNUMBER,       3 },
sl@0
   473
    { "fourth",         tUNUMBER,       4 },
sl@0
   474
    { "fifth",          tUNUMBER,       5 },
sl@0
   475
    { "sixth",          tUNUMBER,       6 },
sl@0
   476
    { "seventh",        tUNUMBER,       7 },
sl@0
   477
    { "eighth",         tUNUMBER,       8 },
sl@0
   478
    { "ninth",          tUNUMBER,       9 },
sl@0
   479
    { "tenth",          tUNUMBER,       10 },
sl@0
   480
    { "eleventh",       tUNUMBER,       11 },
sl@0
   481
    { "twelfth",        tUNUMBER,       12 },
sl@0
   482
#endif
sl@0
   483
    { "ago",            tAGO,   1 },
sl@0
   484
    { "epoch",          tEPOCH,   0 },
sl@0
   485
    { "stardate",       tSTARDATE, 0},
sl@0
   486
    { NULL }
sl@0
   487
};
sl@0
   488
sl@0
   489
/*
sl@0
   490
 * The timezone table.  (Note: This table was modified to not use any floating
sl@0
   491
 * point constants to work around an SGI compiler bug).
sl@0
   492
 */
sl@0
   493
static TABLE    TimezoneTable[] = {
sl@0
   494
    { "gmt",    tZONE,     HOUR( 0) },      /* Greenwich Mean */
sl@0
   495
    { "ut",     tZONE,     HOUR( 0) },      /* Universal (Coordinated) */
sl@0
   496
    { "utc",    tZONE,     HOUR( 0) },
sl@0
   497
    { "uct",    tZONE,     HOUR( 0) },      /* Universal Coordinated Time */
sl@0
   498
    { "wet",    tZONE,     HOUR( 0) },      /* Western European */
sl@0
   499
    { "bst",    tDAYZONE,  HOUR( 0) },      /* British Summer */
sl@0
   500
    { "wat",    tZONE,     HOUR( 1) },      /* West Africa */
sl@0
   501
    { "at",     tZONE,     HOUR( 2) },      /* Azores */
sl@0
   502
#if     0
sl@0
   503
    /* For completeness.  BST is also British Summer, and GST is
sl@0
   504
     * also Guam Standard. */
sl@0
   505
    { "bst",    tZONE,     HOUR( 3) },      /* Brazil Standard */
sl@0
   506
    { "gst",    tZONE,     HOUR( 3) },      /* Greenland Standard */
sl@0
   507
#endif
sl@0
   508
    { "nft",    tZONE,     HOUR( 7/2) },    /* Newfoundland */
sl@0
   509
    { "nst",    tZONE,     HOUR( 7/2) },    /* Newfoundland Standard */
sl@0
   510
    { "ndt",    tDAYZONE,  HOUR( 7/2) },    /* Newfoundland Daylight */
sl@0
   511
    { "ast",    tZONE,     HOUR( 4) },      /* Atlantic Standard */
sl@0
   512
    { "adt",    tDAYZONE,  HOUR( 4) },      /* Atlantic Daylight */
sl@0
   513
    { "est",    tZONE,     HOUR( 5) },      /* Eastern Standard */
sl@0
   514
    { "edt",    tDAYZONE,  HOUR( 5) },      /* Eastern Daylight */
sl@0
   515
    { "cst",    tZONE,     HOUR( 6) },      /* Central Standard */
sl@0
   516
    { "cdt",    tDAYZONE,  HOUR( 6) },      /* Central Daylight */
sl@0
   517
    { "mst",    tZONE,     HOUR( 7) },      /* Mountain Standard */
sl@0
   518
    { "mdt",    tDAYZONE,  HOUR( 7) },      /* Mountain Daylight */
sl@0
   519
    { "pst",    tZONE,     HOUR( 8) },      /* Pacific Standard */
sl@0
   520
    { "pdt",    tDAYZONE,  HOUR( 8) },      /* Pacific Daylight */
sl@0
   521
    { "yst",    tZONE,     HOUR( 9) },      /* Yukon Standard */
sl@0
   522
    { "ydt",    tDAYZONE,  HOUR( 9) },      /* Yukon Daylight */
sl@0
   523
    { "hst",    tZONE,     HOUR(10) },      /* Hawaii Standard */
sl@0
   524
    { "hdt",    tDAYZONE,  HOUR(10) },      /* Hawaii Daylight */
sl@0
   525
    { "cat",    tZONE,     HOUR(10) },      /* Central Alaska */
sl@0
   526
    { "ahst",   tZONE,     HOUR(10) },      /* Alaska-Hawaii Standard */
sl@0
   527
    { "nt",     tZONE,     HOUR(11) },      /* Nome */
sl@0
   528
    { "idlw",   tZONE,     HOUR(12) },      /* International Date Line West */
sl@0
   529
    { "cet",    tZONE,    -HOUR( 1) },      /* Central European */
sl@0
   530
    { "cest",   tDAYZONE, -HOUR( 1) },      /* Central European Summer */
sl@0
   531
    { "met",    tZONE,    -HOUR( 1) },      /* Middle European */
sl@0
   532
    { "mewt",   tZONE,    -HOUR( 1) },      /* Middle European Winter */
sl@0
   533
    { "mest",   tDAYZONE, -HOUR( 1) },      /* Middle European Summer */
sl@0
   534
    { "swt",    tZONE,    -HOUR( 1) },      /* Swedish Winter */
sl@0
   535
    { "sst",    tDAYZONE, -HOUR( 1) },      /* Swedish Summer */
sl@0
   536
    { "fwt",    tZONE,    -HOUR( 1) },      /* French Winter */
sl@0
   537
    { "fst",    tDAYZONE, -HOUR( 1) },      /* French Summer */
sl@0
   538
    { "eet",    tZONE,    -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 */
sl@0
   539
    { "bt",     tZONE,    -HOUR( 3) },      /* Baghdad, USSR Zone 2 */
sl@0
   540
    { "it",     tZONE,    -HOUR( 7/2) },    /* Iran */
sl@0
   541
    { "zp4",    tZONE,    -HOUR( 4) },      /* USSR Zone 3 */
sl@0
   542
    { "zp5",    tZONE,    -HOUR( 5) },      /* USSR Zone 4 */
sl@0
   543
    { "ist",    tZONE,    -HOUR(11/2) },    /* Indian Standard */
sl@0
   544
    { "zp6",    tZONE,    -HOUR( 6) },      /* USSR Zone 5 */
sl@0
   545
#if     0
sl@0
   546
    /* For completeness.  NST is also Newfoundland Stanard, nad SST is
sl@0
   547
     * also Swedish Summer. */
sl@0
   548
    { "nst",    tZONE,    -HOUR(13/2) },    /* North Sumatra */
sl@0
   549
    { "sst",    tZONE,    -HOUR( 7) },      /* South Sumatra, USSR Zone 6 */
sl@0
   550
#endif  /* 0 */
sl@0
   551
    { "wast",   tZONE,    -HOUR( 7) },      /* West Australian Standard */
sl@0
   552
    { "wadt",   tDAYZONE, -HOUR( 7) },      /* West Australian Daylight */
sl@0
   553
    { "jt",     tZONE,    -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
sl@0
   554
    { "cct",    tZONE,    -HOUR( 8) },      /* China Coast, USSR Zone 7 */
sl@0
   555
    { "jst",    tZONE,    -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
sl@0
   556
    { "jdt",    tDAYZONE, -HOUR( 9) },      /* Japan Daylight */
sl@0
   557
    { "kst",    tZONE,    -HOUR( 9) },      /* Korea Standard */
sl@0
   558
    { "kdt",    tDAYZONE, -HOUR( 9) },      /* Korea Daylight */
sl@0
   559
    { "cast",   tZONE,    -HOUR(19/2) },    /* Central Australian Standard */
sl@0
   560
    { "cadt",   tDAYZONE, -HOUR(19/2) },    /* Central Australian Daylight */
sl@0
   561
    { "east",   tZONE,    -HOUR(10) },      /* Eastern Australian Standard */
sl@0
   562
    { "eadt",   tDAYZONE, -HOUR(10) },      /* Eastern Australian Daylight */
sl@0
   563
    { "gst",    tZONE,    -HOUR(10) },      /* Guam Standard, USSR Zone 9 */
sl@0
   564
    { "nzt",    tZONE,    -HOUR(12) },      /* New Zealand */
sl@0
   565
    { "nzst",   tZONE,    -HOUR(12) },      /* New Zealand Standard */
sl@0
   566
    { "nzdt",   tDAYZONE, -HOUR(12) },      /* New Zealand Daylight */
sl@0
   567
    { "idle",   tZONE,    -HOUR(12) },      /* International Date Line East */
sl@0
   568
    /* ADDED BY Marco Nijdam */
sl@0
   569
    { "dst",    tDST,     HOUR( 0) },       /* DST on (hour is ignored) */
sl@0
   570
    /* End ADDED */
sl@0
   571
    {  NULL  }
sl@0
   572
};
sl@0
   573
sl@0
   574
/*
sl@0
   575
 * Military timezone table.
sl@0
   576
 */
sl@0
   577
static TABLE    MilitaryTable[] = {
sl@0
   578
    { "a",      tZONE,  HOUR(  1) },
sl@0
   579
    { "b",      tZONE,  HOUR(  2) },
sl@0
   580
    { "c",      tZONE,  HOUR(  3) },
sl@0
   581
    { "d",      tZONE,  HOUR(  4) },
sl@0
   582
    { "e",      tZONE,  HOUR(  5) },
sl@0
   583
    { "f",      tZONE,  HOUR(  6) },
sl@0
   584
    { "g",      tZONE,  HOUR(  7) },
sl@0
   585
    { "h",      tZONE,  HOUR(  8) },
sl@0
   586
    { "i",      tZONE,  HOUR(  9) },
sl@0
   587
    { "k",      tZONE,  HOUR( 10) },
sl@0
   588
    { "l",      tZONE,  HOUR( 11) },
sl@0
   589
    { "m",      tZONE,  HOUR( 12) },
sl@0
   590
    { "n",      tZONE,  HOUR(- 1) },
sl@0
   591
    { "o",      tZONE,  HOUR(- 2) },
sl@0
   592
    { "p",      tZONE,  HOUR(- 3) },
sl@0
   593
    { "q",      tZONE,  HOUR(- 4) },
sl@0
   594
    { "r",      tZONE,  HOUR(- 5) },
sl@0
   595
    { "s",      tZONE,  HOUR(- 6) },
sl@0
   596
    { "t",      tZONE,  HOUR(- 7) },
sl@0
   597
    { "u",      tZONE,  HOUR(- 8) },
sl@0
   598
    { "v",      tZONE,  HOUR(- 9) },
sl@0
   599
    { "w",      tZONE,  HOUR(-10) },
sl@0
   600
    { "x",      tZONE,  HOUR(-11) },
sl@0
   601
    { "y",      tZONE,  HOUR(-12) },
sl@0
   602
    { "z",      tZONE,  HOUR(  0) },
sl@0
   603
    { NULL }
sl@0
   604
};
sl@0
   605
sl@0
   606
sl@0
   607
/*
sl@0
   608
 * Dump error messages in the bit bucket.
sl@0
   609
 */
sl@0
   610
static void
sl@0
   611
yyerror(s)
sl@0
   612
    char  *s;
sl@0
   613
{
sl@0
   614
}
sl@0
   615
sl@0
   616
sl@0
   617
static time_t
sl@0
   618
ToSeconds(Hours, Minutes, Seconds, Meridian)
sl@0
   619
    time_t      Hours;
sl@0
   620
    time_t      Minutes;
sl@0
   621
    time_t      Seconds;
sl@0
   622
    MERIDIAN    Meridian;
sl@0
   623
{
sl@0
   624
    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
sl@0
   625
        return -1;
sl@0
   626
    switch (Meridian) {
sl@0
   627
    case MER24:
sl@0
   628
        if (Hours < 0 || Hours > 23)
sl@0
   629
            return -1;
sl@0
   630
        return (Hours * 60L + Minutes) * 60L + Seconds;
sl@0
   631
    case MERam:
sl@0
   632
        if (Hours < 1 || Hours > 12)
sl@0
   633
            return -1;
sl@0
   634
        return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
sl@0
   635
    case MERpm:
sl@0
   636
        if (Hours < 1 || Hours > 12)
sl@0
   637
            return -1;
sl@0
   638
        return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
sl@0
   639
    }
sl@0
   640
    return -1;  /* Should never be reached */
sl@0
   641
}
sl@0
   642
sl@0
   643
/*
sl@0
   644
 *-----------------------------------------------------------------------------
sl@0
   645
 *
sl@0
   646
 * Convert --
sl@0
   647
 *
sl@0
   648
 *      Convert a {month, day, year, hours, minutes, seconds, meridian, dst}
sl@0
   649
 *      tuple into a clock seconds value.
sl@0
   650
 *
sl@0
   651
 * Results:
sl@0
   652
 *      0 or -1 indicating success or failure.
sl@0
   653
 *
sl@0
   654
 * Side effects:
sl@0
   655
 *      Fills TimePtr with the computed value.
sl@0
   656
 *
sl@0
   657
 *-----------------------------------------------------------------------------
sl@0
   658
 */
sl@0
   659
static int
sl@0
   660
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr)
sl@0
   661
    time_t      Month;
sl@0
   662
    time_t      Day;
sl@0
   663
    time_t      Year;
sl@0
   664
    time_t      Hours;
sl@0
   665
    time_t      Minutes;
sl@0
   666
    time_t      Seconds;
sl@0
   667
    MERIDIAN    Meridian;
sl@0
   668
    DSTMODE     DSTmode;
sl@0
   669
    time_t     *TimePtr;
sl@0
   670
{
sl@0
   671
    static int  DaysInMonth[12] = {
sl@0
   672
        31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
sl@0
   673
    };
sl@0
   674
    time_t tod;
sl@0
   675
    time_t Julian;
sl@0
   676
    int i;
sl@0
   677
sl@0
   678
    /* Figure out how many days are in February for the given year.
sl@0
   679
     * Every year divisible by 4 is a leap year.
sl@0
   680
     * But, every year divisible by 100 is not a leap year.
sl@0
   681
     * But, every year divisible by 400 is a leap year after all.
sl@0
   682
     */
sl@0
   683
    DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28;
sl@0
   684
sl@0
   685
    /* Check the inputs for validity */
sl@0
   686
    if (Month < 1 || Month > 12
sl@0
   687
	    || Year < START_OF_TIME || Year > END_OF_TIME
sl@0
   688
	    || Day < 1 || Day > DaysInMonth[(int)--Month])
sl@0
   689
        return -1;
sl@0
   690
sl@0
   691
    /* Start computing the value.  First determine the number of days
sl@0
   692
     * represented by the date, then multiply by the number of seconds/day.
sl@0
   693
     */
sl@0
   694
    for (Julian = Day - 1, i = 0; i < Month; i++)
sl@0
   695
        Julian += DaysInMonth[i];
sl@0
   696
    if (Year >= EPOCH) {
sl@0
   697
        for (i = EPOCH; i < Year; i++)
sl@0
   698
            Julian += 365 + IsLeapYear(i);
sl@0
   699
    } else {
sl@0
   700
        for (i = Year; i < EPOCH; i++)
sl@0
   701
            Julian -= 365 + IsLeapYear(i);
sl@0
   702
    }
sl@0
   703
    Julian *= SECSPERDAY;
sl@0
   704
sl@0
   705
    /* Add the timezone offset ?? */
sl@0
   706
    Julian += yyTimezone * 60L;
sl@0
   707
sl@0
   708
    /* Add the number of seconds represented by the time component */
sl@0
   709
    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
sl@0
   710
        return -1;
sl@0
   711
    Julian += tod;
sl@0
   712
sl@0
   713
    /* Perform a preliminary DST compensation ?? */
sl@0
   714
    if (DSTmode == DSTon
sl@0
   715
     || (DSTmode == DSTmaybe && TclpGetDate((TclpTime_t)&Julian, 0)->tm_isdst))
sl@0
   716
        Julian -= 60 * 60;
sl@0
   717
    *TimePtr = Julian;
sl@0
   718
    return 0;
sl@0
   719
}
sl@0
   720
sl@0
   721
sl@0
   722
static time_t
sl@0
   723
DSTcorrect(Start, Future)
sl@0
   724
    time_t      Start;
sl@0
   725
    time_t      Future;
sl@0
   726
{
sl@0
   727
    time_t      StartDay;
sl@0
   728
    time_t      FutureDay;
sl@0
   729
    StartDay = (TclpGetDate((TclpTime_t)&Start, 0)->tm_hour + 1) % 24;
sl@0
   730
    FutureDay = (TclpGetDate((TclpTime_t)&Future, 0)->tm_hour + 1) % 24;
sl@0
   731
    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
sl@0
   732
}
sl@0
   733
sl@0
   734
sl@0
   735
static time_t
sl@0
   736
NamedDay(Start, DayOrdinal, DayNumber)
sl@0
   737
    time_t      Start;
sl@0
   738
    time_t      DayOrdinal;
sl@0
   739
    time_t      DayNumber;
sl@0
   740
{
sl@0
   741
    struct tm   *tm;
sl@0
   742
    time_t      now;
sl@0
   743
sl@0
   744
    now = Start;
sl@0
   745
    tm = TclpGetDate((TclpTime_t)&now, 0);
sl@0
   746
    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
sl@0
   747
    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
sl@0
   748
    return DSTcorrect(Start, now);
sl@0
   749
}
sl@0
   750
sl@0
   751
static time_t
sl@0
   752
NamedMonth(Start, MonthOrdinal, MonthNumber)
sl@0
   753
    time_t Start;
sl@0
   754
    time_t MonthOrdinal;
sl@0
   755
    time_t MonthNumber;
sl@0
   756
{
sl@0
   757
    struct tm *tm;
sl@0
   758
    time_t now;
sl@0
   759
    int result;
sl@0
   760
    
sl@0
   761
    now = Start;
sl@0
   762
    tm = TclpGetDate((TclpTime_t)&now, 0);
sl@0
   763
    /* To compute the next n'th month, we use this alg:
sl@0
   764
     * add n to year value
sl@0
   765
     * if currentMonth < requestedMonth decrement year value by 1 (so that
sl@0
   766
     *  doing next february from january gives us february of the current year)
sl@0
   767
     * set day to 1, time to 0
sl@0
   768
     */
sl@0
   769
    tm->tm_year += MonthOrdinal;
sl@0
   770
    if (tm->tm_mon < MonthNumber - 1) {
sl@0
   771
	tm->tm_year--;
sl@0
   772
    }
sl@0
   773
    result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE,
sl@0
   774
	    (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now);
sl@0
   775
    if (result < 0) {
sl@0
   776
	return 0;
sl@0
   777
    }
sl@0
   778
    return DSTcorrect(Start, now);
sl@0
   779
}
sl@0
   780
sl@0
   781
static int
sl@0
   782
RelativeMonth(Start, RelMonth, TimePtr)
sl@0
   783
    time_t Start;
sl@0
   784
    time_t RelMonth;
sl@0
   785
    time_t *TimePtr;
sl@0
   786
{
sl@0
   787
    struct tm *tm;
sl@0
   788
    time_t Month;
sl@0
   789
    time_t Year;
sl@0
   790
    time_t Julian;
sl@0
   791
    int result;
sl@0
   792
sl@0
   793
    if (RelMonth == 0) {
sl@0
   794
        *TimePtr = 0;
sl@0
   795
        return 0;
sl@0
   796
    }
sl@0
   797
    tm = TclpGetDate((TclpTime_t)&Start, 0);
sl@0
   798
    Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth;
sl@0
   799
    Year = Month / 12;
sl@0
   800
    Month = Month % 12 + 1;
sl@0
   801
    result = Convert(Month, (time_t) tm->tm_mday, Year,
sl@0
   802
	    (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
sl@0
   803
	    MER24, DSTmaybe, &Julian);
sl@0
   804
sl@0
   805
    /*
sl@0
   806
     * The Julian time returned above is behind by one day, if "month" 
sl@0
   807
     * or "year" is used to specify relative time and the GMT flag is true.
sl@0
   808
     * This problem occurs only when the current time is closer to
sl@0
   809
     * midnight, the difference being not more than its time difference
sl@0
   810
     * with GMT. For example, in US/Pacific time zone, the problem occurs
sl@0
   811
     * whenever the current time is between midnight to 8:00am or 7:00amDST.
sl@0
   812
     * See Bug# 413397 for more details and sample script.
sl@0
   813
     * To resolve this bug, we simply add the number of seconds corresponding
sl@0
   814
     * to timezone difference with GMT to Julian time, if GMT flag is true.
sl@0
   815
     */
sl@0
   816
sl@0
   817
    if (TclDateTimezone == 0) {
sl@0
   818
        Julian += TclpGetTimeZone((unsigned long) Start) * 60L;
sl@0
   819
    }
sl@0
   820
sl@0
   821
    /*
sl@0
   822
     * The following iteration takes into account the case were we jump
sl@0
   823
     * into a "short month".  Far example, "one month from Jan 31" will
sl@0
   824
     * fail because there is no Feb 31.  The code below will reduce the
sl@0
   825
     * day and try converting the date until we succed or the date equals
sl@0
   826
     * 28 (which always works unless the date is bad in another way).
sl@0
   827
     */
sl@0
   828
sl@0
   829
    while ((result != 0) && (tm->tm_mday > 28)) {
sl@0
   830
	tm->tm_mday--;
sl@0
   831
	result = Convert(Month, (time_t) tm->tm_mday, Year,
sl@0
   832
		(time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
sl@0
   833
		MER24, DSTmaybe, &Julian);
sl@0
   834
    }
sl@0
   835
    if (result != 0) {
sl@0
   836
	return -1;
sl@0
   837
    }
sl@0
   838
    *TimePtr = DSTcorrect(Start, Julian);
sl@0
   839
    return 0;
sl@0
   840
}
sl@0
   841
sl@0
   842
sl@0
   843
/*
sl@0
   844
 *-----------------------------------------------------------------------------
sl@0
   845
 *
sl@0
   846
 * RelativeDay --
sl@0
   847
 *
sl@0
   848
 *      Given a starting time and a number of days before or after, compute the
sl@0
   849
 *      DST corrected difference between those dates.
sl@0
   850
 *
sl@0
   851
 * Results:
sl@0
   852
 *     1 or -1 indicating success or failure.
sl@0
   853
 *
sl@0
   854
 * Side effects:
sl@0
   855
 *      Fills TimePtr with the computed value.
sl@0
   856
 *
sl@0
   857
 *-----------------------------------------------------------------------------
sl@0
   858
 */
sl@0
   859
sl@0
   860
static int
sl@0
   861
RelativeDay(Start, RelDay, TimePtr)
sl@0
   862
    time_t Start;
sl@0
   863
    time_t RelDay;
sl@0
   864
    time_t *TimePtr;
sl@0
   865
{
sl@0
   866
    time_t new;
sl@0
   867
sl@0
   868
    new = Start + (RelDay * 60 * 60 * 24);
sl@0
   869
    *TimePtr = DSTcorrect(Start, new);
sl@0
   870
    return 1;
sl@0
   871
}
sl@0
   872
sl@0
   873
static int
sl@0
   874
LookupWord(buff)
sl@0
   875
    char                *buff;
sl@0
   876
{
sl@0
   877
    register char *p;
sl@0
   878
    register char *q;
sl@0
   879
    register TABLE *tp;
sl@0
   880
    int i;
sl@0
   881
    int abbrev;
sl@0
   882
sl@0
   883
    /*
sl@0
   884
     * Make it lowercase.
sl@0
   885
     */
sl@0
   886
sl@0
   887
    Tcl_UtfToLower(buff);
sl@0
   888
sl@0
   889
    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
sl@0
   890
        yylval.Meridian = MERam;
sl@0
   891
        return tMERIDIAN;
sl@0
   892
    }
sl@0
   893
    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
sl@0
   894
        yylval.Meridian = MERpm;
sl@0
   895
        return tMERIDIAN;
sl@0
   896
    }
sl@0
   897
sl@0
   898
    /*
sl@0
   899
     * See if we have an abbreviation for a month.
sl@0
   900
     */
sl@0
   901
    if (strlen(buff) == 3) {
sl@0
   902
        abbrev = 1;
sl@0
   903
    } else if (strlen(buff) == 4 && buff[3] == '.') {
sl@0
   904
        abbrev = 1;
sl@0
   905
        buff[3] = '\0';
sl@0
   906
    } else {
sl@0
   907
        abbrev = 0;
sl@0
   908
    }
sl@0
   909
sl@0
   910
    for (tp = MonthDayTable; tp->name; tp++) {
sl@0
   911
        if (abbrev) {
sl@0
   912
            if (strncmp(buff, tp->name, 3) == 0) {
sl@0
   913
                yylval.Number = tp->value;
sl@0
   914
                return tp->type;
sl@0
   915
            }
sl@0
   916
        } else if (strcmp(buff, tp->name) == 0) {
sl@0
   917
            yylval.Number = tp->value;
sl@0
   918
            return tp->type;
sl@0
   919
        }
sl@0
   920
    }
sl@0
   921
sl@0
   922
    for (tp = TimezoneTable; tp->name; tp++) {
sl@0
   923
        if (strcmp(buff, tp->name) == 0) {
sl@0
   924
            yylval.Number = tp->value;
sl@0
   925
            return tp->type;
sl@0
   926
        }
sl@0
   927
    }
sl@0
   928
sl@0
   929
    for (tp = UnitsTable; tp->name; tp++) {
sl@0
   930
        if (strcmp(buff, tp->name) == 0) {
sl@0
   931
            yylval.Number = tp->value;
sl@0
   932
            return tp->type;
sl@0
   933
        }
sl@0
   934
    }
sl@0
   935
sl@0
   936
    /*
sl@0
   937
     * Strip off any plural and try the units table again.
sl@0
   938
     */
sl@0
   939
    i = strlen(buff) - 1;
sl@0
   940
    if (buff[i] == 's') {
sl@0
   941
        buff[i] = '\0';
sl@0
   942
        for (tp = UnitsTable; tp->name; tp++) {
sl@0
   943
            if (strcmp(buff, tp->name) == 0) {
sl@0
   944
                yylval.Number = tp->value;
sl@0
   945
                return tp->type;
sl@0
   946
            }
sl@0
   947
	}
sl@0
   948
    }
sl@0
   949
sl@0
   950
    for (tp = OtherTable; tp->name; tp++) {
sl@0
   951
        if (strcmp(buff, tp->name) == 0) {
sl@0
   952
            yylval.Number = tp->value;
sl@0
   953
            return tp->type;
sl@0
   954
        }
sl@0
   955
    }
sl@0
   956
sl@0
   957
    /*
sl@0
   958
     * Military timezones.
sl@0
   959
     */
sl@0
   960
    if (buff[1] == '\0' && !(*buff & 0x80)
sl@0
   961
	    && isalpha(UCHAR(*buff))) {	/* INTL: ISO only */
sl@0
   962
        for (tp = MilitaryTable; tp->name; tp++) {
sl@0
   963
            if (strcmp(buff, tp->name) == 0) {
sl@0
   964
                yylval.Number = tp->value;
sl@0
   965
                return tp->type;
sl@0
   966
            }
sl@0
   967
	}
sl@0
   968
    }
sl@0
   969
sl@0
   970
    /*
sl@0
   971
     * Drop out any periods and try the timezone table again.
sl@0
   972
     */
sl@0
   973
    for (i = 0, p = q = buff; *q; q++)
sl@0
   974
        if (*q != '.') {
sl@0
   975
            *p++ = *q;
sl@0
   976
        } else {
sl@0
   977
            i++;
sl@0
   978
	}
sl@0
   979
    *p = '\0';
sl@0
   980
    if (i) {
sl@0
   981
        for (tp = TimezoneTable; tp->name; tp++) {
sl@0
   982
            if (strcmp(buff, tp->name) == 0) {
sl@0
   983
                yylval.Number = tp->value;
sl@0
   984
                return tp->type;
sl@0
   985
            }
sl@0
   986
	}
sl@0
   987
    }
sl@0
   988
    
sl@0
   989
    return tID;
sl@0
   990
}
sl@0
   991
sl@0
   992
sl@0
   993
static int
sl@0
   994
yylex()
sl@0
   995
{
sl@0
   996
    register char       c;
sl@0
   997
    register char       *p;
sl@0
   998
    char                buff[20];
sl@0
   999
    int                 Count;
sl@0
  1000
sl@0
  1001
    for ( ; ; ) {
sl@0
  1002
        while (isspace(UCHAR(*yyInput))) {
sl@0
  1003
            yyInput++;
sl@0
  1004
	}
sl@0
  1005
sl@0
  1006
        if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */
sl@0
  1007
	    /* convert the string into a number; count the number of digits */
sl@0
  1008
	    Count = 0;
sl@0
  1009
            for (yylval.Number = 0;
sl@0
  1010
		    isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */
sl@0
  1011
                yylval.Number = 10 * yylval.Number + c - '0';
sl@0
  1012
		Count++;
sl@0
  1013
	    }
sl@0
  1014
            yyInput--;
sl@0
  1015
	    /* A number with 6 or more digits is considered an ISO 8601 base */
sl@0
  1016
	    if (Count >= 6) {
sl@0
  1017
		return tISOBASE;
sl@0
  1018
	    } else {
sl@0
  1019
		return tUNUMBER;
sl@0
  1020
	    }
sl@0
  1021
        }
sl@0
  1022
        if (!(c & 0x80) && isalpha(UCHAR(c))) {	/* INTL: ISO only. */
sl@0
  1023
            for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */
sl@0
  1024
		     || c == '.'; ) {
sl@0
  1025
                if (p < &buff[sizeof buff - 1]) {
sl@0
  1026
                    *p++ = c;
sl@0
  1027
		}
sl@0
  1028
	    }
sl@0
  1029
            *p = '\0';
sl@0
  1030
            yyInput--;
sl@0
  1031
            return LookupWord(buff);
sl@0
  1032
        }
sl@0
  1033
        if (c != '(') {
sl@0
  1034
            return *yyInput++;
sl@0
  1035
	}
sl@0
  1036
        Count = 0;
sl@0
  1037
        do {
sl@0
  1038
            c = *yyInput++;
sl@0
  1039
            if (c == '\0') {
sl@0
  1040
                return c;
sl@0
  1041
	    } else if (c == '(') {
sl@0
  1042
                Count++;
sl@0
  1043
	    } else if (c == ')') {
sl@0
  1044
                Count--;
sl@0
  1045
	    }
sl@0
  1046
        } while (Count > 0);
sl@0
  1047
    }
sl@0
  1048
}
sl@0
  1049
sl@0
  1050
/*
sl@0
  1051
 * Specify zone is of -50000 to force GMT.  (This allows BST to work).
sl@0
  1052
 */
sl@0
  1053
sl@0
  1054
int
sl@0
  1055
TclGetDate(p, now, zone, timePtr)
sl@0
  1056
    char *p;
sl@0
  1057
    Tcl_WideInt now;
sl@0
  1058
    long zone;
sl@0
  1059
    Tcl_WideInt *timePtr;
sl@0
  1060
{
sl@0
  1061
    struct tm *tm;
sl@0
  1062
    time_t Start;
sl@0
  1063
    time_t Time;
sl@0
  1064
    time_t tod;
sl@0
  1065
    int thisyear;
sl@0
  1066
sl@0
  1067
    yyInput = p;
sl@0
  1068
    /* now has to be cast to a time_t for 64bit compliance */
sl@0
  1069
    Start = (time_t) now;
sl@0
  1070
    tm = TclpGetDate((TclpTime_t) &Start, (zone == -50000));
sl@0
  1071
    thisyear = tm->tm_year + TM_YEAR_BASE;
sl@0
  1072
    yyYear = thisyear;
sl@0
  1073
    yyMonth = tm->tm_mon + 1;
sl@0
  1074
    yyDay = tm->tm_mday;
sl@0
  1075
    yyTimezone = zone;
sl@0
  1076
    if (zone == -50000) {
sl@0
  1077
        yyDSTmode = DSToff;  /* assume GMT */
sl@0
  1078
        yyTimezone = 0;
sl@0
  1079
    } else {
sl@0
  1080
        yyDSTmode = DSTmaybe;
sl@0
  1081
    }
sl@0
  1082
    yyHour = 0;
sl@0
  1083
    yyMinutes = 0;
sl@0
  1084
    yySeconds = 0;
sl@0
  1085
    yyMeridian = MER24;
sl@0
  1086
    yyRelSeconds = 0;
sl@0
  1087
    yyRelMonth = 0;
sl@0
  1088
    yyRelDay = 0;
sl@0
  1089
    yyRelPointer = NULL;
sl@0
  1090
sl@0
  1091
    yyHaveDate = 0;
sl@0
  1092
    yyHaveDay = 0;
sl@0
  1093
    yyHaveOrdinalMonth = 0;
sl@0
  1094
    yyHaveRel = 0;
sl@0
  1095
    yyHaveTime = 0;
sl@0
  1096
    yyHaveZone = 0;
sl@0
  1097
sl@0
  1098
    if (yyparse() || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 ||
sl@0
  1099
	    yyHaveDay > 1 || yyHaveOrdinalMonth > 1) {
sl@0
  1100
        return -1;
sl@0
  1101
    }
sl@0
  1102
    
sl@0
  1103
    if (yyHaveDate || yyHaveTime || yyHaveDay) {
sl@0
  1104
	if (TclDateYear < 0) {
sl@0
  1105
	    TclDateYear = -TclDateYear;
sl@0
  1106
	}
sl@0
  1107
	/*
sl@0
  1108
	 * The following line handles years that are specified using
sl@0
  1109
	 * only two digits.  The line of code below implements a policy
sl@0
  1110
	 * defined by the X/Open workgroup on the millinium rollover.
sl@0
  1111
	 * Note: some of those dates may not actually be valid on some
sl@0
  1112
	 * platforms.  The POSIX standard startes that the dates 70-99
sl@0
  1113
	 * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038.
sl@0
  1114
	 * This later definition should work on all platforms.
sl@0
  1115
	 */
sl@0
  1116
sl@0
  1117
	if (TclDateYear < 100) {
sl@0
  1118
	    if (TclDateYear >= 69) {
sl@0
  1119
		TclDateYear += 1900;
sl@0
  1120
	    } else {
sl@0
  1121
		TclDateYear += 2000;
sl@0
  1122
	    }
sl@0
  1123
	}
sl@0
  1124
	if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
sl@0
  1125
		yyMeridian, yyDSTmode, &Start) < 0) {
sl@0
  1126
            return -1;
sl@0
  1127
	}
sl@0
  1128
    } else {
sl@0
  1129
        Start = (time_t) now;
sl@0
  1130
        if (!yyHaveRel) {
sl@0
  1131
            Start -= ((tm->tm_hour * 60L * 60L) +
sl@0
  1132
		    tm->tm_min * 60L) +	tm->tm_sec;
sl@0
  1133
	}
sl@0
  1134
    }
sl@0
  1135
sl@0
  1136
    Start += yyRelSeconds;
sl@0
  1137
    if (RelativeMonth(Start, yyRelMonth, &Time) < 0) {
sl@0
  1138
        return -1;
sl@0
  1139
    }
sl@0
  1140
    Start += Time;
sl@0
  1141
sl@0
  1142
    if (RelativeDay(Start, yyRelDay, &Time) < 0) {
sl@0
  1143
	return -1;
sl@0
  1144
    }
sl@0
  1145
    Start += Time;
sl@0
  1146
    
sl@0
  1147
    if (yyHaveDay && !yyHaveDate) {
sl@0
  1148
        tod = NamedDay(Start, yyDayOrdinal, yyDayNumber);
sl@0
  1149
        Start += tod;
sl@0
  1150
    }
sl@0
  1151
sl@0
  1152
    if (yyHaveOrdinalMonth) {
sl@0
  1153
	tod = NamedMonth(Start, yyMonthOrdinal, yyMonth);
sl@0
  1154
	Start += tod;
sl@0
  1155
    }
sl@0
  1156
    
sl@0
  1157
    *timePtr = Start;
sl@0
  1158
    return 0;
sl@0
  1159
}