diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2024-04-01 19:56:29 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2024-04-01 19:56:29 (GMT) |
commit | 8912060cdcf0a95cb82a6e7e62fd43cb49cbee84 (patch) | |
tree | 07b7c505e21f347e493c9edab8e8ae7539ccbf51 /generic/tclGetDate.y | |
parent | a478f93fdabf01d106b3b76ab2d83141d178ff4c (diff) | |
parent | 0670a7bc017e581d6fa5376ce4e23564cf7ceb54 (diff) | |
download | tcl-8912060cdcf0a95cb82a6e7e62fd43cb49cbee84.zip tcl-8912060cdcf0a95cb82a6e7e62fd43cb49cbee84.tar.gz tcl-8912060cdcf0a95cb82a6e7e62fd43cb49cbee84.tar.bz2 |
TIP 688: clock command revision and speedup
Diffstat (limited to 'generic/tclGetDate.y')
-rw-r--r-- | generic/tclGetDate.y | 684 |
1 files changed, 313 insertions, 371 deletions
diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index dc30d51..3b04de4 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -7,8 +7,9 @@ * 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. + * Copyright © 1992-1995 Karl Lehenbauer & Mark Diekhans. + * Copyright © 1995-1997 Sun Microsystems, Inc. + * Copyright © 2015 Sergey G. Brester aka sebres. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -27,8 +28,9 @@ * 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. + * Copyright © 1992-1995 Karl Lehenbauer & Mark Diekhans. + * Copyright © 1995-1997 Sun Microsystems, Inc. + * Copyright © 2015 Sergey G. Brester aka sebres. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -45,86 +47,20 @@ #pragma warning( disable : 4102 ) #endif /* _MSC_VER */ -/* - * Meridian: am, pm, or 24-hour style. - */ - -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; +#if 0 +#define YYDEBUG 1 +#endif /* * 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; +#include "tclDate.h" #define YYMALLOC Tcl_Alloc #define YYFREE(x) (Tcl_Free((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 @@ -136,18 +72,24 @@ typedef struct DateInfo { #define TM_YEAR_BASE 1900 -#define HOUR(x) ((int) (60 * (x))) -#define SECSPERDAY (24L * 60L * 60L) +#define HOUR(x) ((60 * (int)(x))) #define IsLeapYear(x) (((x) % 4 == 0) && ((x) % 100 != 0 || (x) % 400 == 0)) +#define yyIncrFlags(f) \ + do { \ + info->errFlags |= (info->flags & (f)); \ + if (info->errFlags) { YYABORT; } \ + info->flags |= (f); \ + } while (0); + /* * An entry in the lexical lookup table. */ -typedef struct _TABLE { +typedef struct { const char *name; int type; - time_t value; + int value; } TABLE; /* @@ -161,7 +103,7 @@ typedef enum _DSTMODE { %} %union { - time_t Number; + Tcl_WideInt Number; enum _MERIDIAN Meridian; } @@ -172,12 +114,10 @@ typedef enum _DSTMODE { */ static int LookupWord(YYSTYPE* yylvalPtr, char *buff); - static void TclDateerror(YYLTYPE* location, +static void TclDateerror(YYLTYPE* location, DateInfo* info, const char *s); - static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, +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*); %} @@ -191,14 +131,18 @@ MODULE_SCOPE int yyparse(DateInfo*); %token tMONTH_UNIT %token tSTARDATE %token tSEC_UNIT -%token tSNUMBER %token tUNUMBER %token tZONE +%token tZONEwO4 +%token tZONEwO2 %token tEPOCH %token tDST -%token tISOBASE +%token tISOBAS8 +%token tISOBAS6 +%token tISOBASL %token tDAY_UNIT %token tNEXT +%token SP %type <Number> tDAY %type <Number> tDAYZONE @@ -206,10 +150,14 @@ MODULE_SCOPE int yyparse(DateInfo*); %type <Number> tMONTH_UNIT %type <Number> tDST %type <Number> tSEC_UNIT -%type <Number> tSNUMBER %type <Number> tUNUMBER +%type <Number> INTNUM %type <Number> tZONE -%type <Number> tISOBASE +%type <Number> tZONEwO4 +%type <Number> tZONEwO2 +%type <Number> tISOBAS8 +%type <Number> tISOBAS6 +%type <Number> tISOBASL %type <Number> tDAY_UNIT %type <Number> unit %type <Number> sign @@ -222,100 +170,121 @@ MODULE_SCOPE int yyparse(DateInfo*); spec : /* NULL */ | spec item + /* | spec SP item */ ; item : time { - yyHaveTime++; + yyIncrFlags(CLF_TIME); } | zone { - yyHaveZone++; + yyIncrFlags(CLF_ZONE); } | date { - yyHaveDate++; + yyIncrFlags(CLF_HAVEDATE); } | ordMonth { - yyHaveOrdinalMonth++; + yyIncrFlags(CLF_ORDINALMONTH); } | day { - yyHaveDay++; + yyIncrFlags(CLF_DAYOFWEEK); } | relspec { - yyHaveRel++; + info->flags |= CLF_RELCONV; } | iso { - yyHaveTime++; - yyHaveDate++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); } | trek { - yyHaveTime++; - yyHaveDate++; - yyHaveRel++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); + info->flags |= CLF_RELCONV; } - | number + | numitem ; -time : tUNUMBER tMERIDIAN { +iextime : tUNUMBER ':' tUNUMBER ':' tUNUMBER { yyHour = $1; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = $2; + yyMinutes = $3; + yySeconds = $5; } - | tUNUMBER ':' tUNUMBER o_merid { + | tUNUMBER ':' tUNUMBER { yyHour = $1; yyMinutes = $3; yySeconds = 0; - yyMeridian = $4; } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + ; +time : tUNUMBER tMERIDIAN { yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = $6; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | iextime o_merid { + yyMeridian = $2; } ; 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 { + | tZONEwO4 sign INTNUM { /* GMT+0100, GMT-1000, etc. */ + yyTimezone = $1 - $2*($3 % 100 + ($3 / 100) * 60); + yyDSTmode = DSToff; + } + | tZONEwO2 sign INTNUM { /* GMT+1, GMT-10, etc. */ + yyTimezone = $1 - $2*($3 * 60); + yyDSTmode = DSToff; + } + | sign INTNUM { /* +0100, -0100 */ yyTimezone = -$1*($2 % 100 + ($2 / 100) * 60); yyDSTmode = DSToff; } ; +comma : ',' + | ',' SP + ; + day : tDAY { yyDayOrdinal = 1; - yyDayNumber = $1; + yyDayOfWeek = $1; } - | tDAY ',' { + | tDAY comma { yyDayOrdinal = 1; - yyDayNumber = $1; + yyDayOfWeek = $1; } | tUNUMBER tDAY { yyDayOrdinal = $1; - yyDayNumber = $2; + yyDayOfWeek = $2; + } + | sign SP tUNUMBER tDAY { + yyDayOrdinal = $1 * $3; + yyDayOfWeek = $4; } | sign tUNUMBER tDAY { yyDayOrdinal = $1 * $2; - yyDayNumber = $3; + yyDayOfWeek = $3; } | tNEXT tDAY { yyDayOrdinal = 2; - yyDayNumber = $2; + yyDayOfWeek = $2; } ; +iexdate : tUNUMBER '-' tUNUMBER '-' tUNUMBER { + yyMonth = $3; + yyDay = $5; + yyYear = $1; + } + ; date : tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; @@ -325,26 +294,17 @@ date : tUNUMBER '/' tUNUMBER { yyDay = $3; yyYear = $5; } - | tISOBASE { - yyYear = $1 / 10000; - yyMonth = ($1 % 10000)/100; - yyDay = $1 % 100; - } + | isodate | 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 { + | tMONTH tUNUMBER comma tUNUMBER { yyMonth = $1; yyDay = $2; yyYear = $4; @@ -366,44 +326,38 @@ date : tUNUMBER '/' tUNUMBER { ; ordMonth: tNEXT tMONTH { - yyMonthOrdinal = 1; - yyMonth = $2; + yyMonthOrdinalIncr = 1; + yyMonthOrdinal = $2; } | tNEXT tUNUMBER tMONTH { - yyMonthOrdinal = $2; - yyMonth = $3; + yyMonthOrdinalIncr = $2; + yyMonthOrdinal = $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; +isosep : 'T'|SP + ; +isodate : tISOBAS8 { /* YYYYMMDD */ 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; + | tISOBAS6 { /* YYMMDD */ yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; - yyHour = $3; - yyMinutes = $5; - yySeconds = $7; } - | tISOBASE tISOBASE { + | iexdate + ; +isotime : tISOBAS6 { + yyHour = $1 / 10000; + yyMinutes = ($1 % 10000)/100; + yySeconds = $1 % 100; + } + | iextime + ; +iso : isodate isosep isotime + | tISOBASL tISOBAS6 { /* YYYYMMDDhhmmss */ yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; @@ -411,9 +365,18 @@ iso : tUNUMBER '-' tUNUMBER '-' tUNUMBER tZONE yyMinutes = ($2 % 10000)/100; yySeconds = $2 % 100; } + | tISOBASL tUNUMBER { /* YYYYMMDDhhmm */ + if (yyDigitCount != 4) YYABORT; /* normally unreached */ + yyYear = $1 / 10000; + yyMonth = ($1 % 10000)/100; + yyDay = $1 % 100; + yyHour = $2 / 100; + yyMinutes = ($2 % 100); + yySeconds = 0; + } ; -trek : tSTARDATE tUNUMBER '.' tUNUMBER { +trek : tSTARDATE INTNUM '.' tUNUMBER { /* * Offset computed year by -377 so that the returned years will be * in a range accessible with a 32 bit clock seconds value. @@ -423,7 +386,7 @@ trek : tSTARDATE tUNUMBER '.' tUNUMBER { yyDay = 1; yyMonth = 1; yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000; - yyRelSeconds += $4 * 144 * 60; + yyRelSeconds += $4 * (144LL * 60LL); } ; @@ -435,16 +398,19 @@ relspec : relunits tAGO { | relunits ; -relunits : sign tUNUMBER unit { +relunits : sign SP INTNUM unit { + *yyRelPointer += $1 * $3 * $4; + } + | sign INTNUM unit { *yyRelPointer += $1 * $2 * $3; } - | tUNUMBER unit { + | INTNUM unit { *yyRelPointer += $1 * $2; } | tNEXT unit { *yyRelPointer += $2; } - | tNEXT tUNUMBER unit { + | tNEXT INTNUM unit { *yyRelPointer += $2 * $3; } | unit { @@ -474,11 +440,22 @@ unit : tSEC_UNIT { } ; -number : tUNUMBER { - if (yyHaveTime && yyHaveDate && !yyHaveRel) { +INTNUM : tUNUMBER { + $$ = $1; + } + | tISOBAS6 { + $$ = $1; + } + | tISOBAS8 { + $$ = $1; + } + ; + +numitem : tUNUMBER { + if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { yyYear = $1; } else { - yyHaveTime++; + yyIncrFlags(CLF_TIME); if (yyDigitCount <= 2) { yyHour = $1; yyMinutes = 0; @@ -563,20 +540,6 @@ static const TABLE OtherTable[] = { { "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 }, @@ -676,34 +639,44 @@ static const TABLE TimezoneTable[] = { */ 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) }, + { "a", tZONE, -HOUR( 1) }, + { "b", tZONE, -HOUR( 2) }, + { "c", tZONE, -HOUR( 3) }, + { "d", tZONE, -HOUR( 4) }, + { "e", tZONE, -HOUR( 5) }, + { "f", tZONE, -HOUR( 6) }, + { "g", tZONE, -HOUR( 7) }, + { "h", tZONE, -HOUR( 8) }, + { "i", tZONE, -HOUR( 9) }, + { "k", tZONE, -HOUR(10) }, + { "l", tZONE, -HOUR(11) }, + { "m", tZONE, -HOUR(12) }, + { "n", tZONE, HOUR( 1) }, + { "o", tZONE, HOUR( 2) }, + { "p", tZONE, HOUR( 3) }, + { "q", tZONE, HOUR( 4) }, + { "r", tZONE, HOUR( 5) }, + { "s", tZONE, HOUR( 6) }, + { "t", tZONE, HOUR( 7) }, + { "u", tZONE, HOUR( 8) }, + { "v", tZONE, HOUR( 9) }, + { "w", tZONE, HOUR( 10) }, + { "x", tZONE, HOUR( 11) }, + { "y", tZONE, HOUR( 12) }, + { "z", tZONE, HOUR( 0) }, { NULL, 0, 0 } }; +static inline const char * +bypassSpaces( + const char *s) +{ + while (TclIsSpaceProc(*s)) { + s++; + } + return s; +} + /* * Dump error messages in the bit bucket. */ @@ -715,6 +688,9 @@ TclDateerror( const char *s) { Tcl_Obj* t; + if (!infoPtr->messages) { + TclNewObj(infoPtr->messages); + } Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); Tcl_AppendToObj(infoPtr->messages, s, -1); Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); @@ -731,11 +707,11 @@ TclDateerror( infoPtr->separatrix = "\n"; } -static time_t +int ToSeconds( - time_t Hours, - time_t Minutes, - time_t Seconds, + int Hours, + int Minutes, + int Seconds, MERIDIAN Meridian) { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) { @@ -746,17 +722,17 @@ ToSeconds( if (Hours < 0 || Hours > 23) { return -1; } - return (Hours * 60L + Minutes) * 60L + Seconds; + return (Hours * 60 + Minutes) * 60 + Seconds; case MERam: if (Hours < 1 || Hours > 12) { return -1; } - return ((Hours % 12) * 60L + Minutes) * 60L + Seconds; + return ((Hours % 12) * 60 + Minutes) * 60 + Seconds; case MERpm: if (Hours < 1 || Hours > 12) { return -1; } - return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds; + return (((Hours % 12) + 12) * 60 + Minutes) * 60 + Seconds; } return -1; /* Should never be reached */ } @@ -777,11 +753,11 @@ LookupWord( Tcl_UtfToLower(buff); - if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + if (*buff == 'a' && (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0)) { yylvalPtr->Meridian = MERam; return tMERIDIAN; } - if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + if (*buff == 'p' && (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0)) { yylvalPtr->Meridian = MERpm; return tMERIDIAN; } @@ -895,50 +871,110 @@ TclDatelex( char *p; char buff[20]; int Count; + const char *tokStart; location->first_column = yyInput - info->dateStart; for ( ; ; ) { - while (TclIsSpaceProcM(*yyInput)) { - yyInput++; + + if (isspace(UCHAR(*yyInput))) { + yyInput = bypassSpaces(yyInput); + /* ignore space at end of text and before some words */ + c = *yyInput; + if (c != '\0' && !isalpha(UCHAR(c))) { + return SP; + } } + tokStart = yyInput; if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ + /* - * Convert the string into a number; count the number of digits. + * 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++; + p = (char *)yyInput; + while (isdigit(UCHAR(*++p))) {}; + yyDigitCount = p - yyInput; + /* + * A number with 12 or 14 digits is considered an ISO 8601 date. + */ + if (yyDigitCount == 14 || yyDigitCount == 12) { + /* long form of ISO 8601 (without separator), either + * YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date + * (8 chars is isodate) */ + p = (char *)yyInput+8; + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } + yyDigitCount = 8; + yyInput = p; + location->last_column = yyInput - info->dateStart - 1; + return tISOBASL; } - yyInput--; - yyDigitCount = Count; - + /* + * Convert the string into a number + */ + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } + yyInput = p; /* * 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; + location->last_column = yyInput - info->dateStart - 1; + if (yyDigitCount >= 6) { + if (yyDigitCount == 8) { + return tISOBAS8; + } + if (yyDigitCount == 6) { + return tISOBAS6; + } } + /* ignore spaces after digits (optional) */ + yyInput = bypassSpaces(yyInput); + return tUNUMBER; } if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ + int ret; for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { - if (p < &buff[sizeof buff - 1]) { + if (p < &buff[sizeof(buff) - 1]) { *p++ = c; } } *p = '\0'; yyInput--; location->last_column = yyInput - info->dateStart - 1; - return LookupWord(yylvalPtr, buff); + ret = LookupWord(yylvalPtr, buff); + /* + * lookahead: + * for spaces to consider word boundaries (for instance + * literal T in isodateTisotimeZ is not a TZ, but Z is UTC); + * for +/- digit, to differentiate between "GMT+1000 day" and "GMT +1000 day"; + * bypass spaces after token (but ignore by TZ+OFFS), because should + * recognize next SP token, if TZ only. + */ + if (ret == tZONE || ret == tDAYZONE) { + c = *yyInput; + if (isdigit(UCHAR(c))) { /* literal not a TZ */ + yyInput = tokStart; + return *yyInput++; + } + if ((c == '+' || c == '-') && isdigit(UCHAR(*(yyInput+1)))) { + if ( !isdigit(UCHAR(*(yyInput+2))) + || !isdigit(UCHAR(*(yyInput+3)))) { + /* GMT+1, GMT-10, etc. */ + return tZONEwO2; + } + if ( isdigit(UCHAR(*(yyInput+4))) + && !isdigit(UCHAR(*(yyInput+5)))) { + /* GMT+1000, etc. */ + return tZONEwO4; + } + } + } + yyInput = bypassSpaces(yyInput); + return ret; + } if (c != '(') { location->last_column = yyInput - info->dateStart; @@ -958,169 +994,75 @@ TclDatelex( } while (Count > 0); } } - + int -TclClockOldscanObjCmd( - TCL_UNUSED(void *), +TclClockFreeScan( Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Count of parameters */ - Tcl_Obj *const *objv) /* Parameters */ + DateInfo *info) /* Input and result parameters */ { - Tcl_Obj *result, *resultElement; - int yr, mo, da; - DateInfo dateInfo; - DateInfo* info = &dateInfo; int status; - if (objc != 5) { - Tcl_WrongNumArgs(interp, 1, objv, - "stringToParse baseYear baseMonth baseDay" ); - return TCL_ERROR; - } - - yyInput = TclGetString(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; + #if YYDEBUG + /* enable debugging if compiled with YYDEBUG */ + yydebug = 1; + #endif - yyHaveTime = 0; - yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; - - yyHaveZone = 0; - yyTimezone = 0; yyDSTmode = DSTmaybe; + /* + * yyInput = stringToParse; + * + * ClockInitDateInfo(info) should be executed to pre-init info; + */ - yyHaveOrdinalMonth = 0; - yyMonthOrdinal = 0; + yyDSTmode = DSTmaybe; - yyHaveDay = 0; - yyDayOrdinal = 0; yyDayNumber = 0; + info->separatrix = ""; - yyHaveRel = 0; - yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; + info->dateStart = yyInput; - TclNewObj(dateInfo.messages); - dateInfo.separatrix = ""; - Tcl_IncrRefCount(dateInfo.messages); + /* ignore spaces at begin */ + yyInput = bypassSpaces(yyInput); - status = yyparse(&dateInfo); + /* parse */ + status = yyparse(info); if (status == 1) { - Tcl_SetObjResult(interp, dateInfo.messages); - Tcl_DecrRefCount(dateInfo.messages); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); - return TCL_ERROR; + const char *msg = NULL; + if (info->errFlags & CLF_HAVEDATE) { + msg = "more than one date in string"; + } else if (info->errFlags & CLF_TIME) { + msg = "more than one time of day in string"; + } else if (info->errFlags & CLF_ZONE) { + msg = "more than one time zone in string"; + } else if (info->errFlags & CLF_DAYOFWEEK) { + msg = "more than one weekday in string"; + } else if (info->errFlags & CLF_ORDINALMONTH) { + msg = "more than one ordinal month in string"; + } + if (msg) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); + } else { + Tcl_SetObjResult(interp, + info->messages ? info->messages : Tcl_NewObj()); + info->messages = NULL; + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); + } + status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_DecrRefCount(dateInfo.messages); Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL); - return TCL_ERROR; + status = 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", (char *)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", (char *)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", (char *)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", (char *)NULL); - return TCL_ERROR; + status = TCL_ERROR; } - if (yyHaveDay > 1) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one weekday in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); - return TCL_ERROR; + if (info->messages) { + Tcl_DecrRefCount(info->messages); } - if (yyHaveOrdinalMonth > 1) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one ordinal month in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); - return TCL_ERROR; - } - - TclNewObj(result); - TclNewObj(resultElement); - if (yyHaveDate) { - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyYear)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyMonth)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyDay)); - } - Tcl_ListObjAppendElement(interp, result, resultElement); - - if (yyHaveTime) { - Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj( - ToSeconds(yyHour, yyMinutes, yySeconds, (MERIDIAN)yyMeridian))); - } else { - TclNewObj(resultElement); - Tcl_ListObjAppendElement(interp, result, resultElement); - } - - TclNewObj(resultElement); - if (yyHaveZone) { - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(-yyTimezone)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(1 - yyDSTmode)); - } - Tcl_ListObjAppendElement(interp, result, resultElement); - - TclNewObj(resultElement); - if (yyHaveRel) { - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyRelMonth)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyRelDay)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyRelSeconds)); - } - Tcl_ListObjAppendElement(interp, result, resultElement); - - TclNewObj(resultElement); - if (yyHaveDay && !yyHaveDate) { - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyDayOrdinal)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyDayNumber)); - } - Tcl_ListObjAppendElement(interp, result, resultElement); - - TclNewObj(resultElement); - if (yyHaveOrdinalMonth) { - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyMonthOrdinal)); - Tcl_ListObjAppendElement(interp, resultElement, - Tcl_NewIntObj(yyMonth)); - } - Tcl_ListObjAppendElement(interp, result, resultElement); - - Tcl_SetObjResult(interp, result); - return TCL_OK; + return status; } /* |