1131 lines
28 KiB
Plaintext
1131 lines
28 KiB
Plaintext
/*
|
||
* tclGetDate.y --
|
||
*
|
||
* Contains yacc grammar for parsing date and time strings. The output of
|
||
* this file should be the file tclDate.c which is used directly in the
|
||
* Tcl sources. Note that this file is largely obsolete in Tcl 8.5; it is
|
||
* only used when doing free-form date parsing, an ill-defined process
|
||
* anyway.
|
||
*
|
||
* Copyright (c) 1992-1995 Karl Lehenbauer & Mark Diekhans.
|
||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution of
|
||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*/
|
||
|
||
%parse-param {DateInfo* info}
|
||
%lex-param {DateInfo* info}
|
||
%define api.pure
|
||
/* %error-verbose would be nice, but our token names are meaningless */
|
||
%locations
|
||
|
||
%{
|
||
/*
|
||
* tclDate.c --
|
||
*
|
||
* This file is generated from a yacc grammar defined in the file
|
||
* tclGetDate.y. It should not be edited directly.
|
||
*
|
||
* Copyright (c) 1992-1995 Karl Lehenbauer & Mark Diekhans.
|
||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution of
|
||
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*
|
||
*/
|
||
#include "tclInt.h"
|
||
|
||
/*
|
||
* Bison generates several labels that happen to be unused. MS Visual C++
|
||
* doesn't like that, and complains. Tell it to shut up.
|
||
*/
|
||
|
||
#ifdef _MSC_VER
|
||
#pragma warning( disable : 4102 )
|
||
#endif /* _MSC_VER */
|
||
|
||
/*
|
||
* Meridian: am, pm, or 24-hour style.
|
||
*/
|
||
|
||
typedef enum _MERIDIAN {
|
||
MERam, MERpm, MER24
|
||
} MERIDIAN;
|
||
|
||
/*
|
||
* yyparse will accept a 'struct DateInfo' as its parameter; that's where the
|
||
* parsed fields will be returned.
|
||
*/
|
||
|
||
typedef struct DateInfo {
|
||
|
||
Tcl_Obj* messages; /* Error messages */
|
||
const char* separatrix; /* String separating messages */
|
||
|
||
time_t dateYear;
|
||
time_t dateMonth;
|
||
time_t dateDay;
|
||
int dateHaveDate;
|
||
|
||
time_t dateHour;
|
||
time_t dateMinutes;
|
||
time_t dateSeconds;
|
||
MERIDIAN dateMeridian;
|
||
int dateHaveTime;
|
||
|
||
time_t dateTimezone;
|
||
int dateDSTmode;
|
||
int dateHaveZone;
|
||
|
||
time_t dateRelMonth;
|
||
time_t dateRelDay;
|
||
time_t dateRelSeconds;
|
||
int dateHaveRel;
|
||
|
||
time_t dateMonthOrdinal;
|
||
int dateHaveOrdinalMonth;
|
||
|
||
time_t dateDayOrdinal;
|
||
time_t dateDayNumber;
|
||
int dateHaveDay;
|
||
|
||
const char *dateStart;
|
||
const char *dateInput;
|
||
time_t *dateRelPointer;
|
||
|
||
int dateDigitCount;
|
||
} DateInfo;
|
||
|
||
#define YYMALLOC ckalloc
|
||
#define YYFREE(x) (ckfree((void*) (x)))
|
||
|
||
#define yyDSTmode (info->dateDSTmode)
|
||
#define yyDayOrdinal (info->dateDayOrdinal)
|
||
#define yyDayNumber (info->dateDayNumber)
|
||
#define yyMonthOrdinal (info->dateMonthOrdinal)
|
||
#define yyHaveDate (info->dateHaveDate)
|
||
#define yyHaveDay (info->dateHaveDay)
|
||
#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth)
|
||
#define yyHaveRel (info->dateHaveRel)
|
||
#define yyHaveTime (info->dateHaveTime)
|
||
#define yyHaveZone (info->dateHaveZone)
|
||
#define yyTimezone (info->dateTimezone)
|
||
#define yyDay (info->dateDay)
|
||
#define yyMonth (info->dateMonth)
|
||
#define yyYear (info->dateYear)
|
||
#define yyHour (info->dateHour)
|
||
#define yyMinutes (info->dateMinutes)
|
||
#define yySeconds (info->dateSeconds)
|
||
#define yyMeridian (info->dateMeridian)
|
||
#define yyRelMonth (info->dateRelMonth)
|
||
#define yyRelDay (info->dateRelDay)
|
||
#define yyRelSeconds (info->dateRelSeconds)
|
||
#define yyRelPointer (info->dateRelPointer)
|
||
#define yyInput (info->dateInput)
|
||
#define yyDigitCount (info->dateDigitCount)
|
||
|
||
#define EPOCH 1970
|
||
#define START_OF_TIME 1902
|
||
#define END_OF_TIME 2037
|
||
|
||
/*
|
||
* The offset of tm_year of struct tm returned by localtime, gmtime, etc.
|
||
* Posix requires 1900.
|
||
*/
|
||
|
||
#define TM_YEAR_BASE 1900
|
||
|
||
#define HOUR(x) ((int) (60 * x))
|
||
#define SECSPERDAY (24L * 60L * 60L)
|
||
#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
|
||
|
||
/*
|
||
* An entry in the lexical lookup table.
|
||
*/
|
||
|
||
typedef struct _TABLE {
|
||
const char *name;
|
||
int type;
|
||
time_t value;
|
||
} TABLE;
|
||
|
||
/*
|
||
* Daylight-savings mode: on, off, or not yet known.
|
||
*/
|
||
|
||
typedef enum _DSTMODE {
|
||
DSTon, DSToff, DSTmaybe
|
||
} DSTMODE;
|
||
|
||
%}
|
||
|
||
%union {
|
||
time_t Number;
|
||
enum _MERIDIAN Meridian;
|
||
}
|
||
|
||
%{
|
||
|
||
/*
|
||
* Prototypes of internal functions.
|
||
*/
|
||
|
||
static int LookupWord(YYSTYPE* yylvalPtr, char *buff);
|
||
static void TclDateerror(YYLTYPE* location,
|
||
DateInfo* info, const char *s);
|
||
static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location,
|
||
DateInfo* info);
|
||
static time_t ToSeconds(time_t Hours, time_t Minutes,
|
||
time_t Seconds, MERIDIAN Meridian);
|
||
MODULE_SCOPE int yyparse(DateInfo*);
|
||
|
||
%}
|
||
|
||
%token tAGO
|
||
%token tDAY
|
||
%token tDAYZONE
|
||
%token tID
|
||
%token tMERIDIAN
|
||
%token tMONTH
|
||
%token tMONTH_UNIT
|
||
%token tSTARDATE
|
||
%token tSEC_UNIT
|
||
%token tSNUMBER
|
||
%token tUNUMBER
|
||
%token tZONE
|
||
%token tEPOCH
|
||
%token tDST
|
||
%token tISOBASE
|
||
%token tDAY_UNIT
|
||
%token tNEXT
|
||
|
||
%type <Number> tDAY
|
||
%type <Number> tDAYZONE
|
||
%type <Number> tMONTH
|
||
%type <Number> tMONTH_UNIT
|
||
%type <Number> tDST
|
||
%type <Number> tSEC_UNIT
|
||
%type <Number> tSNUMBER
|
||
%type <Number> tUNUMBER
|
||
%type <Number> tZONE
|
||
%type <Number> tISOBASE
|
||
%type <Number> tDAY_UNIT
|
||
%type <Number> unit
|
||
%type <Number> sign
|
||
%type <Number> tNEXT
|
||
%type <Number> tSTARDATE
|
||
%type <Meridian> tMERIDIAN
|
||
%type <Meridian> o_merid
|
||
|
||
%%
|
||
|
||
spec : /* NULL */
|
||
| spec item
|
||
;
|
||
|
||
item : time {
|
||
yyHaveTime++;
|
||
}
|
||
| zone {
|
||
yyHaveZone++;
|
||
}
|
||
| date {
|
||
yyHaveDate++;
|
||
}
|
||
| ordMonth {
|
||
yyHaveOrdinalMonth++;
|
||
}
|
||
| day {
|
||
yyHaveDay++;
|
||
}
|
||
| relspec {
|
||
yyHaveRel++;
|
||
}
|
||
| iso {
|
||
yyHaveTime++;
|
||
yyHaveDate++;
|
||
}
|
||
| trek {
|
||
yyHaveTime++;
|
||
yyHaveDate++;
|
||
yyHaveRel++;
|
||
}
|
||
| number
|
||
;
|
||
|
||
time : tUNUMBER tMERIDIAN {
|
||
yyHour = $1;
|
||
yyMinutes = 0;
|
||
yySeconds = 0;
|
||
yyMeridian = $2;
|
||
}
|
||
| tUNUMBER ':' tUNUMBER o_merid {
|
||
yyHour = $1;
|
||
yyMinutes = $3;
|
||
yySeconds = 0;
|
||
yyMeridian = $4;
|
||
}
|
||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
|
||
yyHour = $1;
|
||
yyMinutes = $3;
|
||
yySeconds = $5;
|
||
yyMeridian = $6;
|
||
}
|
||
;
|
||
|
||
zone : tZONE tDST {
|
||
yyTimezone = $1;
|
||
if (yyTimezone > HOUR( 12)) yyTimezone -= HOUR(100);
|
||
yyDSTmode = DSTon;
|
||
}
|
||
| tZONE {
|
||
yyTimezone = $1;
|
||
if (yyTimezone > HOUR( 12)) yyTimezone -= HOUR(100);
|
||
yyDSTmode = DSToff;
|
||
}
|
||
| tDAYZONE {
|
||
yyTimezone = $1;
|
||
yyDSTmode = DSTon;
|
||
}
|
||
| sign tUNUMBER {
|
||
yyTimezone = -$1*($2 % 100 + ($2 / 100) * 60);
|
||
yyDSTmode = DSToff;
|
||
}
|
||
;
|
||
|
||
day : tDAY {
|
||
yyDayOrdinal = 1;
|
||
yyDayNumber = $1;
|
||
}
|
||
| tDAY ',' {
|
||
yyDayOrdinal = 1;
|
||
yyDayNumber = $1;
|
||
}
|
||
| tUNUMBER tDAY {
|
||
yyDayOrdinal = $1;
|
||
yyDayNumber = $2;
|
||
}
|
||
| sign tUNUMBER tDAY {
|
||
yyDayOrdinal = $1 * $2;
|
||
yyDayNumber = $3;
|
||
}
|
||
| tNEXT tDAY {
|
||
yyDayOrdinal = 2;
|
||
yyDayNumber = $2;
|
||
}
|
||
;
|
||
|
||
date : tUNUMBER '/' tUNUMBER {
|
||
yyMonth = $1;
|
||
yyDay = $3;
|
||
}
|
||
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
|
||
yyMonth = $1;
|
||
yyDay = $3;
|
||
yyYear = $5;
|
||
}
|
||
| tISOBASE {
|
||
yyYear = $1 / 10000;
|
||
yyMonth = ($1 % 10000)/100;
|
||
yyDay = $1 % 100;
|
||
}
|
||
| tUNUMBER '-' tMONTH '-' tUNUMBER {
|
||
yyDay = $1;
|
||
yyMonth = $3;
|
||
yyYear = $5;
|
||
}
|
||
| tUNUMBER '-' tUNUMBER '-' tUNUMBER {
|
||
yyMonth = $3;
|
||
yyDay = $5;
|
||
yyYear = $1;
|
||
}
|
||
| tMONTH tUNUMBER {
|
||
yyMonth = $1;
|
||
yyDay = $2;
|
||
}
|
||
| tMONTH tUNUMBER ',' tUNUMBER {
|
||
yyMonth = $1;
|
||
yyDay = $2;
|
||
yyYear = $4;
|
||
}
|
||
| tUNUMBER tMONTH {
|
||
yyMonth = $2;
|
||
yyDay = $1;
|
||
}
|
||
| tEPOCH {
|
||
yyMonth = 1;
|
||
yyDay = 1;
|
||
yyYear = EPOCH;
|
||
}
|
||
| tUNUMBER tMONTH tUNUMBER {
|
||
yyMonth = $2;
|
||
yyDay = $1;
|
||
yyYear = $3;
|
||
}
|
||
;
|
||
|
||
ordMonth: tNEXT tMONTH {
|
||
yyMonthOrdinal = 1;
|
||
yyMonth = $2;
|
||
}
|
||
| tNEXT tUNUMBER tMONTH {
|
||
yyMonthOrdinal = $2;
|
||
yyMonth = $3;
|
||
}
|
||
;
|
||
|
||
iso : tUNUMBER '-' tUNUMBER '-' tUNUMBER tZONE
|
||
tUNUMBER ':' tUNUMBER ':' tUNUMBER {
|
||
if ($6 != HOUR( 7) + HOUR(100)) YYABORT;
|
||
yyYear = $1;
|
||
yyMonth = $3;
|
||
yyDay = $5;
|
||
yyHour = $7;
|
||
yyMinutes = $9;
|
||
yySeconds = $11;
|
||
}
|
||
| tISOBASE tZONE tISOBASE {
|
||
if ($2 != HOUR( 7) + HOUR(100)) YYABORT;
|
||
yyYear = $1 / 10000;
|
||
yyMonth = ($1 % 10000)/100;
|
||
yyDay = $1 % 100;
|
||
yyHour = $3 / 10000;
|
||
yyMinutes = ($3 % 10000)/100;
|
||
yySeconds = $3 % 100;
|
||
}
|
||
| tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER {
|
||
if ($2 != HOUR( 7) + HOUR(100)) YYABORT;
|
||
yyYear = $1 / 10000;
|
||
yyMonth = ($1 % 10000)/100;
|
||
yyDay = $1 % 100;
|
||
yyHour = $3;
|
||
yyMinutes = $5;
|
||
yySeconds = $7;
|
||
}
|
||
| tISOBASE tISOBASE {
|
||
yyYear = $1 / 10000;
|
||
yyMonth = ($1 % 10000)/100;
|
||
yyDay = $1 % 100;
|
||
yyHour = $2 / 10000;
|
||
yyMinutes = ($2 % 10000)/100;
|
||
yySeconds = $2 % 100;
|
||
}
|
||
;
|
||
|
||
trek : tSTARDATE tUNUMBER '.' tUNUMBER {
|
||
/*
|
||
* Offset computed year by -377 so that the returned years will be
|
||
* in a range accessible with a 32 bit clock seconds value.
|
||
*/
|
||
|
||
yyYear = $2/1000 + 2323 - 377;
|
||
yyDay = 1;
|
||
yyMonth = 1;
|
||
yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000;
|
||
yyRelSeconds += $4 * 144 * 60;
|
||
}
|
||
;
|
||
|
||
relspec : relunits tAGO {
|
||
yyRelSeconds *= -1;
|
||
yyRelMonth *= -1;
|
||
yyRelDay *= -1;
|
||
}
|
||
| relunits
|
||
;
|
||
|
||
relunits : sign tUNUMBER unit {
|
||
*yyRelPointer += $1 * $2 * $3;
|
||
}
|
||
| tUNUMBER unit {
|
||
*yyRelPointer += $1 * $2;
|
||
}
|
||
| tNEXT unit {
|
||
*yyRelPointer += $2;
|
||
}
|
||
| tNEXT tUNUMBER unit {
|
||
*yyRelPointer += $2 * $3;
|
||
}
|
||
| unit {
|
||
*yyRelPointer += $1;
|
||
}
|
||
;
|
||
|
||
sign : '-' {
|
||
$$ = -1;
|
||
}
|
||
| '+' {
|
||
$$ = 1;
|
||
}
|
||
;
|
||
|
||
unit : tSEC_UNIT {
|
||
$$ = $1;
|
||
yyRelPointer = &yyRelSeconds;
|
||
}
|
||
| tDAY_UNIT {
|
||
$$ = $1;
|
||
yyRelPointer = &yyRelDay;
|
||
}
|
||
| tMONTH_UNIT {
|
||
$$ = $1;
|
||
yyRelPointer = &yyRelMonth;
|
||
}
|
||
;
|
||
|
||
number : tUNUMBER {
|
||
if (yyHaveTime && yyHaveDate && !yyHaveRel) {
|
||
yyYear = $1;
|
||
} else {
|
||
yyHaveTime++;
|
||
if (yyDigitCount <= 2) {
|
||
yyHour = $1;
|
||
yyMinutes = 0;
|
||
} else {
|
||
yyHour = $1 / 100;
|
||
yyMinutes = $1 % 100;
|
||
}
|
||
yySeconds = 0;
|
||
yyMeridian = MER24;
|
||
}
|
||
}
|
||
;
|
||
|
||
o_merid : /* NULL */ {
|
||
$$ = MER24;
|
||
}
|
||
| tMERIDIAN {
|
||
$$ = $1;
|
||
}
|
||
;
|
||
|
||
%%
|
||
/*
|
||
* Month and day table.
|
||
*/
|
||
|
||
static const TABLE MonthDayTable[] = {
|
||
{ "january", tMONTH, 1 },
|
||
{ "february", tMONTH, 2 },
|
||
{ "march", tMONTH, 3 },
|
||
{ "april", tMONTH, 4 },
|
||
{ "may", tMONTH, 5 },
|
||
{ "june", tMONTH, 6 },
|
||
{ "july", tMONTH, 7 },
|
||
{ "august", tMONTH, 8 },
|
||
{ "september", tMONTH, 9 },
|
||
{ "sept", tMONTH, 9 },
|
||
{ "october", tMONTH, 10 },
|
||
{ "november", tMONTH, 11 },
|
||
{ "december", tMONTH, 12 },
|
||
{ "sunday", tDAY, 0 },
|
||
{ "monday", tDAY, 1 },
|
||
{ "tuesday", tDAY, 2 },
|
||
{ "tues", tDAY, 2 },
|
||
{ "wednesday", tDAY, 3 },
|
||
{ "wednes", tDAY, 3 },
|
||
{ "thursday", tDAY, 4 },
|
||
{ "thur", tDAY, 4 },
|
||
{ "thurs", tDAY, 4 },
|
||
{ "friday", tDAY, 5 },
|
||
{ "saturday", tDAY, 6 },
|
||
{ NULL, 0, 0 }
|
||
};
|
||
|
||
/*
|
||
* Time units table.
|
||
*/
|
||
|
||
static const TABLE UnitsTable[] = {
|
||
{ "year", tMONTH_UNIT, 12 },
|
||
{ "month", tMONTH_UNIT, 1 },
|
||
{ "fortnight", tDAY_UNIT, 14 },
|
||
{ "week", tDAY_UNIT, 7 },
|
||
{ "day", tDAY_UNIT, 1 },
|
||
{ "hour", tSEC_UNIT, 60 * 60 },
|
||
{ "minute", tSEC_UNIT, 60 },
|
||
{ "min", tSEC_UNIT, 60 },
|
||
{ "second", tSEC_UNIT, 1 },
|
||
{ "sec", tSEC_UNIT, 1 },
|
||
{ NULL, 0, 0 }
|
||
};
|
||
|
||
/*
|
||
* Assorted relative-time words.
|
||
*/
|
||
|
||
static const TABLE OtherTable[] = {
|
||
{ "tomorrow", tDAY_UNIT, 1 },
|
||
{ "yesterday", tDAY_UNIT, -1 },
|
||
{ "today", tDAY_UNIT, 0 },
|
||
{ "now", tSEC_UNIT, 0 },
|
||
{ "last", tUNUMBER, -1 },
|
||
{ "this", tSEC_UNIT, 0 },
|
||
{ "next", tNEXT, 1 },
|
||
#if 0
|
||
{ "first", tUNUMBER, 1 },
|
||
{ "second", tUNUMBER, 2 },
|
||
{ "third", tUNUMBER, 3 },
|
||
{ "fourth", tUNUMBER, 4 },
|
||
{ "fifth", tUNUMBER, 5 },
|
||
{ "sixth", tUNUMBER, 6 },
|
||
{ "seventh", tUNUMBER, 7 },
|
||
{ "eighth", tUNUMBER, 8 },
|
||
{ "ninth", tUNUMBER, 9 },
|
||
{ "tenth", tUNUMBER, 10 },
|
||
{ "eleventh", tUNUMBER, 11 },
|
||
{ "twelfth", tUNUMBER, 12 },
|
||
#endif
|
||
{ "ago", tAGO, 1 },
|
||
{ "epoch", tEPOCH, 0 },
|
||
{ "stardate", tSTARDATE, 0 },
|
||
{ NULL, 0, 0 }
|
||
};
|
||
|
||
/*
|
||
* The timezone table. (Note: This table was modified to not use any floating
|
||
* point constants to work around an SGI compiler bug).
|
||
*/
|
||
|
||
static const TABLE TimezoneTable[] = {
|
||
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
|
||
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
|
||
{ "utc", tZONE, HOUR( 0) },
|
||
{ "uct", tZONE, HOUR( 0) }, /* Universal Coordinated Time */
|
||
{ "wet", tZONE, HOUR( 0) }, /* Western European */
|
||
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
|
||
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
|
||
{ "at", tZONE, HOUR( 2) }, /* Azores */
|
||
#if 0
|
||
/* For completeness. BST is also British Summer, and GST is
|
||
* also Guam Standard. */
|
||
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
|
||
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
|
||
#endif
|
||
{ "nft", tZONE, HOUR( 7/2) }, /* Newfoundland */
|
||
{ "nst", tZONE, HOUR( 7/2) }, /* Newfoundland Standard */
|
||
{ "ndt", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */
|
||
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
|
||
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
|
||
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
|
||
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
|
||
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
|
||
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
|
||
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
|
||
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
|
||
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
|
||
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
|
||
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
|
||
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
|
||
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
|
||
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
|
||
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
|
||
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
|
||
{ "nt", tZONE, HOUR(11) }, /* Nome */
|
||
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
|
||
{ "cet", tZONE, -HOUR( 1) }, /* Central European */
|
||
{ "cest", tDAYZONE, -HOUR( 1) }, /* Central European Summer */
|
||
{ "met", tZONE, -HOUR( 1) }, /* Middle European */
|
||
{ "mewt", tZONE, -HOUR( 1) }, /* Middle European Winter */
|
||
{ "mest", tDAYZONE, -HOUR( 1) }, /* Middle European Summer */
|
||
{ "swt", tZONE, -HOUR( 1) }, /* Swedish Winter */
|
||
{ "sst", tDAYZONE, -HOUR( 1) }, /* Swedish Summer */
|
||
{ "fwt", tZONE, -HOUR( 1) }, /* French Winter */
|
||
{ "fst", tDAYZONE, -HOUR( 1) }, /* French Summer */
|
||
{ "eet", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */
|
||
{ "bt", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */
|
||
{ "it", tZONE, -HOUR( 7/2) }, /* Iran */
|
||
{ "zp4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */
|
||
{ "zp5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */
|
||
{ "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */
|
||
{ "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */
|
||
#if 0
|
||
/* For completeness. NST is also Newfoundland Stanard, nad SST is
|
||
* also Swedish Summer. */
|
||
{ "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */
|
||
{ "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */
|
||
#endif /* 0 */
|
||
{ "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */
|
||
{ "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */
|
||
{ "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */
|
||
{ "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */
|
||
{ "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */
|
||
{ "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */
|
||
{ "kst", tZONE, -HOUR( 9) }, /* Korea Standard */
|
||
{ "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */
|
||
{ "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */
|
||
{ "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */
|
||
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
|
||
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
|
||
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
|
||
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
|
||
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
|
||
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
|
||
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
|
||
/* ADDED BY Marco Nijdam */
|
||
{ "dst", tDST, HOUR( 0) }, /* DST on (hour is ignored) */
|
||
/* End ADDED */
|
||
{ NULL, 0, 0 }
|
||
};
|
||
|
||
/*
|
||
* Military timezone table.
|
||
*/
|
||
|
||
static const TABLE MilitaryTable[] = {
|
||
{ "a", tZONE, -HOUR( 1) + HOUR(100) },
|
||
{ "b", tZONE, -HOUR( 2) + HOUR(100) },
|
||
{ "c", tZONE, -HOUR( 3) + HOUR(100) },
|
||
{ "d", tZONE, -HOUR( 4) + HOUR(100) },
|
||
{ "e", tZONE, -HOUR( 5) + HOUR(100) },
|
||
{ "f", tZONE, -HOUR( 6) + HOUR(100) },
|
||
{ "g", tZONE, -HOUR( 7) + HOUR(100) },
|
||
{ "h", tZONE, -HOUR( 8) + HOUR(100) },
|
||
{ "i", tZONE, -HOUR( 9) + HOUR(100) },
|
||
{ "k", tZONE, -HOUR(10) + HOUR(100) },
|
||
{ "l", tZONE, -HOUR(11) + HOUR(100) },
|
||
{ "m", tZONE, -HOUR(12) + HOUR(100) },
|
||
{ "n", tZONE, HOUR( 1) + HOUR(100) },
|
||
{ "o", tZONE, HOUR( 2) + HOUR(100) },
|
||
{ "p", tZONE, HOUR( 3) + HOUR(100) },
|
||
{ "q", tZONE, HOUR( 4) + HOUR(100) },
|
||
{ "r", tZONE, HOUR( 5) + HOUR(100) },
|
||
{ "s", tZONE, HOUR( 6) + HOUR(100) },
|
||
{ "t", tZONE, HOUR( 7) + HOUR(100) },
|
||
{ "u", tZONE, HOUR( 8) + HOUR(100) },
|
||
{ "v", tZONE, HOUR( 9) + HOUR(100) },
|
||
{ "w", tZONE, HOUR( 10) + HOUR(100) },
|
||
{ "x", tZONE, HOUR( 11) + HOUR(100) },
|
||
{ "y", tZONE, HOUR( 12) + HOUR(100) },
|
||
{ "z", tZONE, HOUR( 0) + HOUR(100) },
|
||
{ NULL, 0, 0 }
|
||
};
|
||
|
||
/*
|
||
* Dump error messages in the bit bucket.
|
||
*/
|
||
|
||
static void
|
||
TclDateerror(
|
||
YYLTYPE* location,
|
||
DateInfo* infoPtr,
|
||
const char *s)
|
||
{
|
||
Tcl_Obj* t;
|
||
Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1);
|
||
Tcl_AppendToObj(infoPtr->messages, s, -1);
|
||
Tcl_AppendToObj(infoPtr->messages, " (characters ", -1);
|
||
TclNewIntObj(t, location->first_column);
|
||
Tcl_IncrRefCount(t);
|
||
Tcl_AppendObjToObj(infoPtr->messages, t);
|
||
Tcl_DecrRefCount(t);
|
||
Tcl_AppendToObj(infoPtr->messages, "-", -1);
|
||
TclNewIntObj(t, location->last_column);
|
||
Tcl_IncrRefCount(t);
|
||
Tcl_AppendObjToObj(infoPtr->messages, t);
|
||
Tcl_DecrRefCount(t);
|
||
Tcl_AppendToObj(infoPtr->messages, ")", -1);
|
||
infoPtr->separatrix = "\n";
|
||
}
|
||
|
||
static time_t
|
||
ToSeconds(
|
||
time_t Hours,
|
||
time_t Minutes,
|
||
time_t Seconds,
|
||
MERIDIAN Meridian)
|
||
{
|
||
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) {
|
||
return -1;
|
||
}
|
||
switch (Meridian) {
|
||
case MER24:
|
||
if (Hours < 0 || Hours > 23) {
|
||
return -1;
|
||
}
|
||
return (Hours * 60L + Minutes) * 60L + Seconds;
|
||
case MERam:
|
||
if (Hours < 1 || Hours > 12) {
|
||
return -1;
|
||
}
|
||
return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
|
||
case MERpm:
|
||
if (Hours < 1 || Hours > 12) {
|
||
return -1;
|
||
}
|
||
return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
|
||
}
|
||
return -1; /* Should never be reached */
|
||
}
|
||
|
||
static int
|
||
LookupWord(
|
||
YYSTYPE* yylvalPtr,
|
||
char *buff)
|
||
{
|
||
char *p;
|
||
char *q;
|
||
const TABLE *tp;
|
||
int i, abbrev;
|
||
|
||
/*
|
||
* Make it lowercase.
|
||
*/
|
||
|
||
Tcl_UtfToLower(buff);
|
||
|
||
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
|
||
yylvalPtr->Meridian = MERam;
|
||
return tMERIDIAN;
|
||
}
|
||
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
|
||
yylvalPtr->Meridian = MERpm;
|
||
return tMERIDIAN;
|
||
}
|
||
|
||
/*
|
||
* See if we have an abbreviation for a month.
|
||
*/
|
||
|
||
if (strlen(buff) == 3) {
|
||
abbrev = 1;
|
||
} else if (strlen(buff) == 4 && buff[3] == '.') {
|
||
abbrev = 1;
|
||
buff[3] = '\0';
|
||
} else {
|
||
abbrev = 0;
|
||
}
|
||
|
||
for (tp = MonthDayTable; tp->name; tp++) {
|
||
if (abbrev) {
|
||
if (strncmp(buff, tp->name, 3) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
} else if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
|
||
for (tp = TimezoneTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
|
||
for (tp = UnitsTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Strip off any plural and try the units table again.
|
||
*/
|
||
|
||
i = strlen(buff) - 1;
|
||
if (i > 0 && buff[i] == 's') {
|
||
buff[i] = '\0';
|
||
for (tp = UnitsTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (tp = OtherTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Military timezones.
|
||
*/
|
||
|
||
if (buff[1] == '\0' && !(*buff & 0x80)
|
||
&& isalpha(UCHAR(*buff))) { /* INTL: ISO only */
|
||
for (tp = MilitaryTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Drop out any periods and try the timezone table again.
|
||
*/
|
||
|
||
for (i = 0, p = q = buff; *q; q++) {
|
||
if (*q != '.') {
|
||
*p++ = *q;
|
||
} else {
|
||
i++;
|
||
}
|
||
}
|
||
*p = '\0';
|
||
if (i) {
|
||
for (tp = TimezoneTable; tp->name; tp++) {
|
||
if (strcmp(buff, tp->name) == 0) {
|
||
yylvalPtr->Number = tp->value;
|
||
return tp->type;
|
||
}
|
||
}
|
||
}
|
||
|
||
return tID;
|
||
}
|
||
|
||
static int
|
||
TclDatelex(
|
||
YYSTYPE* yylvalPtr,
|
||
YYLTYPE* location,
|
||
DateInfo *info)
|
||
{
|
||
char c;
|
||
char *p;
|
||
char buff[20];
|
||
int Count;
|
||
|
||
location->first_column = yyInput - info->dateStart;
|
||
for ( ; ; ) {
|
||
while (TclIsSpaceProcM(*yyInput)) {
|
||
yyInput++;
|
||
}
|
||
|
||
if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */
|
||
/*
|
||
* Convert the string into a number; count the number of digits.
|
||
*/
|
||
|
||
Count = 0;
|
||
for (yylvalPtr->Number = 0;
|
||
isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */
|
||
yylvalPtr->Number = 10 * yylvalPtr->Number + c - '0';
|
||
Count++;
|
||
}
|
||
yyInput--;
|
||
yyDigitCount = Count;
|
||
|
||
/*
|
||
* A number with 6 or more digits is considered an ISO 8601 base.
|
||
*/
|
||
|
||
if (Count >= 6) {
|
||
location->last_column = yyInput - info->dateStart - 1;
|
||
return tISOBASE;
|
||
} else {
|
||
location->last_column = yyInput - info->dateStart - 1;
|
||
return tUNUMBER;
|
||
}
|
||
}
|
||
if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */
|
||
for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */
|
||
|| c == '.'; ) {
|
||
if (p < &buff[sizeof buff - 1]) {
|
||
*p++ = c;
|
||
}
|
||
}
|
||
*p = '\0';
|
||
yyInput--;
|
||
location->last_column = yyInput - info->dateStart - 1;
|
||
return LookupWord(yylvalPtr, buff);
|
||
}
|
||
if (c != '(') {
|
||
location->last_column = yyInput - info->dateStart;
|
||
return *yyInput++;
|
||
}
|
||
Count = 0;
|
||
do {
|
||
c = *yyInput++;
|
||
if (c == '\0') {
|
||
location->last_column = yyInput - info->dateStart - 1;
|
||
return c;
|
||
} else if (c == '(') {
|
||
Count++;
|
||
} else if (c == ')') {
|
||
Count--;
|
||
}
|
||
} while (Count > 0);
|
||
}
|
||
}
|
||
|
||
int
|
||
TclClockOldscanObjCmd(
|
||
void *dummy, /* Unused */
|
||
Tcl_Interp *interp, /* Tcl interpreter */
|
||
int objc, /* Count of paraneters */
|
||
Tcl_Obj *const *objv) /* Parameters */
|
||
{
|
||
Tcl_Obj *result, *resultElement;
|
||
int yr, mo, da;
|
||
DateInfo dateInfo;
|
||
DateInfo* info = &dateInfo;
|
||
int status;
|
||
(void)dummy;
|
||
|
||
if (objc != 5) {
|
||
Tcl_WrongNumArgs(interp, 1, objv,
|
||
"stringToParse baseYear baseMonth baseDay" );
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
yyInput = Tcl_GetString( objv[1] );
|
||
dateInfo.dateStart = yyInput;
|
||
|
||
yyHaveDate = 0;
|
||
if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK
|
||
|| Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK
|
||
|| Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) {
|
||
return TCL_ERROR;
|
||
}
|
||
yyYear = yr; yyMonth = mo; yyDay = da;
|
||
|
||
yyHaveTime = 0;
|
||
yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24;
|
||
|
||
yyHaveZone = 0;
|
||
yyTimezone = 0; yyDSTmode = DSTmaybe;
|
||
|
||
yyHaveOrdinalMonth = 0;
|
||
yyMonthOrdinal = 0;
|
||
|
||
yyHaveDay = 0;
|
||
yyDayOrdinal = 0; yyDayNumber = 0;
|
||
|
||
yyHaveRel = 0;
|
||
yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL;
|
||
|
||
TclNewObj(dateInfo.messages);
|
||
dateInfo.separatrix = "";
|
||
Tcl_IncrRefCount(dateInfo.messages);
|
||
|
||
status = yyparse(&dateInfo);
|
||
if (status == 1) {
|
||
Tcl_SetObjResult(interp, dateInfo.messages);
|
||
Tcl_DecrRefCount(dateInfo.messages);
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL);
|
||
return TCL_ERROR;
|
||
} else if (status == 2) {
|
||
Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1));
|
||
Tcl_DecrRefCount(dateInfo.messages);
|
||
Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
|
||
return TCL_ERROR;
|
||
} else if (status != 0) {
|
||
Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown status returned "
|
||
"from date parser. Please "
|
||
"report this error as a "
|
||
"bug in Tcl.", -1));
|
||
Tcl_DecrRefCount(dateInfo.messages);
|
||
Tcl_SetErrorCode(interp, "TCL", "BUG", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
Tcl_DecrRefCount(dateInfo.messages);
|
||
|
||
if (yyHaveDate > 1) {
|
||
Tcl_SetObjResult(interp,
|
||
Tcl_NewStringObj("more than one date in string", -1));
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
if (yyHaveTime > 1) {
|
||
Tcl_SetObjResult(interp,
|
||
Tcl_NewStringObj("more than one time of day in string", -1));
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
if (yyHaveZone > 1) {
|
||
Tcl_SetObjResult(interp,
|
||
Tcl_NewStringObj("more than one time zone in string", -1));
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
if (yyHaveDay > 1) {
|
||
Tcl_SetObjResult(interp,
|
||
Tcl_NewStringObj("more than one weekday in string", -1));
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
if (yyHaveOrdinalMonth > 1) {
|
||
Tcl_SetObjResult(interp,
|
||
Tcl_NewStringObj("more than one ordinal month in string", -1));
|
||
Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
TclNewObj(result);
|
||
TclNewObj(resultElement);
|
||
if (yyHaveDate) {
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyYear));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyMonth));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyDay));
|
||
}
|
||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||
|
||
if (yyHaveTime) {
|
||
Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj((int)
|
||
ToSeconds(yyHour, yyMinutes, yySeconds, (MERIDIAN)yyMeridian)));
|
||
} else {
|
||
Tcl_ListObjAppendElement(interp, result, Tcl_NewObj());
|
||
}
|
||
|
||
TclNewObj(resultElement);
|
||
if (yyHaveZone) {
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) -yyTimezone));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj(1 - yyDSTmode));
|
||
}
|
||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||
|
||
TclNewObj(resultElement);
|
||
if (yyHaveRel) {
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyRelMonth));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyRelDay));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyRelSeconds));
|
||
}
|
||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||
|
||
TcNewObj(resultElement);
|
||
if (yyHaveDay && !yyHaveDate) {
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyDayOrdinal));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyDayNumber));
|
||
}
|
||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||
|
||
TclNewObj(resultElement);
|
||
if (yyHaveOrdinalMonth) {
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyMonthOrdinal));
|
||
Tcl_ListObjAppendElement(interp, resultElement,
|
||
Tcl_NewIntObj((int) yyMonth));
|
||
}
|
||
Tcl_ListObjAppendElement(interp, result, resultElement);
|
||
|
||
Tcl_SetObjResult(interp, result);
|
||
return TCL_OK;
|
||
}
|
||
|
||
/*
|
||
* Local Variables:
|
||
* mode: c
|
||
* c-basic-offset: 4
|
||
* fill-column: 78
|
||
* End:
|
||
*/
|