From e5fd7b2a2adac4fd495a5c5f955af750e732292c Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 5 Oct 2018 18:13:40 +0000 Subject: scan: new tests for validation rules: invalid time (DST-hole, out of range in time-zone) --- tests/clock.test | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index 20ebb0a..4e81c10 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36604,6 +36604,68 @@ test clock-46.17$idx {scan: validation rules: invalid year} -setup { }; # foreach unset -nocomplain idx relstr +set dst_hole_check { + {":Europe/Berlin" + "2017-03-26 01:59:59" "2017-03-26 02:00:00" "2017-03-26 02:59:59" "2017-03-26 03:00:00" + "2017-10-29 01:59:59" "2017-10-29 02:00:00"} + {":Europe/Berlin" + "2018-03-25 01:59:59" "2018-03-25 02:00:00" "2018-03-25 02:59:59" "2018-03-25 03:00:00" + "2018-10-28 01:59:59" "2018-10-28 02:00:00"} + {":America/New_York" + "2017-03-12 01:59:59" "2017-03-12 02:00:00" "2017-03-12 02:59:59" "2017-03-12 03:00:00" + "2017-11-05 01:59:59" "2017-11-05 02:00:00"} + {":America/New_York" + "2018-03-11 01:59:59" "2018-03-11 02:00:00" "2018-03-11 02:59:59" "2018-03-11 03:00:00" + "2018-11-04 01:59:59" "2018-11-04 02:00:00"} +} +test clock-46.19-1 {free-scan: validation rules: invalid time (DST-hole, out of range in time-zone)} \ + -body { + set res {} + foreach tz $dst_hole_check { set dt [lassign $tz tz]; foreach dt $dt { + lappend res [set v [catch {clock scan $dt -timezone $tz -valid 1} msg]] + if {$v} { lappend res $msg } + }} + set res + } -cleanup { + unset -nocomplain res v dt tz + } -result [lrepeat 4 \ + {*}[list 0 {*}[lrepeat 2 1 {unable to convert input string: invalid time (does not exist in this time-zone)}] 0 0 0]] +test clock-46.19-2 {free-scan: validation rules regression: all scans successful, if -valid 0} \ + -body { + set res {} + set res {} + foreach tz $dst_hole_check { set dt [lassign $tz tz]; foreach dt $dt { + lappend res [set v [catch {clock scan $dt -timezone $tz} msg]] + }} + set res + } -cleanup { + unset -nocomplain res v dt tz + } -result [lrepeat 4 {*}[if {$valid_mode} {list 0 1 1 0 0 0} else {list 0 0 0 0 0 0}]] +test clock-46.19-3 {scan: validation rules: invalid time (DST-hole, out of range in time-zone)} \ + -body { + set res {} + foreach tz $dst_hole_check { set dt [lassign $tz tz]; foreach dt $dt { + lappend res [set v [catch {clock scan $dt -timezone $tz -format "%Y-%m-%d %H:%M:%S" -valid 1} msg]] + if {$v} { lappend res $msg } + }} + set res + } -cleanup { + unset -nocomplain res v dt tz + } -result [lrepeat 4 \ + {*}[list 0 {*}[lrepeat 2 1 {unable to convert input string: invalid time (does not exist in this time-zone)}] 0 0 0]] +test clock-46.19-4 {scan: validation rules regression: all scans successful, if -valid 0} \ + -body { + set res {} + set res {} + foreach tz $dst_hole_check { set dt [lassign $tz tz]; foreach dt $dt { + lappend res [set v [catch {clock scan $dt -timezone $tz -format "%Y-%m-%d %H:%M:%S"} msg]] + }} + set res + } -cleanup { + unset -nocomplain res v dt tz + } -result [lrepeat 4 {*}[if {$valid_mode} {list 0 1 1 0 0 0} else {list 0 0 0 0 0 0}]] +unset -nocomplain dst_hole_check + test clock-46.20 {scan: validation rules: invalid time} \ -body { # 13:00 am/pm are invalid input strings... -- cgit v0.12 From ed80b6476b460a6247856a1c4eb3cbb50af09382 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 5 Oct 2018 19:38:19 +0000 Subject: =?UTF-8?q?Introduces=20new=20validity=20rule=20(gh-11):=20check?= =?UTF-8?q?=20input-time=20is=20valid=20regarding=20time-zone=20conversion?= =?UTF-8?q?=20inside=20the=20time-zone=20ranges=20(not=20in=20DST-hole);?= =?UTF-8?q?=20ConvertLocalToUTC/ConvertUTCToLocal=20rewritten=20to=20use?= =?UTF-8?q?=20common=20cache=20(and=20ConvertLocalToUTC=20invalidates=20th?= =?UTF-8?q?e=20local=20seconds,=20if=20it=20was=20outside=20the=20time-zon?= =?UTF-8?q?e=20ranges=20during=20conversion);=20Bonus:=20improves=20perfor?= =?UTF-8?q?mance=20of=20the=20involved=20cache=20by=20time-zone=20conversi?= =?UTF-8?q?ons=20(if=20more=20as=201=20TZ),=20see=20both=20performance=20t?= =?UTF-8?q?est-cases=20"Convert=20TZ:=20direct":=20(1.3=C2=B5s=20vs.=201.7?= =?UTF-8?q?=C2=B5s=20previously)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generic/tclClock.c | 282 ++++++++++++++++++++++++++++++----------------------- generic/tclDate.h | 43 ++++---- 2 files changed, 179 insertions(+), 146 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index dba98fd..dfa760c 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -262,9 +262,8 @@ TclClockInit( data->prevUsedLocaleDict = NULL; data->lastBase.timezoneObj = NULL; - data->utc2local.timezoneObj = NULL; - data->utc2local.tzName = NULL; - data->local2utc.timezoneObj = NULL; + + memset(&data->lastTZOffsCache, 0, sizeof(data->lastTZOffsCache)); data->defFlags = 0; @@ -337,9 +336,11 @@ ClockConfigureClear( data->prevUsedLocaleDict = NULL; Tcl_UnsetObjRef(data->lastBase.timezoneObj); - Tcl_UnsetObjRef(data->utc2local.timezoneObj); - Tcl_UnsetObjRef(data->utc2local.tzName); - Tcl_UnsetObjRef(data->local2utc.timezoneObj); + + Tcl_UnsetObjRef(data->lastTZOffsCache[0].timezoneObj); + Tcl_UnsetObjRef(data->lastTZOffsCache[0].tzName); + Tcl_UnsetObjRef(data->lastTZOffsCache[1].timezoneObj); + Tcl_UnsetObjRef(data->lastTZOffsCache[1].tzName); Tcl_UnsetObjRef(data->mcDicts); } @@ -1869,6 +1870,7 @@ ConvertLocalToUTC( int rowc; /* Number of rows in tzdata */ Tcl_Obj **rowv; /* Pointers to the rows */ Tcl_WideInt seconds; + ClockLastTZOffs * ltzoc = NULL; /* fast phase-out for shared GMT-object (don't need to convert UTC 2 UTC) */ if (timezoneObj == dataPtr->literals[LIT_GMT]) { @@ -1879,38 +1881,30 @@ ConvertLocalToUTC( /* * Check cacheable conversion could be used - * (last-period Local2UTC cache within the same TZ) + * (last-period UTC2Local cache within the same TZ and seconds) */ - seconds = fields->localSeconds - dataPtr->local2utc.tzOffset; - if ( timezoneObj == dataPtr->local2utc.timezoneObj - && ( fields->localSeconds == dataPtr->local2utc.localSeconds - || ( seconds >= dataPtr->local2utc.rangesVal[0] - && seconds < dataPtr->local2utc.rangesVal[1]) - ) - && changeover == dataPtr->local2utc.changeover - ) { - /* the same time zone and offset (UTC time inside the last minute) */ - fields->tzOffset = dataPtr->local2utc.tzOffset; - fields->seconds = seconds; - return TCL_OK; - } - - /* - * Check cacheable back-conversion could be used - * (last-period UTC2Local cache within the same TZ) - */ - seconds = fields->localSeconds - dataPtr->utc2local.tzOffset; - if ( timezoneObj == dataPtr->utc2local.timezoneObj - && ( seconds == dataPtr->utc2local.seconds - || ( seconds >= dataPtr->utc2local.rangesVal[0] - && seconds < dataPtr->utc2local.rangesVal[1]) - ) - && changeover == dataPtr->utc2local.changeover - ) { - /* the same time zone and offset (UTC time inside the last minute) */ - fields->tzOffset = dataPtr->utc2local.tzOffset; - fields->seconds = seconds; - return TCL_OK; + for (rowc = 0; rowc < 2; rowc++) { + ltzoc = &dataPtr->lastTZOffsCache[rowc]; + if (timezoneObj != ltzoc->timezoneObj || changeover != ltzoc->changeover) { + ltzoc = NULL; + continue; + } + seconds = fields->localSeconds - ltzoc->tzOffset; + if ( seconds >= ltzoc->rangesVal[0] + && seconds < ltzoc->rangesVal[1] + ) { + /* the same time zone and offset (UTC time inside the last minute) */ + fields->tzOffset = ltzoc->tzOffset; + fields->seconds = seconds; + return TCL_OK; + } + /* in the DST-hole (because of the check above) - correct localSeconds */ + if (fields->localSeconds == ltzoc->localSeconds) { + /* the same time zone and offset (but we'll shift local-time) */ + fields->tzOffset = ltzoc->tzOffset; + fields->seconds = seconds; + goto dstHole; + } } /* @@ -1932,25 +1926,58 @@ ConvertLocalToUTC( */ if (rowc == 0) { - dataPtr->local2utc.rangesVal[0] = 0; - dataPtr->local2utc.rangesVal[1] = 0; if (ConvertLocalToUTCUsingC(interp, fields, changeover) != TCL_OK) { return TCL_ERROR; }; + + /* we cannot cache (ranges unknown yet) - todo: check later the DST-hole here */ + return TCL_OK; + } else { + Tcl_WideInt rangesVal[2]; + if (ConvertLocalToUTCUsingTable(interp, fields, rowc, rowv, - dataPtr->local2utc.rangesVal) != TCL_OK) { + rangesVal) != TCL_OK) { return TCL_ERROR; }; - } - /* Cache the last conversion */ - Tcl_SetObjRef(dataPtr->local2utc.timezoneObj, timezoneObj); - dataPtr->local2utc.localSeconds = fields->localSeconds; - dataPtr->local2utc.changeover = changeover; - dataPtr->local2utc.tzOffset = fields->tzOffset; + seconds = fields->seconds; + /* Cache the last conversion */ + if (ltzoc != NULL) { /* slot was found above */ + /* timezoneObj and changeover are the same */ + Tcl_SetObjRef(ltzoc->tzName, fields->tzName); /* may be NULL */ + } else { + /* no TZ in cache - just move second slot down and use the first one */ + ltzoc = &dataPtr->lastTZOffsCache[0]; + Tcl_UnsetObjRef(dataPtr->lastTZOffsCache[1].timezoneObj); + Tcl_UnsetObjRef(dataPtr->lastTZOffsCache[1].tzName); + memcpy(&dataPtr->lastTZOffsCache[1], ltzoc, sizeof(*ltzoc)); + Tcl_InitObjRef(ltzoc->timezoneObj, timezoneObj); + ltzoc->changeover = changeover; + Tcl_InitObjRef(ltzoc->tzName, fields->tzName); /* may be NULL */ + } + ltzoc->localSeconds = fields->localSeconds; + ltzoc->rangesVal[0] = rangesVal[0]; + ltzoc->rangesVal[1] = rangesVal[1]; + ltzoc->tzOffset = fields->tzOffset; + } + + + /* check DST-hole: if retrieved seconds is out of range */ + if ( ltzoc->rangesVal[0] > seconds || seconds >= ltzoc->rangesVal[1] ) { + dstHole: + #if 0 + printf("given local-time is outside the time-zone (in DST-hole): " + "%d - offs %d => %d <= %d < %d\n", + (int)fields->localSeconds, fields->tzOffset, + (int)ltzoc->rangesVal[0], (int)seconds, (int)ltzoc->rangesVal[1]); + #endif + /* because we don't know real TZ (we're outsize), just invalidate local + * time (which could be verified in ClockValidDate later) */ + fields->localSeconds = TCL_INV_SECONDS; /* not valid seconds */ + } return TCL_OK; } @@ -1983,10 +2010,12 @@ ConvertLocalToUTCUsingTable( Tcl_Obj *row; int cellc; Tcl_Obj **cellv; - int have[8]; + struct { + Tcl_Obj *tzName; + int tzOffset; + } have[8]; int nHave = 0; int i; - int found; /* * Perform an initial lookup assuming that local == UTC, and locate the @@ -1998,10 +2027,9 @@ ConvertLocalToUTCUsingTable( * Saving Time transition. */ - found = 0; fields->tzOffset = 0; fields->seconds = fields->localSeconds; - while (!found) { + while (1) { row = LookupLastTransition(interp, fields->seconds, rowc, rowv, rangesVal); if ((row == NULL) @@ -2011,57 +2039,23 @@ ConvertLocalToUTCUsingTable( &fields->tzOffset) != TCL_OK) { return TCL_ERROR; } - found = 0; - for (i = 0; !found && i < nHave; ++i) { - if (have[i] == fields->tzOffset) { - found = 1; - break; + for (i = 0; i < nHave; ++i) { + if (have[i].tzOffset == fields->tzOffset) { + goto found; } } - if (!found) { - if (nHave == 8) { - Tcl_Panic("loop in ConvertLocalToUTCUsingTable"); - } - have[nHave++] = fields->tzOffset; + if (nHave == 8) { + Tcl_Panic("loop in ConvertLocalToUTCUsingTable"); } + have[nHave].tzName = cellv[3]; + have[nHave++].tzOffset = fields->tzOffset; fields->seconds = fields->localSeconds - fields->tzOffset; } - fields->tzOffset = have[i]; - fields->seconds = fields->localSeconds - fields->tzOffset; -#if 0 - /* currently unused, test purposes only */ - /* - * Convert back from UTC, if local times are different - wrong local time - * (local time seems to be in between DST-hole). - */ - if (fields->tzOffset) { - - int corrOffset; - Tcl_WideInt backCompVal; - /* check DST-hole interval contains UTC time */ - TclGetWideIntFromObj(NULL, cellv[0], &backCompVal); - if ( fields->seconds >= backCompVal - fields->tzOffset - && fields->seconds <= backCompVal + fields->tzOffset - ) { - row = LookupLastTransition(interp, fields->seconds, rowc, rowv); - if (row == NULL || - TclListObjGetElements(interp, row, &cellc, &cellv) != TCL_OK || - TclGetIntFromObj(interp, cellv[1], &corrOffset) != TCL_OK) { - return TCL_ERROR; - } - if (fields->localSeconds != fields->seconds + corrOffset) { - Tcl_Panic("wrong local time %ld by LocalToUTC conversion," - " local time seems to be in between DST-hole", - fields->localSeconds); - /* correcting offset * / - fields->tzOffset -= corrOffset; - fields->seconds += fields->tzOffset; - */ - } - } - } -#endif + found: + fields->tzOffset = have[i].tzOffset; + fields->seconds = fields->localSeconds - fields->tzOffset; + Tcl_SetObjRef(fields->tzName, have[i].tzName); return TCL_OK; } @@ -2176,6 +2170,7 @@ ConvertUTCToLocal( Tcl_Obj *tzdata; /* Time zone data */ int rowc; /* Number of rows in tzdata */ Tcl_Obj **rowv; /* Pointers to the rows */ + ClockLastTZOffs * ltzoc = NULL; /* fast phase-out for shared GMT-object (don't need to convert UTC 2 UTC) */ if (timezoneObj == dataPtr->literals[LIT_GMT]) { @@ -2196,20 +2191,23 @@ ConvertUTCToLocal( /* * Check cacheable conversion could be used - * (last-period UTC2Local cache within the same TZ) + * (last-period UTC2Local cache within the same TZ and seconds) */ - if ( timezoneObj == dataPtr->utc2local.timezoneObj - && ( fields->seconds == dataPtr->utc2local.seconds - || ( fields->seconds >= dataPtr->utc2local.rangesVal[0] - && fields->seconds < dataPtr->utc2local.rangesVal[1]) - ) - && changeover == dataPtr->utc2local.changeover - ) { - /* the same time zone and offset (UTC time inside the last minute) */ - Tcl_SetObjRef(fields->tzName, dataPtr->utc2local.tzName); - fields->tzOffset = dataPtr->utc2local.tzOffset; - fields->localSeconds = fields->seconds + fields->tzOffset; - return TCL_OK; + for (rowc = 0; rowc < 2; rowc++) { + ltzoc = &dataPtr->lastTZOffsCache[rowc]; + if (timezoneObj != ltzoc->timezoneObj || changeover != ltzoc->changeover) { + ltzoc = NULL; + continue; + } + if ( fields->seconds >= ltzoc->rangesVal[0] + && fields->seconds < ltzoc->rangesVal[1] + ) { + /* the same time zone and offset (UTC time inside the last minute) */ + fields->tzOffset = ltzoc->tzOffset; + fields->localSeconds = fields->seconds + fields->tzOffset; + Tcl_SetObjRef(fields->tzName, ltzoc->tzName); + return TCL_OK; + } } /* @@ -2231,25 +2229,40 @@ ConvertUTCToLocal( */ if (rowc == 0) { - dataPtr->utc2local.rangesVal[0] = 0; - dataPtr->utc2local.rangesVal[1] = 0; if (ConvertUTCToLocalUsingC(interp, fields, changeover) != TCL_OK) { return TCL_ERROR; } + + /* we cannot cache (ranges unknown yet) */ } else { + Tcl_WideInt rangesVal[2]; + if (ConvertUTCToLocalUsingTable(interp, fields, rowc, rowv, - dataPtr->utc2local.rangesVal) != TCL_OK) { + rangesVal) != TCL_OK) { return TCL_ERROR; } + + /* Cache the last conversion */ + if (ltzoc != NULL) { /* slot was found above */ + /* timezoneObj and changeover are the same */ + Tcl_SetObjRef(ltzoc->tzName, fields->tzName); + } else { + /* no TZ in cache - just move second slot down and use the first one */ + ltzoc = &dataPtr->lastTZOffsCache[0]; + Tcl_UnsetObjRef(dataPtr->lastTZOffsCache[1].timezoneObj); + Tcl_UnsetObjRef(dataPtr->lastTZOffsCache[1].tzName); + memcpy(&dataPtr->lastTZOffsCache[1], ltzoc, sizeof(*ltzoc)); + Tcl_InitObjRef(ltzoc->timezoneObj, timezoneObj); + ltzoc->changeover = changeover; + Tcl_InitObjRef(ltzoc->tzName, fields->tzName); + } + ltzoc->localSeconds = fields->localSeconds; + ltzoc->rangesVal[0] = rangesVal[0]; + ltzoc->rangesVal[1] = rangesVal[1]; + ltzoc->tzOffset = fields->tzOffset; } - /* Cache the last conversion */ - Tcl_SetObjRef(dataPtr->utc2local.timezoneObj, timezoneObj); - dataPtr->utc2local.seconds = fields->seconds; - dataPtr->utc2local.changeover = changeover; - dataPtr->utc2local.tzOffset = fields->tzOffset; - Tcl_SetObjRef(dataPtr->utc2local.tzName, fields->tzName); return TCL_OK; } @@ -2421,7 +2434,7 @@ LookupLastTransition( int l = 0; int u; Tcl_Obj *compObj; - Tcl_WideInt compVal, fromVal = tick, toVal = tick; + Tcl_WideInt compVal, fromVal = LLONG_MIN, toVal = LLONG_MAX; /* * Examine the first row to make sure we're in bounds. @@ -2437,7 +2450,7 @@ LookupLastTransition( * anyway. */ - if (tick < compVal) { + if (tick < (fromVal = compVal)) { if (rangesVal) { rangesVal[0] = fromVal; rangesVal[1] = toVal; @@ -3422,7 +3435,7 @@ ClockParseFmtScnArgs( */ if ( baseObj->typePtr == &tclBignumType - || baseVal < -0x00F0000000000000L || baseVal > 0x00F0000000000000L + || baseVal < TCL_MIN_SECONDS || baseVal > TCL_MAX_SECONDS ) { Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]); return TCL_ERROR; @@ -3760,8 +3773,15 @@ ClockValidDate( const char *errMsg = "", *errCode = ""; TclDateFields temp; int tempCpyFlg = 0; + ClockClientData *dataPtr = opts->clientData; - // printf("yyMonth %d, yyDay %d, yyDayOfYear %d, yyHour %d, yyMinutes %d, yySeconds %d\n", yyMonth, yyDay, yydate.dayOfYear, yyHour, yyMinutes, yySeconds); + #if 0 + printf("yyMonth %d, yyDay %d, yyDayOfYear %d, yyHour %d, yyMinutes %d, yySeconds %d, " + "yySecondOfDay %d, sec %d, daySec %d, tzOffset %d\n", + yyMonth, yyDay, yydate.dayOfYear, yyHour, yyMinutes, yySeconds, + yySecondOfDay, (int)yydate.localSeconds, (int)(yydate.localSeconds % SECONDS_PER_DAY), + yydate.tzOffset); + #endif if (!(stage & 1)) { goto stage_2; @@ -3769,8 +3789,6 @@ ClockValidDate( /* first year (used later in hath / daysInPriorMonths) */ if ((info->flags & (CLF_YEAR|CLF_ISO8601YEAR)) || yyHaveDate) { - ClockClientData *dataPtr = opts->clientData; - if ((info->flags & CLF_ISO8601YEAR)) { if ( yydate.iso8601Year < dataPtr->validMinYear || yydate.iso8601Year > dataPtr->validMaxYear ) { @@ -3853,10 +3871,26 @@ ClockValidDate( } /* - * Further tests expected ready calculated julianDay (inclusive relative) + * Further tests expected ready calculated julianDay (inclusive relative), + * and time-zone conversion (local to UTC time). */ stage_2: + /* time, regarding the modifications by the time-zone (looks for given time + * in between DST-time hole, so does not exist in this time-zone) */ + if (((info->flags & CLF_TIME) || yyHaveTime)) { + /* + * we don't need to do the backwards time-conversion (UTC to local) and + * compare results, because the after conversion (local to UTC) we + * should have valid localSeconds (was not invalidated to TCL_INV_SECONDS), + * so if it was invalidated - invalid time, outside the time-zone (in DST-hole) + */ + if ( yydate.localSeconds == TCL_INV_SECONDS ) { + errMsg = "invalid time (does not exist in this time-zone)"; + errCode = "out-of-time"; goto error; + } + } + /* day of week */ if (info->flags & CLF_DAYOFWEEK) { if (!tempCpyFlg) { diff --git a/generic/tclDate.h b/generic/tclDate.h index 1054b145..55eb331 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -56,6 +56,10 @@ CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | \ CLF_DAYOFWEEK | CLF_ISO8601WEAK) +#define TCL_MIN_SECONDS -0x00F0000000000000L +#define TCL_MAX_SECONDS 0x00F0000000000000L +#define TCL_INV_SECONDS (TCL_MIN_SECONDS-1) + /* * Enumeration of the string literals used in [clock] */ @@ -274,6 +278,18 @@ typedef struct ClockFmtScnCmdArgs { Tcl_Obj *mcDictObj; /* Current dictionary of tcl::clock package for given localeObj*/ } ClockFmtScnCmdArgs; +/* Last-period cache for fast UTC to local and backwards conversion */ +typedef struct ClockLastTZOffs { + /* keys */ + Tcl_Obj *timezoneObj; + int changeover; + Tcl_WideInt localSeconds; + Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */ + /* values */ + int tzOffset; + Tcl_Obj *tzName; /* Name (abbreviation) of this area in TZ */ +} ClockLastTZOffs; + /* * Structure containing the client data for [clock] */ @@ -294,6 +310,7 @@ typedef struct ClockClientData { int yearOfCenturySwitch; int validMinYear; int validMaxYear; + Tcl_Obj *systemTimeZone; Tcl_Obj *systemSetupTZData; Tcl_Obj *gmtSetupTimeZoneUnnorm; @@ -306,7 +323,7 @@ typedef struct ClockClientData { Tcl_Obj *prevSetupTimeZoneUnnorm; Tcl_Obj *prevSetupTimeZone; Tcl_Obj *prevSetupTZData; - + Tcl_Obj *defaultLocale; Tcl_Obj *defaultLocaleDict; Tcl_Obj *currentLocale; @@ -323,27 +340,9 @@ typedef struct ClockClientData { Tcl_Obj *timezoneObj; TclDateFields date; } lastBase; - /* Las-period cache for fast UTC2Local conversion */ - struct { - /* keys */ - Tcl_Obj *timezoneObj; - int changeover; - Tcl_WideInt seconds; - Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */ - /* values */ - int tzOffset; - Tcl_Obj *tzName; - } utc2local; - /* Las-period cache for fast local2utc conversion */ - struct { - /* keys */ - Tcl_Obj *timezoneObj; - int changeover; - Tcl_WideInt localSeconds; - Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */ - /* values */ - int tzOffset; - } local2utc; + + /* Last-period cache for fast UTC to Local and backwards conversion */ + ClockLastTZOffs lastTZOffsCache[2]; int defFlags; /* Default flags (from configure), ATM * only CLF_VALIDATE supported */ -- cgit v0.12 From 9931564ea5b0968f70fcf434405bb6712c82df73 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 8 Oct 2018 14:08:05 +0000 Subject: tclGetDate.y: added missing semicolon, tclDate.c rebuilt using Bison 3.1; resolves warning "maybe-uninitialized" by `*++yyvsp = yylval;` --- generic/tclDate.c | 1789 +++++++++++++++++++++++++------------------------- generic/tclGetDate.y | 4 +- 2 files changed, 894 insertions(+), 899 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index a48f5fa..165f911 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -1,20 +1,19 @@ -/* A Bison parser, made by GNU Bison 2.4.2. */ +/* A Bison parser, made by GNU Bison 3.1. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software - Foundation, Inc. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -27,7 +26,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -45,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.4.2" +#define YYBISON_VERSION "3.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -59,18 +58,14 @@ /* Pull parsers. */ #define YYPULL 1 -/* Using locations. */ -#define YYLSP_NEEDED 1 /* Substitute the variable and function names. */ #define yyparse TclDateparse #define yylex TclDatelex #define yyerror TclDateerror -#define yylval TclDatelval -#define yychar TclDatechar #define yydebug TclDatedebug #define yynerrs TclDatenerrs -#define yylloc TclDatelloc + /* Copy the first part of user declarations. */ @@ -149,10 +144,13 @@ typedef enum _DSTMODE { -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE @@ -162,44 +160,46 @@ typedef enum _DSTMODE { # define YYERROR_VERBOSE 0 #endif -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int TclDatedebug; +#endif -/* Tokens. */ +/* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - tAGO = 258, - tDAY = 259, - tDAYZONE = 260, - tID = 261, - tMERIDIAN = 262, - tMONTH = 263, - tMONTH_UNIT = 264, - tSTARDATE = 265, - tSEC_UNIT = 266, - tUNUMBER = 267, - tZONE = 268, - tZONEwO4 = 269, - tZONEwO2 = 270, - tEPOCH = 271, - tDST = 272, - tISOBASE = 273, - tDAY_UNIT = 274, - tNEXT = 275, - SP = 276 - }; + enum yytokentype + { + tAGO = 258, + tDAY = 259, + tDAYZONE = 260, + tID = 261, + tMERIDIAN = 262, + tMONTH = 263, + tMONTH_UNIT = 264, + tSTARDATE = 265, + tSEC_UNIT = 266, + tUNUMBER = 267, + tZONE = 268, + tZONEwO4 = 269, + tZONEwO2 = 270, + tEPOCH = 271, + tDST = 272, + tISOBASE = 273, + tDAY_UNIT = 274, + tNEXT = 275, + SP = 276 + }; #endif - - +/* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE + +union YYSTYPE { @@ -207,27 +207,33 @@ typedef union YYSTYPE enum _MERIDIAN Meridian; +}; -} YYSTYPE; +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif +/* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +}; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif + +int TclDateparse (DateInfo* info); + + + /* Copy the second part of user declarations. */ @@ -258,23 +264,20 @@ typedef unsigned char yytype_uint8; #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; #else -typedef short int yytype_int8; +typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else -typedef unsigned short int yytype_uint16; +typedef unsigned short yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else -typedef short int yytype_int16; +typedef short yytype_int16; #endif #ifndef YYSIZE_T @@ -282,12 +285,11 @@ typedef short int yytype_int16; # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else -# define YYSIZE_T unsigned int +# define YYSIZE_T unsigned # endif #endif @@ -297,39 +299,68 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ -# define YY_(msgid) msgid +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) +# define YYUSE(E) ((void) (E)) #else -# define YYUSE(e) /* empty */ +# define YYUSE(E) /* empty */ #endif -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") #else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int yyi) -#else -static int -YYID (yyi) - int yyi; +# define YY_INITIAL_VALUE(Value) Value #endif -{ - return yyi; -} +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif + #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ @@ -347,11 +378,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # endif @@ -359,8 +390,8 @@ YYID (yyi) # endif # ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely @@ -374,25 +405,23 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined _STDLIB_H \ +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) + && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +# if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif @@ -402,8 +431,8 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc @@ -422,42 +451,46 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif +# define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) #endif +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ @@ -469,17 +502,19 @@ union yyalloc #define YYNNTS 18 /* YYNRULES -- Number of rules. */ #define YYNRULES 66 -/* YYNRULES -- Number of states. */ +/* YYNSTATES -- Number of states. */ #define YYNSTATES 106 -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 276 -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) +#define YYTRANSLATE(YYX) \ + ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -513,47 +548,7 @@ static const yytype_uint8 yytranslate[] = }; #if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint8 yyprhs[] = -{ - 0, 0, 3, 4, 7, 11, 13, 15, 17, 19, - 21, 23, 25, 27, 29, 32, 37, 44, 47, 49, - 51, 55, 59, 62, 64, 67, 69, 72, 75, 80, - 84, 87, 91, 97, 99, 105, 111, 114, 119, 122, - 124, 128, 131, 135, 139, 142, 150, 158, 162, 167, - 170, 172, 177, 181, 184, 187, 191, 193, 195, 197, - 199, 201, 203, 205, 207, 209, 210 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 29, 0, -1, -1, 29, 30, -1, 29, 21, 30, - -1, 31, -1, 32, -1, 35, -1, 36, -1, 34, - -1, 39, -1, 37, -1, 38, -1, 44, -1, 12, - 7, -1, 12, 22, 12, 45, -1, 12, 22, 12, - 22, 12, 45, -1, 13, 17, -1, 13, -1, 5, - -1, 14, 41, 43, -1, 15, 41, 43, -1, 41, - 43, -1, 23, -1, 23, 21, -1, 4, -1, 4, - 33, -1, 12, 4, -1, 41, 21, 12, 4, -1, - 41, 12, 4, -1, 20, 4, -1, 12, 24, 12, - -1, 12, 24, 12, 24, 12, -1, 18, -1, 12, - 25, 8, 25, 12, -1, 12, 25, 12, 25, 12, - -1, 8, 12, -1, 8, 12, 33, 12, -1, 12, - 8, -1, 16, -1, 12, 8, 12, -1, 20, 8, - -1, 20, 12, 8, -1, 18, 13, 18, -1, 18, - 18, -1, 18, 21, 12, 22, 12, 22, 12, -1, - 18, 13, 12, 22, 12, 22, 12, -1, 18, 21, - 18, -1, 10, 43, 26, 12, -1, 40, 3, -1, - 40, -1, 41, 21, 43, 42, -1, 41, 43, 42, - -1, 43, 42, -1, 20, 42, -1, 20, 43, 42, - -1, 42, -1, 25, -1, 27, -1, 11, -1, 19, - -1, 9, -1, 12, -1, 18, -1, 43, -1, -1, - 7, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 160, 160, 161, 162, 165, 168, 171, 174, 177, @@ -566,7 +561,7 @@ static const yytype_uint16 yyrline[] = }; #endif -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +#if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -577,13 +572,13 @@ static const char *const yytname[] = "tISOBASE", "tDAY_UNIT", "tNEXT", "SP", "':'", "','", "'/'", "'-'", "'.'", "'+'", "$accept", "spec", "item", "time", "zone", "comma", "day", "date", "ordMonth", "iso", "trek", "relspec", "relunits", "sign", "unit", - "INTNUM", "number", "o_merid", 0 + "INTNUM", "number", "o_merid", YY_NULLPTR }; #endif # ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, @@ -592,58 +587,18 @@ static const yytype_uint16 yytoknum[] = }; # endif -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 28, 29, 29, 29, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, - 32, 32, 32, 33, 33, 34, 34, 34, 34, 34, - 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 36, 36, 37, 37, 37, 37, 37, 38, 39, - 39, 40, 40, 40, 40, 40, 40, 41, 41, 42, - 42, 42, 43, 43, 44, 45, 45 -}; +#define YYPACT_NINF -17 -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 4, 6, 2, 1, 1, - 3, 3, 2, 1, 2, 1, 2, 2, 4, 3, - 2, 3, 5, 1, 5, 5, 2, 4, 2, 1, - 3, 2, 3, 3, 2, 7, 7, 3, 4, 2, - 1, 4, 3, 2, 2, 3, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1 -}; +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-17))) -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 2, 0, 1, 25, 19, 0, 61, 0, 59, 62, - 18, 0, 0, 39, 33, 60, 0, 0, 57, 58, - 3, 5, 6, 9, 7, 8, 11, 12, 10, 50, - 0, 56, 64, 13, 23, 26, 36, 62, 63, 0, - 27, 14, 38, 0, 0, 0, 17, 0, 0, 0, - 44, 0, 30, 41, 62, 54, 0, 4, 49, 62, - 0, 22, 53, 24, 0, 0, 40, 65, 31, 0, - 0, 20, 21, 0, 43, 0, 47, 42, 55, 29, - 62, 0, 52, 37, 48, 66, 0, 15, 0, 0, - 0, 0, 0, 28, 51, 65, 32, 34, 35, 0, - 0, 16, 0, 0, 46, 45 -}; +#define YYTABLE_NINF -1 -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int8 yydefgoto[] = -{ - -1, 1, 20, 21, 22, 35, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 87 -}; +#define yytable_value_is_error(Yytable_value) \ + 0 -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -17 + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ static const yytype_int8 yypact[] = { -17, 48, -17, -9, -17, 34, -17, 19, -17, -2, @@ -659,18 +614,41 @@ static const yytype_int8 yypact[] = 88, -17, 99, 100, -17, -17 }; -/* YYPGOTO[NTERM-NUM]. */ + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 25, 19, 0, 61, 0, 59, 62, + 18, 0, 0, 39, 33, 60, 0, 0, 57, 58, + 3, 5, 6, 9, 7, 8, 11, 12, 10, 50, + 0, 56, 64, 13, 23, 26, 36, 62, 63, 0, + 27, 14, 38, 0, 0, 0, 17, 0, 0, 0, + 44, 0, 30, 41, 62, 54, 0, 4, 49, 62, + 0, 22, 53, 24, 0, 0, 40, 65, 31, 0, + 0, 20, 21, 0, 43, 0, 47, 42, 55, 29, + 62, 0, 52, 37, 48, 66, 0, 15, 0, 0, + 0, 0, 0, 28, 51, 65, 32, 34, 35, 0, + 0, 16, 0, 0, 46, 45 +}; + + /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -17, -17, 96, -17, -17, 79, -17, -17, -17, -17, -17, -17, -17, 22, -16, -6, -17, 21 }; -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 1, 20, 21, 22, 35, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 87 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { 55, 39, 40, 69, 52, 41, 42, 70, 53, 6, @@ -703,8 +681,8 @@ static const yytype_int8 yycheck[] = 22, 12, 12, 17, -1, 36, 95 }; -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 29, 0, 4, 5, 8, 9, 10, 11, 12, @@ -720,80 +698,106 @@ static const yytype_uint8 yystos[] = 12, 45, 22, 22, 12, 12 }; -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ - -#define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 28, 29, 29, 29, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, + 32, 32, 32, 33, 33, 34, 34, 34, 34, 34, + 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 36, 36, 37, 37, 37, 37, 37, 38, 39, + 39, 40, 40, 40, 40, 40, 40, 41, 41, 42, + 42, 42, 43, 43, 44, 45, 45 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 4, 6, 2, 1, 1, + 3, 3, 2, 1, 2, 1, 2, 2, 4, 3, + 2, 3, 5, 1, 5, 5, 2, 4, 2, 1, + 3, 2, 3, 3, 2, 7, 7, 3, 4, 2, + 1, 4, 3, 2, 2, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ yyerror (&yylloc, info, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - + YYERROR; \ + } \ +while (0) -#define YYTERROR 1 -#define YYERRCODE 256 +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) #endif +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know @@ -801,84 +805,74 @@ while (YYID (0)) #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ -#ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -#else -# define YYLEX yylex (&yylval, &yylloc, info) -#endif +YY_ATTRIBUTE_UNUSED +static unsigned +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + unsigned res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; + } -/* Enable debugging if requested. */ -#if YYDEBUG +# define YY_LOCATION_PRINT(File, Loc) \ + yy_location_print_ (File, &(Loc)) -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif +#endif -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, Location, info); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, info); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, info) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; - DateInfo* info; -#endif { - if (!yyvaluep) - return; + FILE *yyo = yyoutput; + YYUSE (yyo); YYUSE (yylocationp); YYUSE (info); + if (!yyvaluep) + return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); # endif - switch (yytype) - { - default: - break; - } + YYUSE (yytype); } @@ -886,24 +880,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, info) | Print this symbol on YYOUTPUT. | `--------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, info) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; - DateInfo* info; -#endif { - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); @@ -916,16 +897,8 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, info) | TOP (included). | `------------------------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -#else -static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; -#endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) @@ -936,51 +909,42 @@ yy_stack_print (yybottom, yytop) YYFPRINTF (stderr, "\n"); } -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void -yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, DateInfo* info) -#else -static void -yy_reduce_print (yyvsp, yylsp, yyrule, info) - YYSTYPE *yyvsp; - YYLTYPE *yylsp; - int yyrule; - DateInfo* info; -#endif +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, DateInfo* info) { + unsigned long yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; - unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); + yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , &(yylsp[(yyi + 1) - (yynrhs)]) , info); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , info); YYFPRINTF (stderr, "\n"); } } -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, yylsp, Rule, info); \ -} while (YYID (0)) +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule, info); \ +} while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ @@ -994,7 +958,7 @@ int yydebug; /* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH +#ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif @@ -1009,7 +973,6 @@ int yydebug; # define YYMAXDEPTH 10000 #endif - #if YYERROR_VERBOSE @@ -1018,15 +981,8 @@ int yydebug; # define yystrlen strlen # else /* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) @@ -1042,16 +998,8 @@ yystrlen (yystr) # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif { char *yyd = yydest; const char *yys = yysrc; @@ -1081,27 +1029,27 @@ yytnamerr (char *yyres, const char *yystr) char const *yyp = yystr; for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } do_not_strip_quotes: ; } @@ -1112,204 +1060,189 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) { - int yyn = yypact[yystate]; + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; } #endif /* YYERROR_VERBOSE */ - /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, DateInfo* info) -#else -static void -yydestruct (yymsg, yytype, yyvaluep, yylocationp, info) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; - YYLTYPE *yylocationp; - DateInfo* info; -#endif { YYUSE (yyvaluep); YYUSE (yylocationp); YYUSE (info); - if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - switch (yytype) - { - - default: - break; - } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (DateInfo* info); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - -/*-------------------------. -| yyparse or yypush_parse. | -`-------------------------*/ +/*----------. +| yyparse. | +`----------*/ -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) int yyparse (DateInfo* info) -#else -int -yyparse (info) - DateInfo* info; -#endif -#endif { /* The lookahead symbol. */ int yychar; + /* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Location data for the lookahead symbol. */ -YYLTYPE yylloc; +static YYLTYPE yyloc_default +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs; @@ -1319,11 +1252,11 @@ YYLTYPE yylloc; int yyerrstatus; /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - `yyls': related to locations. + 'yyss': related to states. + 'yyvs': related to semantic values. + 'yyls': related to locations. - Refer to the stacks thru separate pointers, to allow yyoverflow + Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ @@ -1342,14 +1275,14 @@ YYLTYPE yylloc; YYLTYPE *yylsp; /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[2]; + YYLTYPE yyerror_range[3]; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ - int yytoken; + int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; @@ -1368,10 +1301,9 @@ YYLTYPE yylloc; Keep to zero when no symbol should be popped. */ int yylen = 0; - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yyls = yylsa; + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yylsp = yyls = yylsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); @@ -1380,21 +1312,7 @@ YYLTYPE yylloc; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - yylsp = yyls; - -#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - /* Initialize the default location before parsing starts. */ - yylloc.first_line = yylloc.last_line = 1; - yylloc.first_column = yylloc.last_column = 1; -#endif - + yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. @@ -1415,26 +1333,26 @@ YYLTYPE yylloc; #ifdef yyoverflow { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - - yyls = yyls1; - yyss = yyss1; - yyvs = yyvs1; + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE @@ -1442,23 +1360,23 @@ YYLTYPE yylloc; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; + yystacksize = YYMAXDEPTH; { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ @@ -1468,10 +1386,10 @@ YYLTYPE yylloc; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); + (unsigned long) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) - YYABORT; + YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); @@ -1491,7 +1409,7 @@ yybackup: /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) + if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ @@ -1500,7 +1418,7 @@ yybackup: if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; + yychar = yylex (&yylval, &yylloc, info); } if (yychar <= YYEOF) @@ -1522,8 +1440,8 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; + if (yytable_value_is_error (yyn)) + goto yyerrlab; yyn = -yyn; goto yyreduce; } @@ -1540,7 +1458,9 @@ yybackup: yychar = YYEMPTY; yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; goto yynewstate; @@ -1563,7 +1483,7 @@ yyreduce: yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. + '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison @@ -1572,8 +1492,9 @@ yyreduce: GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; - /* Default location. */ + /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + yyerror_range[1] = yyloc; YY_REDUCE_PRINT (yyn); switch (yyn) { @@ -1581,42 +1502,48 @@ yyreduce: { yyHaveTime++; - ;} + } + break; case 6: { yyHaveZone++; - ;} + } + break; case 7: { yyHaveDate++; - ;} + } + break; case 8: { yyHaveOrdinalMonth++; - ;} + } + break; case 9: { yyHaveDay++; - ;} + } + break; case 10: { yyHaveRel++; - ;} + } + break; case 11: @@ -1624,7 +1551,8 @@ yyreduce: { yyHaveTime++; yyHaveDate++; - ;} + } + break; case 12: @@ -1633,208 +1561,232 @@ yyreduce: yyHaveTime++; yyHaveDate++; yyHaveRel++; - ;} + } + break; case 14: { - yyHour = (yyvsp[(1) - (2)].Number); + yyHour = (yyvsp[-1].Number); yyMinutes = 0; yySeconds = 0; - yyMeridian = (yyvsp[(2) - (2)].Meridian); - ;} + yyMeridian = (yyvsp[0].Meridian); + } + break; case 15: { - yyHour = (yyvsp[(1) - (4)].Number); - yyMinutes = (yyvsp[(3) - (4)].Number); + yyHour = (yyvsp[-3].Number); + yyMinutes = (yyvsp[-1].Number); yySeconds = 0; - yyMeridian = (yyvsp[(4) - (4)].Meridian); - ;} + yyMeridian = (yyvsp[0].Meridian); + } + break; case 16: { - yyHour = (yyvsp[(1) - (6)].Number); - yyMinutes = (yyvsp[(3) - (6)].Number); - yySeconds = (yyvsp[(5) - (6)].Number); - yyMeridian = (yyvsp[(6) - (6)].Meridian); - ;} + yyHour = (yyvsp[-5].Number); + yyMinutes = (yyvsp[-3].Number); + yySeconds = (yyvsp[-1].Number); + yyMeridian = (yyvsp[0].Meridian); + } + break; case 17: { - yyTimezone = (yyvsp[(1) - (2)].Number); + yyTimezone = (yyvsp[-1].Number); yyDSTmode = DSTon; - ;} + } + break; case 18: { - yyTimezone = (yyvsp[(1) - (1)].Number); + yyTimezone = (yyvsp[0].Number); yyDSTmode = DSToff; - ;} + } + break; case 19: { - yyTimezone = (yyvsp[(1) - (1)].Number); + yyTimezone = (yyvsp[0].Number); yyDSTmode = DSTon; - ;} + } + break; case 20: { /* GMT+0100, GMT-1000, etc. */ - yyTimezone = (yyvsp[(1) - (3)].Number) - (yyvsp[(2) - (3)].Number)*((yyvsp[(3) - (3)].Number) % 100 + ((yyvsp[(3) - (3)].Number) / 100) * 60); + yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); yyDSTmode = DSToff; - ;} + } + break; case 21: { /* GMT+1, GMT-10, etc. */ - yyTimezone = (yyvsp[(1) - (3)].Number) - (yyvsp[(2) - (3)].Number)*((yyvsp[(3) - (3)].Number) * 60); + yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) * 60); yyDSTmode = DSToff; - ;} + } + break; case 22: { /* +0100, -0100 */ - yyTimezone = -(yyvsp[(1) - (2)].Number)*((yyvsp[(2) - (2)].Number) % 100 + ((yyvsp[(2) - (2)].Number) / 100) * 60); + yyTimezone = -(yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); yyDSTmode = DSToff; - ;} + } + break; case 25: { yyDayOrdinal = 1; - yyDayOfWeek = (yyvsp[(1) - (1)].Number); + yyDayOfWeek = (yyvsp[0].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 26: { yyDayOrdinal = 1; - yyDayOfWeek = (yyvsp[(1) - (2)].Number); + yyDayOfWeek = (yyvsp[-1].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 27: { - yyDayOrdinal = (yyvsp[(1) - (2)].Number); - yyDayOfWeek = (yyvsp[(2) - (2)].Number); + yyDayOrdinal = (yyvsp[-1].Number); + yyDayOfWeek = (yyvsp[0].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 28: { - yyDayOrdinal = (yyvsp[(1) - (4)].Number) * (yyvsp[(3) - (4)].Number); - yyDayOfWeek = (yyvsp[(4) - (4)].Number); + yyDayOrdinal = (yyvsp[-3].Number) * (yyvsp[-1].Number); + yyDayOfWeek = (yyvsp[0].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 29: { - yyDayOrdinal = (yyvsp[(1) - (3)].Number) * (yyvsp[(2) - (3)].Number); - yyDayOfWeek = (yyvsp[(3) - (3)].Number); + yyDayOrdinal = (yyvsp[-2].Number) * (yyvsp[-1].Number); + yyDayOfWeek = (yyvsp[0].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 30: { yyDayOrdinal = 2; - yyDayOfWeek = (yyvsp[(2) - (2)].Number); + yyDayOfWeek = (yyvsp[0].Number); info->flags |= CLF_DAYOFWEEK; - ;} + } + break; case 31: { - yyMonth = (yyvsp[(1) - (3)].Number); - yyDay = (yyvsp[(3) - (3)].Number); - ;} + yyMonth = (yyvsp[-2].Number); + yyDay = (yyvsp[0].Number); + } + break; case 32: { - yyMonth = (yyvsp[(1) - (5)].Number); - yyDay = (yyvsp[(3) - (5)].Number); - yyYear = (yyvsp[(5) - (5)].Number); - ;} + yyMonth = (yyvsp[-4].Number); + yyDay = (yyvsp[-2].Number); + yyYear = (yyvsp[0].Number); + } + break; case 33: { - yyYear = (yyvsp[(1) - (1)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (1)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (1)].Number) % 100; - ;} + yyYear = (yyvsp[0].Number) / 10000; + yyMonth = ((yyvsp[0].Number) % 10000)/100; + yyDay = (yyvsp[0].Number) % 100; + } + break; case 34: { - yyDay = (yyvsp[(1) - (5)].Number); - yyMonth = (yyvsp[(3) - (5)].Number); - yyYear = (yyvsp[(5) - (5)].Number); - ;} + yyDay = (yyvsp[-4].Number); + yyMonth = (yyvsp[-2].Number); + yyYear = (yyvsp[0].Number); + } + break; case 35: { - yyMonth = (yyvsp[(3) - (5)].Number); - yyDay = (yyvsp[(5) - (5)].Number); - yyYear = (yyvsp[(1) - (5)].Number); - ;} + yyMonth = (yyvsp[-2].Number); + yyDay = (yyvsp[0].Number); + yyYear = (yyvsp[-4].Number); + } + break; case 36: { - yyMonth = (yyvsp[(1) - (2)].Number); - yyDay = (yyvsp[(2) - (2)].Number); - ;} + yyMonth = (yyvsp[-1].Number); + yyDay = (yyvsp[0].Number); + } + break; case 37: { - yyMonth = (yyvsp[(1) - (4)].Number); - yyDay = (yyvsp[(2) - (4)].Number); - yyYear = (yyvsp[(4) - (4)].Number); - ;} + yyMonth = (yyvsp[-3].Number); + yyDay = (yyvsp[-2].Number); + yyYear = (yyvsp[0].Number); + } + break; case 38: { - yyMonth = (yyvsp[(2) - (2)].Number); - yyDay = (yyvsp[(1) - (2)].Number); - ;} + yyMonth = (yyvsp[0].Number); + yyDay = (yyvsp[-1].Number); + } + break; case 39: @@ -1843,94 +1795,103 @@ yyreduce: yyMonth = 1; yyDay = 1; yyYear = EPOCH; - ;} + } + break; case 40: { - yyMonth = (yyvsp[(2) - (3)].Number); - yyDay = (yyvsp[(1) - (3)].Number); - yyYear = (yyvsp[(3) - (3)].Number); - ;} + yyMonth = (yyvsp[-1].Number); + yyDay = (yyvsp[-2].Number); + yyYear = (yyvsp[0].Number); + } + break; case 41: { yyMonthOrdinalIncr = 1; - yyMonthOrdinal = (yyvsp[(2) - (2)].Number); - ;} + yyMonthOrdinal = (yyvsp[0].Number); + } + break; case 42: { - yyMonthOrdinalIncr = (yyvsp[(2) - (3)].Number); - yyMonthOrdinal = (yyvsp[(3) - (3)].Number); - ;} + yyMonthOrdinalIncr = (yyvsp[-1].Number); + yyMonthOrdinal = (yyvsp[0].Number); + } + break; case 43: { - if ((yyvsp[(2) - (3)].Number) != HOUR( 7)) YYABORT; /* T */ - yyYear = (yyvsp[(1) - (3)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (3)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (3)].Number) % 100; - yyHour = (yyvsp[(3) - (3)].Number) / 10000; - yyMinutes = ((yyvsp[(3) - (3)].Number) % 10000)/100; - yySeconds = (yyvsp[(3) - (3)].Number) % 100; - ;} + if ((yyvsp[-1].Number) != HOUR( 7)) YYABORT; /* T */ + yyYear = (yyvsp[-2].Number) / 10000; + yyMonth = ((yyvsp[-2].Number) % 10000)/100; + yyDay = (yyvsp[-2].Number) % 100; + yyHour = (yyvsp[0].Number) / 10000; + yyMinutes = ((yyvsp[0].Number) % 10000)/100; + yySeconds = (yyvsp[0].Number) % 100; + } + break; case 44: { - yyYear = (yyvsp[(1) - (2)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (2)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (2)].Number) % 100; - yyHour = (yyvsp[(2) - (2)].Number) / 10000; - yyMinutes = ((yyvsp[(2) - (2)].Number) % 10000)/100; - yySeconds = (yyvsp[(2) - (2)].Number) % 100; - ;} + yyYear = (yyvsp[-1].Number) / 10000; + yyMonth = ((yyvsp[-1].Number) % 10000)/100; + yyDay = (yyvsp[-1].Number) % 100; + yyHour = (yyvsp[0].Number) / 10000; + yyMinutes = ((yyvsp[0].Number) % 10000)/100; + yySeconds = (yyvsp[0].Number) % 100; + } + break; case 45: { - yyYear = (yyvsp[(1) - (7)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (7)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (7)].Number) % 100; - yyHour = (yyvsp[(3) - (7)].Number); - yyMinutes = (yyvsp[(5) - (7)].Number); - yySeconds = (yyvsp[(7) - (7)].Number); - ;} + yyYear = (yyvsp[-6].Number) / 10000; + yyMonth = ((yyvsp[-6].Number) % 10000)/100; + yyDay = (yyvsp[-6].Number) % 100; + yyHour = (yyvsp[-4].Number); + yyMinutes = (yyvsp[-2].Number); + yySeconds = (yyvsp[0].Number); + } + break; case 46: { - if ((yyvsp[(2) - (7)].Number) != HOUR( 7)) YYABORT; /* T */ - yyYear = (yyvsp[(1) - (7)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (7)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (7)].Number) % 100; - yyHour = (yyvsp[(3) - (7)].Number); - yyMinutes = (yyvsp[(5) - (7)].Number); - yySeconds = (yyvsp[(7) - (7)].Number); - ;} + if ((yyvsp[-5].Number) != HOUR( 7)) YYABORT; /* T */ + yyYear = (yyvsp[-6].Number) / 10000; + yyMonth = ((yyvsp[-6].Number) % 10000)/100; + yyDay = (yyvsp[-6].Number) % 100; + yyHour = (yyvsp[-4].Number); + yyMinutes = (yyvsp[-2].Number); + yySeconds = (yyvsp[0].Number); + } + break; case 47: { - yyYear = (yyvsp[(1) - (3)].Number) / 10000; - yyMonth = ((yyvsp[(1) - (3)].Number) % 10000)/100; - yyDay = (yyvsp[(1) - (3)].Number) % 100; - yyHour = (yyvsp[(3) - (3)].Number) / 10000; - yyMinutes = ((yyvsp[(3) - (3)].Number) % 10000)/100; - yySeconds = (yyvsp[(3) - (3)].Number) % 100; - ;} + yyYear = (yyvsp[-2].Number) / 10000; + yyMonth = ((yyvsp[-2].Number) % 10000)/100; + yyDay = (yyvsp[-2].Number) % 100; + yyHour = (yyvsp[0].Number) / 10000; + yyMinutes = ((yyvsp[0].Number) % 10000)/100; + yySeconds = (yyvsp[0].Number) % 100; + } + break; case 48: @@ -1941,12 +1902,13 @@ yyreduce: * in a range accessible with a 32 bit clock seconds value. */ - yyYear = (yyvsp[(2) - (4)].Number)/1000 + 2323 - 377; + yyYear = (yyvsp[-2].Number)/1000 + 2323 - 377; yyDay = 1; yyMonth = 1; - yyRelDay += (((yyvsp[(2) - (4)].Number)%1000)*(365 + IsLeapYear(yyYear)))/1000; - yyRelSeconds += (yyvsp[(4) - (4)].Number) * 144 * 60; - ;} + yyRelDay += (((yyvsp[-2].Number)%1000)*(365 + IsLeapYear(yyYear)))/1000; + yyRelSeconds += (yyvsp[0].Number) * 144 * 60; + } + break; case 49: @@ -1955,141 +1917,169 @@ yyreduce: yyRelSeconds *= -1; yyRelMonth *= -1; yyRelDay *= -1; - ;} + } + break; case 51: { - *yyRelPointer += (yyvsp[(1) - (4)].Number) * (yyvsp[(3) - (4)].Number) * (yyvsp[(4) - (4)].Number); - ;} + *yyRelPointer += (yyvsp[-3].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); + } + break; case 52: { - *yyRelPointer += (yyvsp[(1) - (3)].Number) * (yyvsp[(2) - (3)].Number) * (yyvsp[(3) - (3)].Number); - ;} + *yyRelPointer += (yyvsp[-2].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); + } + break; case 53: { - *yyRelPointer += (yyvsp[(1) - (2)].Number) * (yyvsp[(2) - (2)].Number); - ;} + *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); + } + break; case 54: { - *yyRelPointer += (yyvsp[(2) - (2)].Number); - ;} + *yyRelPointer += (yyvsp[0].Number); + } + break; case 55: { - *yyRelPointer += (yyvsp[(2) - (3)].Number) * (yyvsp[(3) - (3)].Number); - ;} + *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); + } + break; case 56: { - *yyRelPointer += (yyvsp[(1) - (1)].Number); - ;} + *yyRelPointer += (yyvsp[0].Number); + } + break; case 57: { (yyval.Number) = -1; - ;} + } + break; case 58: { (yyval.Number) = 1; - ;} + } + break; case 59: { - (yyval.Number) = (yyvsp[(1) - (1)].Number); + (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelSeconds; - ;} + } + break; case 60: { - (yyval.Number) = (yyvsp[(1) - (1)].Number); + (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelDay; - ;} + } + break; case 61: { - (yyval.Number) = (yyvsp[(1) - (1)].Number); + (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelMonth; - ;} + } + break; case 62: { - (yyval.Number) = (yyvsp[(1) - (1)].Number) - ;} + (yyval.Number) = (yyvsp[0].Number); + } + break; case 63: { - (yyval.Number) = (yyvsp[(1) - (1)].Number) - ;} + (yyval.Number) = (yyvsp[0].Number); + } + break; case 64: { if (yyHaveTime && yyHaveDate && !yyHaveRel) { - yyYear = (yyvsp[(1) - (1)].Number); + yyYear = (yyvsp[0].Number); } else { yyHaveTime++; if (yyDigitCount <= 2) { - yyHour = (yyvsp[(1) - (1)].Number); + yyHour = (yyvsp[0].Number); yyMinutes = 0; } else { - yyHour = (yyvsp[(1) - (1)].Number) / 100; - yyMinutes = (yyvsp[(1) - (1)].Number) % 100; + yyHour = (yyvsp[0].Number) / 100; + yyMinutes = (yyvsp[0].Number) % 100; } yySeconds = 0; yyMeridian = MER24; } - ;} + } + break; case 65: { (yyval.Meridian) = MER24; - ;} + } + break; case 66: { - (yyval.Meridian) = (yyvsp[(1) - (1)].Meridian); - ;} + (yyval.Meridian) = (yyvsp[0].Meridian); + } + break; default: break; } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -2099,7 +2089,7 @@ yyreduce: *++yyvsp = yyval; *++yylsp = yyloc; - /* Now `shift' the result of the reduction. Determine what state + /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -2114,10 +2104,14 @@ yyreduce: goto yynewstate; -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -2125,59 +2119,58 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (&yylloc, info, YY_("syntax error")); #else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (&yylloc, info, yymsg); - } - else - { - yyerror (&yylloc, info, YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (&yylloc, info, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; } +# undef YYSYNTAX_ERROR #endif } - yyerror_range[0] = yylloc; + yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an - error, discard it. */ + error, discard it. */ if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc, info); - yychar = YYEMPTY; - } + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, info); + yychar = YYEMPTY; + } } /* Else will try to reuse lookahead token after shifting the error @@ -2196,8 +2189,7 @@ yyerrorlab: if (/*CONSTCOND*/ 0) goto yyerrorlab; - yyerror_range[0] = yylsp[1-yylen]; - /* Do not reclaim the symbols of the rule which action triggered + /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; @@ -2210,40 +2202,42 @@ yyerrorlab: | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ + yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) - YYABORT; + YYABORT; - yyerror_range[0] = *yylsp; + yyerror_range[1] = *yylsp; yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp, info); + yystos[yystate], yyvsp, yylsp, info); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END - yyerror_range[1] = yylloc; + yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of the lookahead. YYLOC is available though. */ - YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + YYLLOC_DEFAULT (yyloc, yyerror_range, 2); *++yylsp = yyloc; /* Shift the error token. */ @@ -2267,7 +2261,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined(yyoverflow) || YYERROR_VERBOSE +#if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -2279,16 +2273,21 @@ yyexhaustedlab: yyreturn: if (yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc, info); - /* Do not reclaim the symbols of the rule which action triggered + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, info); + } + /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp, info); + yystos[*yyssp], yyvsp, yylsp, info); YYPOPSTACK (1); } #ifndef yyoverflow @@ -2299,13 +2298,10 @@ yyreturn: if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif - /* Make sure YYID is used. */ - return YYID (yyresult); + return yyresult; } - - /* * Month and day table. */ @@ -2902,4 +2898,3 @@ TclClockFreeScan( * fill-column: 78 * End: */ - diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 6aacf93..f25f45b 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -442,10 +442,10 @@ unit : tSEC_UNIT { ; INTNUM : tUNUMBER { - $$ = $1 + $$ = $1; } | tISOBASE { - $$ = $1 + $$ = $1; } ; -- cgit v0.12 From 68a780a3bf6f4754739c65c7776176bfaaf60cc5 Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 29 Nov 2018 20:04:42 +0000 Subject: clock scan: consider multiple spaces between tokens (closes tclclockmod#13): combine multiple white-spaces as single token in format. --- generic/tclClockFmt.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 51bac2f..d3ec8c1 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1862,11 +1862,10 @@ static const char *ScnOTokenMapAliasIndex[2] = { "dHHHu" }; -static const char *ScnSpecTokenMapIndex = - " "; -static ClockScanTokenMap ScnSpecTokenMap[] = { - {CTOKT_SPACE, 0, 0, 1, 1, 0, - NULL}, +/* Token map reserved for CTOKT_SPACE */ +static ClockScanTokenMap ScnSpaceTokenMap = { + CTOKT_SPACE, 0, 0, 1, 1, 0, + NULL, }; static ClockScanTokenMap ScnWordTokenMap = { @@ -2035,21 +2034,20 @@ ClockGetOrParseScanFormat( continue; } break; - case ' ': - cp = strchr(ScnSpecTokenMapIndex, *p); - if (!cp || *cp == '\0') { - p--; - goto word_tok; + default: + if ( *p == ' ' || isspace(UCHAR(*p)) ) { + tok->map = &ScnSpaceTokenMap; + tok->tokWord.start = p++; + while (p < e && isspace(UCHAR(*p))) { + p++; } - tok->map = &ScnSpecTokenMap[cp - ScnSpecTokenMapIndex]; + tok->tokWord.end = p; /* increase space count used in format */ fss->scnSpaceCount++; /* next token */ AllocTokenInChain(tok, scnTok, fss->scnTokC); tokCnt++; - p++; continue; - break; - default: + } word_tok: if (1) { ClockScanToken *wordTok = tok; -- cgit v0.12 From 577976dba721184f20b79b1ec1977b72ffe008f2 Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 29 Nov 2018 20:11:14 +0000 Subject: clock scan: consider extra trailing spaces at end of input (closes tclclockmod#14), only the first space at end is interesting in non-strict mode (should match SPACE token if present in scan-format) --- generic/tclClockFmt.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index d3ec8c1..3f47be9 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2149,14 +2149,18 @@ ClockScan( x = end; while (p < end) { if (isspace(UCHAR(*p))) { - x = p++; + x = ++p; /* after first space in space block */ yySpaceCount++; + while (p < end && isspace(UCHAR(*p))) { + p++; + yySpaceCount++; + } continue; } x = end; p++; } - /* ignore spaces at end */ + /* ignore more as 1 space at end */ yySpaceCount -= (end - x); end = x; /* ignore mandatory spaces used in format */ @@ -2245,9 +2249,10 @@ ClockScan( }; /* decrement count for possible spaces in match */ while (p < yyInput) { - if (isspace(UCHAR(*p++))) { + if (isspace(UCHAR(*p))) { yySpaceCount--; } + p++; } p = yyInput; flags = (flags & ~map->clearFlags) | map->flags; @@ -2258,7 +2263,8 @@ ClockScan( /* unmatched -> error */ goto not_match; } - yySpaceCount--; + /* don't decrement yySpaceCount by regular (first expected space), + * already considered above with fss->scnSpaceCount */; p++; while (p < end && isspace(UCHAR(*p))) { yySpaceCount--; @@ -2288,8 +2294,17 @@ ClockScan( } /* check end was reached */ if (p < end) { + /* in non-strict mode bypass spaces at end of input */ + if ( !(opts->flags & CLF_STRICT) && isspace(UCHAR(*p)) ) { + p++; + while (p < end && isspace(UCHAR(*p))) { + p++; + } + } /* something after last token - wrong format */ - goto not_match; + if (p < end) { + goto not_match; + } } /* end of string, check only optional tokens at end, otherwise - not match */ while (tok->map != NULL) { -- cgit v0.12 From a6482d22e22ee943e601d3105356593e141d333f Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 29 Nov 2018 20:12:45 +0000 Subject: test-cases: clock-45.* - new compatibility tests checking several scan regression on spaces --- tests/clock.test | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/clock.test b/tests/clock.test index 4e81c10..2b8c757 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36511,13 +36511,54 @@ test clock-44.1 {regression test - time zone name containing hyphen } \ } } \ -result {12:34:56-0500} - -test clock-45.1 {regression test - time zone containing only two digits} \ +test clock-44.2 {regression test - time zone containing only two digits} \ -body { clock scan 1985-04-12T10:15:30+04 -format %Y-%m-%dT%H:%M:%S%Z } \ -result 482134530 +test clock-45.1 {compat: scan regression on spaces (multiple spaces in format)} \ + -body { + list \ + [clock scan "11/08/2018 0612" -format "%m/%d/%Y %H%M" -gmt 1] \ + [clock scan "11/08/2018 0612" -format "%m/%d/%Y %H%M" -gmt 1] \ + [clock scan "11/08/2018 0612" -format "%m/%d/%Y %H%M" -gmt 1] \ + [clock scan " 11/08/2018 0612" -format " %m/%d/%Y %H%M" -gmt 1] \ + [clock scan " 11/08/2018 0612" -format " %m/%d/%Y %H%M" -gmt 1] \ + [clock scan " 11/08/2018 0612" -format " %m/%d/%Y %H%M" -gmt 1] \ + [clock scan "11/08/2018 0612 " -format "%m/%d/%Y %H%M " -gmt 1] \ + [clock scan "11/08/2018 0612 " -format "%m/%d/%Y %H%M " -gmt 1] \ + [clock scan "11/08/2018 0612 " -format "%m/%d/%Y %H%M " -gmt 1] + } -result [lrepeat 9 1541657520] + +test clock-45.2 {compat: scan regression on spaces (multiple leading/trailing spaces in input)} \ + -body { + set sp [string repeat " " 20] + list \ + [clock scan "NOV 7${sp}" -format "%b %d" -base 0 -gmt 1 -locale en] \ + [clock scan "${sp}NOV 7" -format "%b %d" -base 0 -gmt 1 -locale en] \ + [clock scan "${sp}NOV 7${sp}" -format "%b %d" -base 0 -gmt 1 -locale en] \ + [clock scan "1970 NOV 7${sp}" -format "%Y %b %d" -gmt 1 -locale en] \ + [clock scan "${sp}1970 NOV 7" -format "%Y %b %d" -gmt 1 -locale en] \ + [clock scan "${sp}1970 NOV 7${sp}" -format "%Y %b %d" -gmt 1 -locale en] + } -result [lrepeat 6 26784000] +test clock-45.3 {compat: scan regression on spaces (shortest match)} \ + -body { + list \ + [clock scan "11 1 120" -format "%y%m%d %H%M%S" -gmt 1] \ + [clock scan "11 1 120 " -format "%y%m%d %H%M%S" -gmt 1] \ + [clock scan " 11 1 120" -format "%y%m%d %H%M%S" -gmt 1] \ + [clock scan "11 1 120 " -format "%y%m%d %H%M%S " -gmt 1] \ + [clock scan " 11 1 120" -format " %y%m%d %H%M%S" -gmt 1] + } -result [lrepeat 5 978310920] +test clock-45.4 {compat: scan regression on spaces (mandatory leading/trailing spaces in format)} \ + -body { + list \ + [catch {clock scan "11 1 120" -format "%y%m%d %H%M%S " -gmt 1} ret] $ret \ + [catch {clock scan "11 1 120" -format " %y%m%d %H%M%S" -gmt 1} ret] $ret \ + [catch {clock scan "11 1 120" -format " %y%m%d %H%M%S " -gmt 1} ret] $ret + } -result [lrepeat 3 1 "input string does not match supplied format"] + test clock-46.1 {regression test - month zero} -constraints valid_off \ -body { clock scan 2004-00-00 -format %Y-%m-%d -- cgit v0.12 From 6855aaa7995a839003a7c5f9ccef342144897726 Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 29 Nov 2018 20:14:14 +0000 Subject: clock scan: compatibility - scan regression on spaces, mandatory trailing spaces in format, see test "clock-45.4" --- generic/tclClockFmt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 3f47be9..254936c 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2310,7 +2310,10 @@ ClockScan( while (tok->map != NULL) { if (!(opts->flags & CLF_STRICT) && (tok->map->type == CTOKT_SPACE)) { tok++; - if (tok->map == NULL) break; + if (tok->map == NULL) { + /* no tokens anymore - trailing spaces are mandatory */ + goto not_match; + } } if (!(tok->map->flags & CLF_OPTIONAL)) { goto not_match; -- cgit v0.12 From a4600a6847c0bd3f41f69d0446138d37063ef25b Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 10 Jan 2019 13:52:17 +0000 Subject: remove unneeded dependencies (taken along by pack-porting, not needed in mod now) --- generic/tclClock.c | 1 - 1 file changed, 1 deletion(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index dfa760c..e1c70e9 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -17,7 +17,6 @@ #include "tclInt.h" #include "tclStrIdxTree.h" #include "tclDate.h" -#include "tclCompile.h" /* * Windows has mktime. The configurators do not check. -- cgit v0.12 From 2aee61ea3055c9d7212040a402680c89b8df2a9e Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 10 Jan 2019 13:55:20 +0000 Subject: avoid possible leaking on tzName-object in error case (most impossible resp. rarely, but nevertheless better don't return directly). --- generic/tclClock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index e1c70e9..4389e16 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3634,7 +3634,8 @@ ClockScanObjCmd( Tcl_SetObjResult(interp, Tcl_NewStringObj("legacy [clock scan] does not support -locale", -1)); Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", NULL); - return TCL_ERROR; + ret = TCL_ERROR; + goto done; } ret = ClockFreeScan(&yy, objv[1], &opts); } @@ -3657,9 +3658,9 @@ ClockScanObjCmd( /* Apply validation rules, if expected */ if ( (opts.flags & CLF_VALIDATE) ) { - if (ClockValidDate(&yy, &opts, - opts.formatObj == NULL ? 2 : 3) != TCL_OK) { - return TCL_ERROR; + ret = ClockValidDate(&yy, &opts, opts.formatObj == NULL ? 2 : 3); + if (ret != TCL_OK) { + goto done; } } -- cgit v0.12 From 903f7ee3c92b0cc8622f2df23dd64de1dd27b302 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 25 Jan 2019 20:16:57 +0000 Subject: introduced new configure option `-max-jdn` corresponds current setting of tcl-core clock scans for JulianDay per default (5373484 = "9999-12-31 23:59:59") --- generic/tclClock.c | 27 ++++++++++++++++++++++----- generic/tclDate.h | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 4389e16..819f7fb 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -235,6 +235,7 @@ TclClockInit( data->yearOfCenturySwitch = ClockDefaultCenturySwitch; data->validMinYear = INT_MIN; data->validMaxYear = INT_MAX; + data->maxJulianDay = 5373484; /* corresponds 9999-12-31 23:59:59 per default */ data->systemTimeZone = NULL; data->systemSetupTZData = NULL; @@ -981,14 +982,14 @@ ClockConfigureObjCmd( "-system-tz", "-setup-tz", "-default-locale", "-current-locale", "-clear", "-year-century", "-century-switch", - "-min-year", "-max-year", "-validate", + "-min-year", "-max-year", "-max-jdn", "-validate", NULL }; enum optionInd { CLOCK_SYSTEM_TZ, CLOCK_SETUP_TZ, CLOCK_DEFAULT_LOCALE, CLOCK_CURRENT_LOCALE, CLOCK_CLEAR_CACHE, CLOCK_YEAR_CENTURY, CLOCK_CENTURY_SWITCH, - CLOCK_MIN_YEAR, CLOCK_MAX_YEAR, CLOCK_VALIDATE + CLOCK_MIN_YEAR, CLOCK_MAX_YEAR, CLOCK_MAX_JDN, CLOCK_VALIDATE }; int optionIndex; /* Index of an option. */ int i; @@ -1117,6 +1118,21 @@ ClockConfigureObjCmd( Tcl_NewIntObj(dataPtr->validMaxYear)); } break; + case CLOCK_MAX_JDN: + if (i < objc) { + Tcl_WideInt jd; + if (TclGetWideIntFromObj(interp, objv[i], &jd) != TCL_OK) { + return TCL_ERROR; + } + dataPtr->maxJulianDay = jd; + Tcl_SetObjResult(interp, objv[i]); + continue; + } + if (i+1 >= objc) { + Tcl_SetObjResult(interp, + Tcl_NewWideIntObj(dataPtr->maxJulianDay)); + } + break; case CLOCK_VALIDATE: if (i < objc) { int val; @@ -3715,9 +3731,10 @@ ClockScanCommit( info->flags &= ~CLF_ASSEMBLE_JULIANDAY; } - /* some overflow checks, if not extended */ - if (!(opts->flags & CLF_EXTENDED)) { - if (yydate.julianDay > 5373484) { + /* some overflow checks */ + if (info->flags & CLF_JULIANDAY) { + ClockClientData *dataPtr = opts->clientData; + if (yydate.julianDay > dataPtr->maxJulianDay) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( "requested date too large to represent", -1)); Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); diff --git a/generic/tclDate.h b/generic/tclDate.h index 55eb331..9aa031a 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -310,6 +310,7 @@ typedef struct ClockClientData { int yearOfCenturySwitch; int validMinYear; int validMaxYear; + Tcl_WideInt maxJulianDay; Tcl_Obj *systemTimeZone; Tcl_Obj *systemSetupTZData; -- cgit v0.12 From 7a2c96b4211c5695bcfab86f361225c409e801c9 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 25 Jan 2019 20:17:26 +0000 Subject: fix of _witoaw: adjustment of width for negative wide-int (conversion wide to string using `_witoaw(buf, -1, '0', 1)` caused mistakenly 10-chars padding). --- generic/tclClockFmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 254936c..f3ac90a 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -247,7 +247,7 @@ _witoaw( if (!width) width++; /* check resp. recalculate width (regarding sign) */ width--; - if (val <= 10000000000L) { + if (val <= -10000000000L) { Tcl_WideInt val2; val2 = val / 10000000000L; while (width <= 9 && val2 <= -wrange[width]) { -- cgit v0.12 From ec6bc3e8fc49444829d56dfd699dd84bd27331fc Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 25 Jan 2019 20:17:46 +0000 Subject: small optimization of format-proc tokens, that are don't use `val` in callback, as well as don't do the back-conversion from int to string (output inside fmtproc) - switch to CFMTT_PROC token type. --- generic/tclClockFmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index f3ac90a..b4d7b14 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2801,7 +2801,7 @@ static ClockFormatTokenMap FmtSTokenMap[] = { /* %V */ {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.iso8601Week), NULL}, /* %z %Z */ - {CTOKT_INT, NULL, 0, 0, 0, 0, 0, + {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, ClockFmtToken_TimeZone_Proc, NULL}, /* %g */ {CTOKT_INT, "0", 2, 0, 0, 100, TclOffset(DateFormat, date.iso8601Year), NULL}, @@ -2818,7 +2818,7 @@ static ClockFormatTokenMap FmtSTokenMap[] = { /* %t */ {CTOKT_CHAR, "\t", 0, 0, 0, 0, 0, NULL}, /* %Q */ - {CTOKT_INT, NULL, 0, 0, 0, 0, 0, + {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, ClockFmtToken_StarDate_Proc, NULL}, }; static const char *FmtSTokenMapAliasIndex[2] = { @@ -2830,7 +2830,7 @@ static const char *FmtETokenMapIndex = "Eys"; static ClockFormatTokenMap FmtETokenMap[] = { /* %EE */ - {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.era), + {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, ClockFmtToken_LocaleERA_Proc, NULL}, /* %Ey %EC */ {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.year), -- cgit v0.12 From 5846943d27d4aa4f79753cda4526efdbae5f00d3 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 25 Jan 2019 20:18:09 +0000 Subject: fixes [16e4fc3096] julian day calculation (mostly affected for very small times, B.C.E. between 4714 and 4713), added test-cases covering that. --- generic/tclClock.c | 26 ++++++------------------- generic/tclDate.h | 25 ++++++++++++++++++++++++ tests/clock.test | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 819f7fb..26d327e 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -1616,11 +1616,11 @@ ClockGetDateFields( } /* - * Extract Julian day. + * Extract Julian day and seconds of the day. */ - fields->julianDay = (fields->localSeconds + JULIAN_SEC_POSIX_EPOCH) - / SECONDS_PER_DAY; + ClockExtractJDAndSODFromSeconds(fields->julianDay, fields->secondOfDay, + fields->localSeconds); /* * Convert to Julian or Gregorian calendar. @@ -1630,15 +1630,6 @@ ClockGetDateFields( GetMonthDay(fields); GetYearWeekDay(fields, changeover); - - /* - * Seconds of the day. - */ - fields->secondOfDay = (int)(fields->localSeconds % SECONDS_PER_DAY); - if (fields->secondOfDay < 0) { - fields->secondOfDay += SECONDS_PER_DAY; - } - return TCL_OK; } @@ -2102,19 +2093,14 @@ ConvertLocalToUTCUsingC( struct tm timeVal; int localErrno; int secondOfDay; - Tcl_WideInt jsec; /* * Convert the given time to a date. */ - jsec = fields->localSeconds + JULIAN_SEC_POSIX_EPOCH; - fields->julianDay = (jsec / SECONDS_PER_DAY); - secondOfDay = (int)(jsec % SECONDS_PER_DAY); - if (secondOfDay < 0) { - secondOfDay += SECONDS_PER_DAY; - fields->julianDay--; - } + ClockExtractJDAndSODFromSeconds(fields->julianDay, secondOfDay, + fields->localSeconds); + GetGregorianEraYearDay(fields, changeover); GetMonthDay(fields); diff --git a/generic/tclDate.h b/generic/tclDate.h index 9aa031a..2751ee5 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -476,6 +476,31 @@ struct ClockFmtScnStorage { #endif }; +/* + * Clock macros. + */ + +/* + * Extracts Julian day and seconds of the day from posix seconds (tm). + */ +#define ClockExtractJDAndSODFromSeconds(jd, sod, tm) \ + if (1) { \ + jd = (tm + JULIAN_SEC_POSIX_EPOCH); \ + if (jd >= SECONDS_PER_DAY || jd <= -SECONDS_PER_DAY) { \ + jd /= SECONDS_PER_DAY; \ + sod = (int)(tm % SECONDS_PER_DAY); \ + } else { \ + sod = (int)jd, jd = 0; \ + } \ + if (sod < 0) { \ + sod += SECONDS_PER_DAY; \ + /* JD is affected, if switched into negative (avoid 24 hours difference) */ \ + if (jd <= 0) { \ + jd--; \ + } \ + } \ + } + /* * Prototypes of module functions. */ diff --git a/tests/clock.test b/tests/clock.test index 0e143ec..f7d5a83 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -15357,6 +15357,62 @@ test clock-4.96 { format time of day 23:59:59 } { -locale en_US_roman \ -gmt true } {23 xxiii 11 xi 23 xxiii 11 xi 59 lix PM pm 11:59:59 pm 23:59 59 lix 23:59:59 23:59:59 xxiii h lix m lix s Thu Jan 1 23:59:59 GMT 1970} + +test clock-4.97.1 { format julian day } { + clock format 0 -format {%J} -gmt true +} {2440588} +test clock-4.97.2 { format julian day } { + clock format 43200 -format {%J} -gmt true +} {2440588} +test clock-4.97.3 { format julian day } { + clock format 86399 -format {%J} -gmt true +} {2440588} +test clock-4.97.4 { format julian day } { + clock format 86400 -format {%J} -gmt true +} {2440589} +test clock-4.97.5 { format julian day } { + clock format 129599 -format {%J} -gmt true +} {2440589} +test clock-4.97.6 { format julian day } { + clock format 129600 -format {%J} -gmt true +} {2440589} +test clock-4.97.7 { format julian day } { + set i 1548249092 + list \ + [clock format $i -format {%J} -gmt true] \ + [clock format [incr i] -format {%J} -gmt true] \ + [clock format [incr i] -format {%J} -gmt true] +} {2458507 2458507 2458507} +test clock-4.97.8 { format julian day } { + set res {} + foreach i { + -172800 -129600 -86400 -43200 + -1 0 1 21600 43199 43200 86399 + 86400 86401 108000 129600 172800 + } { + lappend res $i [clock format [expr -210866803200 - $i] \ + -format {%EE %Y-%m-%d %T -- %J} -gmt true] + } + set res +} [list \ + -172800 {B.C.E. 4713-01-03 00:00:00 -- 2} \ + -129600 {B.C.E. 4713-01-02 12:00:00 -- 1} \ + -86400 {B.C.E. 4713-01-02 00:00:00 -- 1} \ + -43200 {B.C.E. 4713-01-01 12:00:00 -- 0} \ + -1 {B.C.E. 4713-01-01 00:00:01 -- 0} \ + 0 {B.C.E. 4713-01-01 00:00:00 -- 0} \ + 1 {B.C.E. 4714-12-31 23:59:59 -- -1} \ + 21600 {B.C.E. 4714-12-31 18:00:00 -- -1} \ + 43199 {B.C.E. 4714-12-31 12:00:01 -- -1} \ + 43200 {B.C.E. 4714-12-31 12:00:00 -- -1} \ + 86399 {B.C.E. 4714-12-31 00:00:01 -- -1} \ + 86400 {B.C.E. 4714-12-31 00:00:00 -- -1} \ + 86401 {B.C.E. 4714-12-30 23:59:59 -- -2} \ + 108000 {B.C.E. 4714-12-30 18:00:00 -- -2} \ + 129600 {B.C.E. 4714-12-30 12:00:00 -- -2} \ + 172800 {B.C.E. 4714-12-30 00:00:00 -- -2} \ +] + # END testcases4 # BEGIN testcases5 -- cgit v0.12 From 57f12fe4926235794c3e8baec90bb5870f77f032 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 25 Jan 2019 20:18:27 +0000 Subject: format: fix padding on output of julian day token `%J`: restored tcl-core compatibility (7x 0-padding, affected in B.C.E. only): `clock format -210866803200 -format %J -gmt 1` results into `0000000`. --- generic/tclClockFmt.c | 2 +- tests/clock.test | 54 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index b4d7b14..67a2ec4 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2810,7 +2810,7 @@ static ClockFormatTokenMap FmtSTokenMap[] = { /* %j */ {CTOKT_INT, "0", 3, 0, 0, 0, TclOffset(DateFormat, date.dayOfYear), NULL}, /* %J */ - {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.julianDay), NULL}, + {CTOKT_WIDE, "0", 7, 0, 0, 0, TclOffset(DateFormat, date.julianDay), NULL}, /* %s */ {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.seconds), NULL}, /* %n */ diff --git a/tests/clock.test b/tests/clock.test index f7d5a83..72354c2 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -15395,22 +15395,44 @@ test clock-4.97.8 { format julian day } { } set res } [list \ - -172800 {B.C.E. 4713-01-03 00:00:00 -- 2} \ - -129600 {B.C.E. 4713-01-02 12:00:00 -- 1} \ - -86400 {B.C.E. 4713-01-02 00:00:00 -- 1} \ - -43200 {B.C.E. 4713-01-01 12:00:00 -- 0} \ - -1 {B.C.E. 4713-01-01 00:00:01 -- 0} \ - 0 {B.C.E. 4713-01-01 00:00:00 -- 0} \ - 1 {B.C.E. 4714-12-31 23:59:59 -- -1} \ - 21600 {B.C.E. 4714-12-31 18:00:00 -- -1} \ - 43199 {B.C.E. 4714-12-31 12:00:01 -- -1} \ - 43200 {B.C.E. 4714-12-31 12:00:00 -- -1} \ - 86399 {B.C.E. 4714-12-31 00:00:01 -- -1} \ - 86400 {B.C.E. 4714-12-31 00:00:00 -- -1} \ - 86401 {B.C.E. 4714-12-30 23:59:59 -- -2} \ - 108000 {B.C.E. 4714-12-30 18:00:00 -- -2} \ - 129600 {B.C.E. 4714-12-30 12:00:00 -- -2} \ - 172800 {B.C.E. 4714-12-30 00:00:00 -- -2} \ + -172800 {B.C.E. 4713-01-03 00:00:00 -- 0000002} \ + -129600 {B.C.E. 4713-01-02 12:00:00 -- 0000001} \ + -86400 {B.C.E. 4713-01-02 00:00:00 -- 0000001} \ + -43200 {B.C.E. 4713-01-01 12:00:00 -- 0000000} \ + -1 {B.C.E. 4713-01-01 00:00:01 -- 0000000} \ + 0 {B.C.E. 4713-01-01 00:00:00 -- 0000000} \ + 1 {B.C.E. 4714-12-31 23:59:59 -- -000001} \ + 21600 {B.C.E. 4714-12-31 18:00:00 -- -000001} \ + 43199 {B.C.E. 4714-12-31 12:00:01 -- -000001} \ + 43200 {B.C.E. 4714-12-31 12:00:00 -- -000001} \ + 86399 {B.C.E. 4714-12-31 00:00:01 -- -000001} \ + 86400 {B.C.E. 4714-12-31 00:00:00 -- -000001} \ + 86401 {B.C.E. 4714-12-30 23:59:59 -- -000002} \ + 108000 {B.C.E. 4714-12-30 18:00:00 -- -000002} \ + 129600 {B.C.E. 4714-12-30 12:00:00 -- -000002} \ + 172800 {B.C.E. 4714-12-30 00:00:00 -- -000002} \ +] +test clock-4.97.9 { format JDN/JD (calendar and astronomical) } { + set res {} + foreach i { + -86400 -43200 + -1 0 1 + 43199 43200 43201 86400 + } { + lappend res $i [clock format [expr 653133196800 + $i] \ + -format {%Y-%m-%d %T -- %J} -gmt true] + } + set res +} [list \ + -86400 {22666-12-19 00:00:00 -- 9999999} \ + -43200 {22666-12-19 12:00:00 -- 9999999} \ + -1 {22666-12-19 23:59:59 -- 9999999} \ + 0 {22666-12-20 00:00:00 -- 10000000} \ + 1 {22666-12-20 00:00:01 -- 10000000} \ + 43199 {22666-12-20 11:59:59 -- 10000000} \ + 43200 {22666-12-20 12:00:00 -- 10000000} \ + 43201 {22666-12-20 12:00:01 -- 10000000} \ + 86400 {22666-12-21 00:00:00 -- 10000001} \ ] # END testcases4 -- cgit v0.12 From 0849ec1f7645230c58daa59087a96ec24e919e22 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2019 00:21:13 +0000 Subject: implemented scan of astronomical julian day (JDN/ID) with token `%Ej`, corresponds julian date of sqlite-database. In opposite to calendar julian day `%J`, it starts the day at noon (and can parse float, so contains a time fraction). **TODO** implement `clock format ... -format %Ej` and test-cases for format of this token. **TODO** implement `%EJ` token for calendar JD with time fraction. --- doc/clock.n | 18 +++++++++++++- generic/tclClock.c | 17 +++++++------ generic/tclClockFmt.c | 63 +++++++++++++++++++++++++++++++++++++++++++++- generic/tclDate.h | 2 +- tests/clock.test | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+), 10 deletions(-) diff --git a/doc/clock.n b/doc/clock.n index 0dae993..4294412 100644 --- a/doc/clock.n +++ b/doc/clock.n @@ -400,6 +400,9 @@ seconds from the epoch, that group is used to determine the date. .IP [2] If the string contains a \fB%J\fR format group, representing the Julian Day Number, that group is used to determine the date. +Note, that in case of \fB%Ej\fR format group, representing +the astronomical Julian Date (with time fraction), this group is used +to determine the date and time. .IP [3] If the string contains a complete set of format groups specifying century, year, month, and day of month; century, year, and day of year; @@ -550,6 +553,19 @@ abbreviation appropriate to the current locale, and uses it to fix whether \fB%Y\fR refers to years before or after Year 1 of the Common Era. .TP +\fB%Ej\fR +On output, produces a string of digits giving the Astronomical Julian Date or +Astronomical Julian Day Number (JDN/JD). In opposite to calendar julian day +\fB%J\fR, it starts the day at noon. +On input, accepts a string of digits (or floating point with the time fraction) +and interprets it as an Astronomical Julian Day Number (JDN/JD). +The Astronomical Julian Date is a count of the number of calendar days +that have elapsed since 1 January, 4713 BCE of the proleptic +Julian calendar, which contains also the time fraktion (after floating point). +The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440587.5. +This value corresponds the julian day used in sqlite-database, and is the same +as result of \fBselect julianday(:seconds, 'unixepoch')\fR. +.TP \fB%Es\fR This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses or formats local seconds (not the posix seconds). @@ -605,7 +621,7 @@ On output, produces a three-digit number giving the day of the year (001-366). On input, accepts such a number. .TP \fB%J\fR -On output, produces a string of digits giving the Julian Day Number. +On output, produces a string of digits giving the calendar Julian Day Number. On input, accepts a string of digits and interprets it as a Julian Day Number. The Julian Day Number is a count of the number of calendar days that have elapsed since 1 January, 4713 BCE of the proleptic diff --git a/generic/tclClock.c b/generic/tclClock.c index 26d327e..7f31411 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -235,7 +235,8 @@ TclClockInit( data->yearOfCenturySwitch = ClockDefaultCenturySwitch; data->validMinYear = INT_MIN; data->validMaxYear = INT_MAX; - data->maxJulianDay = 5373484; /* corresponds 9999-12-31 23:59:59 per default */ + /* corresponds max of JDN in sqlite - 9999-12-31 23:59:59 per default */ + data->maxJDN = 5373484.499999994; data->systemTimeZone = NULL; data->systemSetupTZData = NULL; @@ -1120,17 +1121,17 @@ ClockConfigureObjCmd( break; case CLOCK_MAX_JDN: if (i < objc) { - Tcl_WideInt jd; - if (TclGetWideIntFromObj(interp, objv[i], &jd) != TCL_OK) { + double jd; + if (Tcl_GetDoubleFromObj(interp, objv[i], &jd) != TCL_OK) { return TCL_ERROR; } - dataPtr->maxJulianDay = jd; + dataPtr->maxJDN = jd; Tcl_SetObjResult(interp, objv[i]); continue; } if (i+1 >= objc) { Tcl_SetObjResult(interp, - Tcl_NewWideIntObj(dataPtr->maxJulianDay)); + Tcl_NewDoubleObj(dataPtr->maxJDN)); } break; case CLOCK_VALIDATE: @@ -3719,8 +3720,10 @@ ClockScanCommit( /* some overflow checks */ if (info->flags & CLF_JULIANDAY) { - ClockClientData *dataPtr = opts->clientData; - if (yydate.julianDay > dataPtr->maxJulianDay) { + ClockClientData *dataPtr = opts->clientData; + double curJDN = (double)yydate.julianDay + + ((double)yySecondOfDay - SECONDS_PER_DAY/2) / SECONDS_PER_DAY; + if (curJDN > dataPtr->maxJDN) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( "requested date too large to represent", -1)); Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 67a2ec4..67e191a 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1584,6 +1584,64 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts, } static int +ClockScnToken_AstroJDN_Proc(ClockFmtScnCmdArgs *opts, + DateInfo *info, ClockScanToken *tok) +{ + int minLen, maxLen; + register const char *p = yyInput, *end; const char *s; + Tcl_WideInt intJD; int fractJD = 0, fractJDDiv = 1; + + DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + + end = yyInput + maxLen; + + /* currently positive astronomic dates only */ + if (*p == '+') { p++; }; + s = p; + while (p < end && isdigit(UCHAR(*p))) { + p++; + } + if ( _str2wideInt(&intJD, s, p, 1) != TCL_OK) { + return TCL_RETURN; + }; + yyInput = p; + if (p >= end || *p++ != '.') { /* allow pure integer astronomical JDN */ + goto done; + } + s = p; + while (p < end && isdigit(UCHAR(*p))) { + fractJDDiv *= 10; + p++; + } + if ( _str2int(&fractJD, s, p, 1) != TCL_OK) { + return TCL_RETURN; + }; + yyInput = p; + +done: + /* + * Build a date from julian day (integer and fraction). + * Note, astronomical JDN starts at noon in opposite to calendar julianday. + */ + + fractJD = (SECONDS_PER_DAY/2) + + (int)((Tcl_WideInt)SECONDS_PER_DAY * fractJD / fractJDDiv); + if (fractJD > SECONDS_PER_DAY) { + fractJD %= SECONDS_PER_DAY; + intJD += 1; + } + yydate.secondOfDay = fractJD; + yydate.julianDay = intJD; + + yydate.seconds = + -210866803200L + + ( SECONDS_PER_DAY * intJD ) + + ( fractJD ); + + return TCL_OK; +} + +static int ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok) { @@ -1815,11 +1873,14 @@ static const char *ScnSTokenMapAliasIndex[2] = { }; static const char *ScnETokenMapIndex = - "Eys"; + "Ejys"; static ClockScanTokenMap ScnETokenMap[] = { /* %EE */ {CTOKT_PARSER, 0, 0, 0, 0xffff, TclOffset(DateInfo, date.year), ClockScnToken_LocaleERA_Proc, (void *)MCLIT_LOCALE_NUMERALS}, + /* %Ej */ + {CTOKT_PARSER, CLF_JULIANDAY | CLF_POSIXSEC | CLF_SIGNED, 0, 1, 0xffff, 0, + ClockScnToken_AstroJDN_Proc, NULL}, /* %Ey */ {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, /* currently no capture, parse only token */ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS}, diff --git a/generic/tclDate.h b/generic/tclDate.h index 2751ee5..568aef1 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -310,7 +310,7 @@ typedef struct ClockClientData { int yearOfCenturySwitch; int validMinYear; int validMaxYear; - Tcl_WideInt maxJulianDay; + double maxJDN; Tcl_Obj *systemTimeZone; Tcl_Obj *systemSetupTZData; diff --git a/tests/clock.test b/tests/clock.test index 72354c2..50b6648 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18900,6 +18900,72 @@ test clock-7.9 {Julian Day, two values} { clock scan {2440588 2440589} -format {%J %J} -gmt true } 86400 + +test clock-7.11 {Astronomical JDN/JD} { + clock scan 0 -format %Ej -gmt true +} -210866760000 + +test clock-7.12 {Astronomical JDN/JD} { + clock format [clock scan 2440587.5 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "1970-01-01 00:00:00" + +test clock-7.13 {Astronomical JDN/JD} { + clock format [clock scan 2451544.5 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "2000-01-01 00:00:00" + +test clock-7.13.1 {Astronomical JDN/JD} { + clock format [clock scan 2488069.5 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "2100-01-01 00:00:00" + +test clock-7.14 {Astronomical JDN/JD} { + clock format [clock scan 5373483.5 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "9999-12-31 00:00:00" + +test clock-7.14.1 {Astronomical JDN/JD} { + clock format [clock scan 5373484 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "9999-12-31 12:00:00" +test clock-7.14.2 {Astronomical JDN/JD} { + clock format [clock scan 5373484.49999 -format %Ej -gmt true] \ + -format "%Y-%m-%d %T" -gmt true +} "9999-12-31 23:59:59" + +test clock-7.15 {Astronomical JDN/JD, bad} { + list [catch { + clock scan bogus -format %Ej + } result] $result $errorCode +} {1 {input string does not match supplied format} {CLOCK badInputString}} + +test clock-7.16 {Astronomical JDN/JD, overflow} { + list [catch { + clock scan 5373484.5 -format %Ej + } result] $result $errorCode \ + [catch { + clock scan 5373485 -format %Ej + } result] $result $errorCode \ + [catch { + clock scan 2147483648 -format %Ej + } result] $result $errorCode \ + [catch { + clock scan 2147483648.5 -format %Ej + } result] $result $errorCode +} [lrepeat 4 1 {requested date too large to represent} {CLOCK dateTooLarge}] + +test clock-7.18 {Astronomical JDN/JD, same precedence as seconds (last wins} { + list [clock scan {2440588 86400} -format {%Ej %s} -gmt true] \ + [clock scan {2440589 0} -format {%Ej %s} -gmt true] \ + [clock scan {86400 2440588} -format {%s %Ej} -gmt true] \ + [clock scan {0 2440589} -format {%s %Ej} -gmt true] +} {86400 0 43200 129600} + +test clock-7.19 {Astronomical JDN/JD, two values} { + clock scan {2440588 2440589} -format {%Ej %Ej} -gmt true +} 129600 + # BEGIN testcases8 # Test parsing of ccyymmdd @@ -21313,6 +21379,9 @@ test clock-9.1 {seconds take precedence over ccyymmdd} { test clock-9.2 {Julian day takes precedence over ccyymmdd} { clock scan {2440588 20000101} -format {%J %Y%m%d} -gmt true } 0 +test clock-9.2.1 {Astro julian day takes precedence over date-time} { + clock scan {2440587.5 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true +} 0 # Test parsing of ccyyddd -- cgit v0.12 From 1ab33bd2400c55498d6d9d4603f55ce281c1daf6 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2019 00:23:57 +0000 Subject: scan: extended with token `%EJ` to scan calendar julian day with time fraction (in opposite to astronomical JD `%Ej` it starts at midnight like `%J` token). --- doc/clock.n | 22 +++++++++++++++++----- generic/tclClockFmt.c | 28 ++++++++++++++++++++-------- tests/clock.test | 30 ++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/doc/clock.n b/doc/clock.n index 4294412..d75f32d 100644 --- a/doc/clock.n +++ b/doc/clock.n @@ -398,11 +398,12 @@ preprocessed format string. In order of preference: If the string contains a \fB%s\fR format group, representing seconds from the epoch, that group is used to determine the date. .IP [2] -If the string contains a \fB%J\fR format group, representing -the Julian Day Number, that group is used to determine the date. -Note, that in case of \fB%Ej\fR format group, representing -the astronomical Julian Date (with time fraction), this group is used -to determine the date and time. +If the string contains a \fB%J\fR, \fB%EJ\fR or \fB%Ej\fR format groups, +representing the Calendar or Astronomical Julian Day Number, that groups +are used to determine the date. +Note, that in case of \fB%EJ\fR or \fB%Ej\fR format groups, representing +the Julian Date with time fraction, this groups may be used to determine +the date and time. .IP [3] If the string contains a complete set of format groups specifying century, year, month, and day of month; century, year, and day of year; @@ -566,6 +567,17 @@ The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440587.5. This value corresponds the julian day used in sqlite-database, and is the same as result of \fBselect julianday(:seconds, 'unixepoch')\fR. .TP +\fB%EJ\fR +On output, produces a string of digits giving the Calendar Julian Date. +In opposite to julian day \fB%J\fR format group, it produces float number. +In opposite to astronomical julian day \fB%Ej\fR group, it starts at midnight. +On input, accepts a string of digits (or floating point with the time fraction) +and interprets it as a Calendar Julian Day Number. +The Calendar Julian Date is a count of the number of calendar days +that have elapsed since 1 January, 4713 BCE of the proleptic +Julian calendar, which contains also the time fraktion (after floating point). +The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440588. +.TP \fB%Es\fR This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses or formats local seconds (not the posix seconds). diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 67e191a..4582190 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1584,7 +1584,7 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts, } static int -ClockScnToken_AstroJDN_Proc(ClockFmtScnCmdArgs *opts, +ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok) { int minLen, maxLen; @@ -1605,8 +1605,14 @@ ClockScnToken_AstroJDN_Proc(ClockFmtScnCmdArgs *opts, return TCL_RETURN; }; yyInput = p; - if (p >= end || *p++ != '.') { /* allow pure integer astronomical JDN */ - goto done; + if (p >= end || *p++ != '.') { /* allow pure integer JDN */ + /* by astronomical JD the seconds of day offs is 12 hours */ + if (tok->map->offs) { + goto done; + } + /* calendar JD */ + yydate.julianDay = intJD; + return TCL_OK; } s = p; while (p < end && isdigit(UCHAR(*p))) { @@ -1624,12 +1630,12 @@ done: * Note, astronomical JDN starts at noon in opposite to calendar julianday. */ - fractJD = (SECONDS_PER_DAY/2) + fractJD = (int)tok->map->offs /* 0 for calendar or 43200 for astro JD */ + (int)((Tcl_WideInt)SECONDS_PER_DAY * fractJD / fractJDDiv); if (fractJD > SECONDS_PER_DAY) { fractJD %= SECONDS_PER_DAY; intJD += 1; - } + } yydate.secondOfDay = fractJD; yydate.julianDay = intJD; @@ -1638,6 +1644,8 @@ done: + ( SECONDS_PER_DAY * intJD ) + ( fractJD ); + info->flags |= CLF_POSIXSEC | CLF_SIGNED; + return TCL_OK; } @@ -1873,14 +1881,17 @@ static const char *ScnSTokenMapAliasIndex[2] = { }; static const char *ScnETokenMapIndex = - "Ejys"; + "EJjys"; static ClockScanTokenMap ScnETokenMap[] = { /* %EE */ {CTOKT_PARSER, 0, 0, 0, 0xffff, TclOffset(DateInfo, date.year), ClockScnToken_LocaleERA_Proc, (void *)MCLIT_LOCALE_NUMERALS}, + /* %EJ */ + {CTOKT_PARSER, CLF_JULIANDAY, 0, 1, 0xffff, 0, /* calendar JDN starts at midnight */ + ClockScnToken_JDN_Proc, NULL}, /* %Ej */ - {CTOKT_PARSER, CLF_JULIANDAY | CLF_POSIXSEC | CLF_SIGNED, 0, 1, 0xffff, 0, - ClockScnToken_AstroJDN_Proc, NULL}, + {CTOKT_PARSER, CLF_JULIANDAY, 0, 1, 0xffff, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */ + ClockScnToken_JDN_Proc, NULL}, /* %Ey */ {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, /* currently no capture, parse only token */ ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS}, @@ -2385,6 +2396,7 @@ ClockScan( /* * Invalidate result */ + flags |= info->flags; /* seconds token (%s) take precedence over all other tokens */ if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_POSIXSEC)) { diff --git a/tests/clock.test b/tests/clock.test index 50b6648..fa21a26 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18899,6 +18899,14 @@ test clock-7.8 {Julian Day, precedence below seconds} { test clock-7.9 {Julian Day, two values} { clock scan {2440588 2440589} -format {%J %J} -gmt true } 86400 +test clock-7.10 {Calendar vs Astronomical Julian Day (without and with time fraction)} { + list \ + [clock scan {2440588} -format {%J} -gmt true] \ + [clock scan {2440588} -format {%EJ} -gmt true] \ + [clock scan {2440588} -format {%Ej} -gmt true] \ + [clock scan {2440588.5} -format {%EJ} -gmt true] \ + [clock scan {2440588.5} -format {%Ej} -gmt true] \ +} {0 0 43200 43200 86400} test clock-7.11 {Astronomical JDN/JD} { @@ -21376,12 +21384,22 @@ test clock-9.1 {seconds take precedence over ccyymmdd} { clock scan {0 20000101} -format {%s %Y%m%d} -gmt true } 0 -test clock-9.2 {Julian day takes precedence over ccyymmdd} { - clock scan {2440588 20000101} -format {%J %Y%m%d} -gmt true -} 0 -test clock-9.2.1 {Astro julian day takes precedence over date-time} { - clock scan {2440587.5 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true -} 0 +test clock-9.2 {Calendar julian day takes precedence over ccyymmdd} { + list \ + [clock scan {2440588 20000101} -format {%J %Y%m%d} -gmt true] \ + [clock scan {2440588 20000101} -format {%EJ %Y%m%d} -gmt true] +} {0 0} +test clock-9.2.1 {Calendar julian day (with time fraction) takes precedence over date-time} { + list \ + [clock scan {2440588.0 20000101 010203} -format {%EJ %Y%m%d %H%M%S} -gmt true] \ + [clock scan {2440588.5 20000101 010203} -format {%EJ %Y%m%d %H%M%S} -gmt true] + +} {0 43200} +test clock-9.3 {Astro julian day takes always precedence over date-time} { + list \ + [clock scan {2440587.5 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true] \ + [clock scan {2440588 20000101 010203} -format {%Ej %Y%m%d %H%M%S} -gmt true] +} {0 43200} # Test parsing of ccyyddd -- cgit v0.12 From 72f8c81ad189b22d76ff2d8ca8dddd06a0a53958 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2019 00:24:25 +0000 Subject: format: add support of new JDN-tokens (calendar JD `%EJ`, astronomical JD `%Ej`) with time fraction. --- generic/tclClockFmt.c | 69 +++++++++++++++++++++++++++++++++- tests/clock.test | 102 +++++++++++++++++++++++++------------------------- 2 files changed, 119 insertions(+), 52 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 4582190..d4e82ad 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2665,6 +2665,67 @@ ClockFmtToken_WeekOfYear_Proc( return TCL_OK; } static int +ClockFmtToken_JDN_Proc( + ClockFmtScnCmdArgs *opts, + DateFormat *dateFmt, + ClockFormatToken *tok, + int *val) + { + Tcl_WideInt intJD = dateFmt->date.julianDay; + int fractJD; + + /* Convert to JDN parts (regarding start offset) and time fraction */ + fractJD = dateFmt->date.secondOfDay + - (int)tok->map->offs; /* 0 for calendar or 43200 for astro JD */ + if (fractJD < 0) { + intJD--; + fractJD += SECONDS_PER_DAY; + } + if (fractJD && intJD < 0) { /* avoid jump over 0, by negative JD's */ + intJD++; + if (intJD == 0) { + /* -0.0 / -0.9 has zero integer part, so append "-" extra */ + if (FrmResultAllocate(dateFmt, 1) != TCL_OK) { return TCL_ERROR; }; + *dateFmt->output++ = '-'; + } + /* and inverse seconds of day, -0(75) -> -0.25 as float */ + fractJD = SECONDS_PER_DAY - fractJD; + } + + /* 21 is max width of (negative) wide-int (rather smaller, but anyway a time fraction below) */ + if (FrmResultAllocate(dateFmt, 21) != TCL_OK) { return TCL_ERROR; }; + dateFmt->output = _witoaw(dateFmt->output, intJD, '0', 1); + /* simplest cases .0 and .5 */ + if (!fractJD || fractJD == (SECONDS_PER_DAY / 2)) { + /* point + 0 or 5 */ + if (FrmResultAllocate(dateFmt, 1+1) != TCL_OK) { return TCL_ERROR; }; + *dateFmt->output++ = '.'; + *dateFmt->output++ = !fractJD ? '0' : '5'; + *dateFmt->output = '\0'; + return TCL_OK; + } else { + /* wrap the time fraction */ + #define JDN_MAX_PRECISION 8 + #define JDN_MAX_PRECBOUND 100000000 /* 10**JDN_MAX_PRECISION */ + char *p; + + /* to float (part after floating point, + 0.5 to round it up) */ + fractJD = (int)( + (double)fractJD * JDN_MAX_PRECBOUND / SECONDS_PER_DAY + 0.5 + ); + /* point + integer (as time fraction after floating point) */ + if (FrmResultAllocate(dateFmt, 1+JDN_MAX_PRECISION) != TCL_OK) { return TCL_ERROR; }; + *dateFmt->output++ = '.'; + p = _itoaw(dateFmt->output, fractJD, '0', JDN_MAX_PRECISION); + /* remove trailing zero's */ + dateFmt->output++; + while (p > dateFmt->output && *(p-1) == '0') {p--;} + *p = '\0'; + dateFmt->output = p; + } + return TCL_OK; +} +static int ClockFmtToken_TimeZone_Proc( ClockFmtScnCmdArgs *opts, DateFormat *dateFmt, @@ -2900,11 +2961,17 @@ static const char *FmtSTokenMapAliasIndex[2] = { }; static const char *FmtETokenMapIndex = - "Eys"; + "EJjys"; static ClockFormatTokenMap FmtETokenMap[] = { /* %EE */ {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, ClockFmtToken_LocaleERA_Proc, NULL}, + /* %EJ */ + {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, /* calendar JDN starts at midnight */ + ClockFmtToken_JDN_Proc, NULL}, + /* %Ej */ + {CFMTT_PROC, NULL, 0, 0, 0, 0, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */ + ClockFmtToken_JDN_Proc, NULL}, /* %Ey %EC */ {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.year), ClockFmtToken_LocaleERAYear_Proc, NULL}, diff --git a/tests/clock.test b/tests/clock.test index fa21a26..9a949a9 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -15358,32 +15358,32 @@ test clock-4.96 { format time of day 23:59:59 } { -gmt true } {23 xxiii 11 xi 23 xxiii 11 xi 59 lix PM pm 11:59:59 pm 23:59 59 lix 23:59:59 23:59:59 xxiii h lix m lix s Thu Jan 1 23:59:59 GMT 1970} -test clock-4.97.1 { format julian day } { - clock format 0 -format {%J} -gmt true -} {2440588} -test clock-4.97.2 { format julian day } { - clock format 43200 -format {%J} -gmt true -} {2440588} -test clock-4.97.3 { format julian day } { - clock format 86399 -format {%J} -gmt true -} {2440588} -test clock-4.97.4 { format julian day } { - clock format 86400 -format {%J} -gmt true -} {2440589} -test clock-4.97.5 { format julian day } { - clock format 129599 -format {%J} -gmt true -} {2440589} -test clock-4.97.6 { format julian day } { - clock format 129600 -format {%J} -gmt true -} {2440589} -test clock-4.97.7 { format julian day } { +test clock-4.97.1 { format JDN/JD (calendar and astronomical) } { + clock format 0 -format {%J %EJ %Ej} -gmt true +} {2440588 2440588.0 2440587.5} +test clock-4.97.2 { format JDN/JD (calendar and astronomical) } { + clock format 43200 -format {%J %EJ %Ej} -gmt true +} {2440588 2440588.5 2440588.0} +test clock-4.97.3 { format JDN/JD (calendar and astronomical) } { + clock format 86399 -format {%J %EJ %Ej} -gmt true +} {2440588 2440588.99998843 2440588.49998843} +test clock-4.97.4 { format JDN/JD (calendar and astronomical) } { + clock format 86400 -format {%J %EJ %Ej} -gmt true +} {2440589 2440589.0 2440588.5} +test clock-4.97.5 { format JDN/JD (calendar and astronomical) } { + clock format 129599 -format {%J %EJ %Ej} -gmt true +} {2440589 2440589.49998843 2440588.99998843} +test clock-4.97.6 { format JDN/JD (calendar and astronomical) } { + clock format 129600 -format {%J %EJ %Ej} -gmt true +} {2440589 2440589.5 2440589.0} +test clock-4.97.7 { format JDN/JD (calendar and astronomical) } { set i 1548249092 list \ - [clock format $i -format {%J} -gmt true] \ - [clock format [incr i] -format {%J} -gmt true] \ - [clock format [incr i] -format {%J} -gmt true] -} {2458507 2458507 2458507} -test clock-4.97.8 { format julian day } { + [clock format $i -format {%J %EJ %Ej} -gmt true] \ + [clock format [incr i] -format {%J %EJ %Ej} -gmt true] \ + [clock format [incr i] -format {%J %EJ %Ej} -gmt true] +} {{2458507 2458507.54967593 2458507.04967593} {2458507 2458507.5496875 2458507.0496875} {2458507 2458507.54969907 2458507.04969907}} +test clock-4.97.8 { format JDN/JD (calendar and astronomical) } { set res {} foreach i { -172800 -129600 -86400 -43200 @@ -15391,26 +15391,26 @@ test clock-4.97.8 { format julian day } { 86400 86401 108000 129600 172800 } { lappend res $i [clock format [expr -210866803200 - $i] \ - -format {%EE %Y-%m-%d %T -- %J} -gmt true] + -format {%EE %Y-%m-%d %T -- %J %EJ %Ej} -gmt true] } set res } [list \ - -172800 {B.C.E. 4713-01-03 00:00:00 -- 0000002} \ - -129600 {B.C.E. 4713-01-02 12:00:00 -- 0000001} \ - -86400 {B.C.E. 4713-01-02 00:00:00 -- 0000001} \ - -43200 {B.C.E. 4713-01-01 12:00:00 -- 0000000} \ - -1 {B.C.E. 4713-01-01 00:00:01 -- 0000000} \ - 0 {B.C.E. 4713-01-01 00:00:00 -- 0000000} \ - 1 {B.C.E. 4714-12-31 23:59:59 -- -000001} \ - 21600 {B.C.E. 4714-12-31 18:00:00 -- -000001} \ - 43199 {B.C.E. 4714-12-31 12:00:01 -- -000001} \ - 43200 {B.C.E. 4714-12-31 12:00:00 -- -000001} \ - 86399 {B.C.E. 4714-12-31 00:00:01 -- -000001} \ - 86400 {B.C.E. 4714-12-31 00:00:00 -- -000001} \ - 86401 {B.C.E. 4714-12-30 23:59:59 -- -000002} \ - 108000 {B.C.E. 4714-12-30 18:00:00 -- -000002} \ - 129600 {B.C.E. 4714-12-30 12:00:00 -- -000002} \ - 172800 {B.C.E. 4714-12-30 00:00:00 -- -000002} \ + -172800 {B.C.E. 4713-01-03 00:00:00 -- 0000002 2.0 1.5} \ + -129600 {B.C.E. 4713-01-02 12:00:00 -- 0000001 1.5 1.0} \ + -86400 {B.C.E. 4713-01-02 00:00:00 -- 0000001 1.0 0.5} \ + -43200 {B.C.E. 4713-01-01 12:00:00 -- 0000000 0.5 0.0} \ + -1 {B.C.E. 4713-01-01 00:00:01 -- 0000000 0.00001157 -0.49998843} \ + 0 {B.C.E. 4713-01-01 00:00:00 -- 0000000 0.0 -0.5} \ + 1 {B.C.E. 4714-12-31 23:59:59 -- -000001 -0.00001157 -0.50001157} \ + 21600 {B.C.E. 4714-12-31 18:00:00 -- -000001 -0.25 -0.75} \ + 43199 {B.C.E. 4714-12-31 12:00:01 -- -000001 -0.49998843 -0.99998843} \ + 43200 {B.C.E. 4714-12-31 12:00:00 -- -000001 -0.5 -1.0} \ + 86399 {B.C.E. 4714-12-31 00:00:01 -- -000001 -0.99998843 -1.49998843} \ + 86400 {B.C.E. 4714-12-31 00:00:00 -- -000001 -1.0 -1.5} \ + 86401 {B.C.E. 4714-12-30 23:59:59 -- -000002 -1.00001157 -1.50001157} \ + 108000 {B.C.E. 4714-12-30 18:00:00 -- -000002 -1.25 -1.75} \ + 129600 {B.C.E. 4714-12-30 12:00:00 -- -000002 -1.5 -2.0} \ + 172800 {B.C.E. 4714-12-30 00:00:00 -- -000002 -2.0 -2.5} \ ] test clock-4.97.9 { format JDN/JD (calendar and astronomical) } { set res {} @@ -15420,19 +15420,19 @@ test clock-4.97.9 { format JDN/JD (calendar and astronomical) } { 43199 43200 43201 86400 } { lappend res $i [clock format [expr 653133196800 + $i] \ - -format {%Y-%m-%d %T -- %J} -gmt true] + -format {%Y-%m-%d %T -- %J %EJ %Ej} -gmt true] } set res } [list \ - -86400 {22666-12-19 00:00:00 -- 9999999} \ - -43200 {22666-12-19 12:00:00 -- 9999999} \ - -1 {22666-12-19 23:59:59 -- 9999999} \ - 0 {22666-12-20 00:00:00 -- 10000000} \ - 1 {22666-12-20 00:00:01 -- 10000000} \ - 43199 {22666-12-20 11:59:59 -- 10000000} \ - 43200 {22666-12-20 12:00:00 -- 10000000} \ - 43201 {22666-12-20 12:00:01 -- 10000000} \ - 86400 {22666-12-21 00:00:00 -- 10000001} \ + -86400 {22666-12-19 00:00:00 -- 9999999 9999999.0 9999998.5} \ + -43200 {22666-12-19 12:00:00 -- 9999999 9999999.5 9999999.0} \ + -1 {22666-12-19 23:59:59 -- 9999999 9999999.99998843 9999999.49998843} \ + 0 {22666-12-20 00:00:00 -- 10000000 10000000.0 9999999.5} \ + 1 {22666-12-20 00:00:01 -- 10000000 10000000.00001157 9999999.50001157} \ + 43199 {22666-12-20 11:59:59 -- 10000000 10000000.49998843 9999999.99998843} \ + 43200 {22666-12-20 12:00:00 -- 10000000 10000000.5 10000000.0} \ + 43201 {22666-12-20 12:00:01 -- 10000000 10000000.50001157 10000000.00001157} \ + 86400 {22666-12-21 00:00:00 -- 10000001 10000001.0 10000000.5} \ ] # END testcases4 -- cgit v0.12 From e9541d428e336896dbf1d2a0d128e81808fbc40e Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2019 00:24:44 +0000 Subject: scan: all JDN/JD are signed, so allow parse negative Julian days --- generic/tclClockFmt.c | 12 ++++++------ tests/clock.test | 11 +++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index d4e82ad..8e14a7d 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1596,12 +1596,12 @@ ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts, end = yyInput + maxLen; /* currently positive astronomic dates only */ - if (*p == '+') { p++; }; + if (*p == '+' || *p == '-') { p++; }; s = p; while (p < end && isdigit(UCHAR(*p))) { p++; } - if ( _str2wideInt(&intJD, s, p, 1) != TCL_OK) { + if ( _str2wideInt(&intJD, s, p, (*yyInput != '-' ? 1 : -1)) != TCL_OK) { return TCL_RETURN; }; yyInput = p; @@ -1644,7 +1644,7 @@ done: + ( SECONDS_PER_DAY * intJD ) + ( fractJD ); - info->flags |= CLF_POSIXSEC | CLF_SIGNED; + info->flags |= CLF_POSIXSEC; return TCL_OK; } @@ -1838,7 +1838,7 @@ static ClockScanTokenMap ScnSTokenMap[] = { {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, ClockScnToken_amPmInd_Proc, NULL}, /* %J */ - {CTOKT_WIDE, CLF_JULIANDAY, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay), + {CTOKT_WIDE, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay), NULL}, /* %j */ {CTOKT_INT, CLF_DAYOFYEAR, 0, 1, 3, TclOffset(DateInfo, date.dayOfYear), @@ -1887,10 +1887,10 @@ static ClockScanTokenMap ScnETokenMap[] = { {CTOKT_PARSER, 0, 0, 0, 0xffff, TclOffset(DateInfo, date.year), ClockScnToken_LocaleERA_Proc, (void *)MCLIT_LOCALE_NUMERALS}, /* %EJ */ - {CTOKT_PARSER, CLF_JULIANDAY, 0, 1, 0xffff, 0, /* calendar JDN starts at midnight */ + {CTOKT_PARSER, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, 0, /* calendar JDN starts at midnight */ ClockScnToken_JDN_Proc, NULL}, /* %Ej */ - {CTOKT_PARSER, CLF_JULIANDAY, 0, 1, 0xffff, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */ + {CTOKT_PARSER, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, (SECONDS_PER_DAY/2), /* astro JDN starts at noon */ ClockScnToken_JDN_Proc, NULL}, /* %Ey */ {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, /* currently no capture, parse only token */ diff --git a/tests/clock.test b/tests/clock.test index 9a949a9..8a0ed13 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18974,6 +18974,17 @@ test clock-7.19 {Astronomical JDN/JD, two values} { clock scan {2440588 2440589} -format {%Ej %Ej} -gmt true } 129600 +test clock-7.20 {all JDN/JD are signed (and extended accept floats)} { + set res {} + foreach i {%J %EJ %Ej} { + lappend res [clock scan "-1" -format $i -gmt 1] + } + foreach i {%EJ %Ej} { + lappend res [clock scan "-1.5" -format $i -gmt 1] + } + set res +} {-210866889600 -210866889600 -210866846400 -210866846400 -210866803200} + # BEGIN testcases8 # Test parsing of ccyymmdd -- cgit v0.12 From c587280d004ba2c60c5b1ce29dfecd3b6dc12e6d Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 15 Jul 2019 12:12:05 +0000 Subject: **interim** try simplify info-structure (replace yyHave... with flags) --- generic/tclClock.c | 56 ++++++++++++++++++++++-------------------------- generic/tclDate.c | 60 +++++++++++++++++++++++++--------------------------- generic/tclDate.h | 26 ++++++++++------------- generic/tclGetDate.y | 46 +++++++++++++++++++--------------------- 4 files changed, 87 insertions(+), 101 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 7f31411..14aaf2a 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3794,14 +3794,14 @@ ClockValidDate( } /* first year (used later in hath / daysInPriorMonths) */ - if ((info->flags & (CLF_YEAR|CLF_ISO8601YEAR)) || yyHaveDate) { + if ((info->flags & (CLF_YEAR|CLF_ISO8601YEAR))) { if ((info->flags & CLF_ISO8601YEAR)) { if ( yydate.iso8601Year < dataPtr->validMinYear || yydate.iso8601Year > dataPtr->validMaxYear ) { errMsg = "invalid iso year"; errCode = "iso year"; goto error; } } - if ((info->flags & CLF_YEAR) || yyHaveDate) { + if (info->flags & CLF_YEAR) { if ( yyYear < dataPtr->validMinYear || yyYear > dataPtr->validMaxYear ) { errMsg = "invalid year"; errCode = "year"; goto error; @@ -3817,14 +3817,14 @@ ClockValidDate( } } /* and month (used later in hath) */ - if ((info->flags & CLF_MONTH) || yyHaveDate) { + if (info->flags & (CLF_MONTH|CLF_DATE)) { info->flags |= CLF_MONTH; if ( yyMonth < 1 || yyMonth > 12 ) { errMsg = "invalid month"; errCode = "month"; goto error; } } /* day of month */ - if ((info->flags & CLF_DAYOFMONTH) || (yyHaveDate || yyHaveDay)) { + if (info->flags & (CLF_DAYOFMONTH|CLF_DAYOFWEEK)) { info->flags |= CLF_DAYOFMONTH; if ( yyDay < 1 || yyDay > 31 ) { errMsg = "invalid day"; errCode = "day"; goto error; @@ -3837,7 +3837,7 @@ ClockValidDate( } } } - if ((info->flags & CLF_DAYOFYEAR)) { + if (info->flags & CLF_DAYOFYEAR) { if ( yydate.dayOfYear < 1 || yydate.dayOfYear > daysInPriorMonths[IsGregorianLeapYear(&yydate)][12] ) { errMsg = "invalid day of year"; errCode = "day of year"; goto error; @@ -3857,7 +3857,7 @@ ClockValidDate( } } - if ((info->flags & CLF_TIME) || yyHaveTime) { + if (info->flags & CLF_TIME) { /* hour */ if ( yyHour < 0 || yyHour > ((yyMeridian == MER24) ? 23 : 12) ) { errMsg = "invalid time (hour)"; errCode = "hour"; goto error; @@ -3884,7 +3884,7 @@ ClockValidDate( /* time, regarding the modifications by the time-zone (looks for given time * in between DST-time hole, so does not exist in this time-zone) */ - if (((info->flags & CLF_TIME) || yyHaveTime)) { + if (info->flags & CLF_TIME) { /* * we don't need to do the backwards time-conversion (UTC to local) and * compare results, because the after conversion (local to UTC) we @@ -3971,7 +3971,7 @@ ClockFreeScan( * midnight. */ - if (yyHaveDate) { + if (info->flags & CLF_YEAR) { if (yyYear < 100) { if (yyYear >= dataPtr->yearOfCenturySwitch) { yyYear -= 100; @@ -3979,9 +3979,6 @@ ClockFreeScan( yyYear += dataPtr->currentYearCentury; } yydate.era = CE; - if (yyHaveTime == 0) { - yyHaveTime = -1; - } info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS; } @@ -3990,7 +3987,7 @@ ClockFreeScan( * zone indicator of +-hhmm and setup this time zone. */ - if (yyHaveZone) { + if (info->flags & CLF_ZONE) { Tcl_Obj *tzObjStor = NULL; int minEast = -yyTimezone; int dstFlag = 1 - yyDSTmode; @@ -4024,20 +4021,20 @@ ClockFreeScan( * Assemble date, time, zone into seconds-from-epoch */ - if (yyHaveTime == -1) { + if ((info->flags & (CLF_TIME|CLF_HAVEDATE)) == CLF_HAVEDATE) { yySecondOfDay = 0; info->flags |= CLF_ASSEMBLE_SECONDS; } else - if (yyHaveTime) { + if (info->flags & CLF_TIME) { yySecondOfDay = ToSeconds(yyHour, yyMinutes, yySeconds, yyMeridian); info->flags |= CLF_ASSEMBLE_SECONDS; } else - if ( (yyHaveDay && !yyHaveDate) - || yyHaveOrdinalMonth - || ( yyHaveRel + if ( (info->flags & (CLF_DAYOFWEEK|CLF_HAVEDATE)) == CLF_DAYOFWEEK + || (info->flags & CLF_ORDINALMONTH) + || ( (info->flags & CLF_RELCONV) && ( yyRelMonth != 0 || yyRelDay != 0 ) ) ) { @@ -4090,7 +4087,7 @@ ClockCalcRelTime( */ repeat_rel: - if (yyHaveRel) { + if (info->flags & CLF_RELCONV) { /* * Relative conversion normally possible in UTC time only, because @@ -4162,14 +4159,14 @@ repeat_rel: } } - yyHaveRel = 0; + info->flags &= ~CLF_RELCONV; } /* * Do relative (ordinal) month */ - if (yyHaveOrdinalMonth) { + if (info->flags & CLF_ORDINALMONTH) { int monthDiff; /* if needed extract year, month, etc. again */ @@ -4195,12 +4192,10 @@ repeat_rel: } /* process it further via relative times */ - yyHaveRel++; yyYear += yyMonthOrdinalIncr; yyRelMonth += monthDiff; - yyHaveOrdinalMonth = 0; - - info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS; + info->flags &= ~CLF_ORDINALMONTH; + info->flags |= CLF_RELCONV|CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS; goto repeat_rel; } @@ -4209,12 +4204,11 @@ repeat_rel: * Do relative weekday */ - if (yyHaveDay && !yyHaveDate) { + if ((info->flags & (CLF_DAYOFWEEK|CLF_HAVEDATE)) == CLF_DAYOFWEEK) { /* restore scanned day of week */ - if (info->flags & CLF_DAYOFWEEK) { - yyDayOfWeek = prevDayOfWeek; - } + yyDayOfWeek = prevDayOfWeek; + /* if needed assemble julianDay now */ if (info->flags & CLF_ASSEMBLE_JULIANDAY) { GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE); @@ -4420,7 +4414,7 @@ ClockAddObjCmd( * correct date info, because the date may be changed, * so refresh it now */ - if ( yyHaveRel + if ( (info->flags & CLF_RELCONV) && ( unitIndex == CLC_ADD_WEEKDAYS /* some months can be shorter as another */ || yyRelMonth || yyRelDay @@ -4435,7 +4429,7 @@ ClockAddObjCmd( } /* process increment by offset + unit */ - yyHaveRel++; + info->flags |= CLF_RELCONV; switch (unitIndex) { case CLC_ADD_YEARS: yyRelMonth += offs * 12; @@ -4472,7 +4466,7 @@ ClockAddObjCmd( * Do relative times (if not yet already processed interim): */ - if (yyHaveRel) { + if (info->flags & CLF_RELCONV) { if (ClockCalcRelTime(info, &opts) != TCL_OK) { goto done; } diff --git a/generic/tclDate.c b/generic/tclDate.c index 7badb1f..b0979cc 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -123,6 +123,13 @@ #define SECSPERDAY (24L * 60L * 60L) #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. */ @@ -551,13 +558,13 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 160, 160, 161, 162, 165, 168, 171, 174, 177, - 180, 183, 187, 192, 195, 201, 207, 215, 219, 223, - 227, 231, 235, 241, 242, 245, 250, 255, 260, 265, - 270, 277, 281, 286, 291, 296, 301, 305, 310, 314, - 319, 326, 330, 336, 345, 353, 361, 370, 380, 394, - 399, 402, 405, 408, 411, 414, 417, 422, 425, 430, - 434, 438, 444, 447, 452, 470, 473 + 0, 167, 167, 168, 169, 172, 175, 178, 181, 184, + 187, 190, 193, 196, 199, 205, 211, 219, 223, 227, + 231, 235, 239, 245, 246, 249, 253, 257, 261, 265, + 269, 275, 279, 284, 289, 294, 299, 303, 308, 312, + 317, 324, 328, 334, 343, 351, 359, 368, 378, 392, + 397, 400, 403, 406, 409, 412, 415, 420, 423, 428, + 432, 436, 442, 445, 450, 468, 471 }; #endif @@ -1501,7 +1508,7 @@ yyreduce: case 5: { - yyHaveTime++; + yyIncrFlags(CLF_TIME); } break; @@ -1509,7 +1516,7 @@ yyreduce: case 6: { - yyHaveZone++; + yyIncrFlags(CLF_ZONE); } break; @@ -1517,7 +1524,7 @@ yyreduce: case 7: { - yyHaveDate++; + yyIncrFlags(CLF_HAVEDATE); } break; @@ -1525,7 +1532,7 @@ yyreduce: case 8: { - yyHaveOrdinalMonth++; + yyIncrFlags(CLF_ORDINALMONTH); } break; @@ -1533,7 +1540,7 @@ yyreduce: case 9: { - yyHaveDay++; + yyIncrFlags(CLF_DAYOFWEEK); } break; @@ -1541,7 +1548,7 @@ yyreduce: case 10: { - yyHaveRel++; + yyIncrFlags(CLF_RELCONV); } break; @@ -1549,8 +1556,7 @@ yyreduce: case 11: { - yyHaveTime++; - yyHaveDate++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); } break; @@ -1558,9 +1564,7 @@ yyreduce: case 12: { - yyHaveTime++; - yyHaveDate++; - yyHaveRel++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE|CLF_RELCONV); } break; @@ -1657,7 +1661,6 @@ yyreduce: { yyDayOrdinal = 1; yyDayOfWeek = (yyvsp[0].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -1667,7 +1670,6 @@ yyreduce: { yyDayOrdinal = 1; yyDayOfWeek = (yyvsp[-1].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -1677,7 +1679,6 @@ yyreduce: { yyDayOrdinal = (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -1687,7 +1688,6 @@ yyreduce: { yyDayOrdinal = (yyvsp[-3].Number) * (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -1697,7 +1697,6 @@ yyreduce: { yyDayOrdinal = (yyvsp[-2].Number) * (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -1707,7 +1706,6 @@ yyreduce: { yyDayOrdinal = 2; yyDayOfWeek = (yyvsp[0].Number); - info->flags |= CLF_DAYOFWEEK; } break; @@ -2031,10 +2029,10 @@ yyreduce: case 64: { - if (yyHaveTime && yyHaveDate && !yyHaveRel) { + if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { yyYear = (yyvsp[0].Number); } else { - yyHaveTime++; + yyIncrFlags(CLF_TIME); if (yyDigitCount <= 2) { yyHour = (yyvsp[0].Number); yyMinutes = 0; @@ -2855,31 +2853,31 @@ TclClockFreeScan( } Tcl_DecrRefCount(info->messages); - if (yyHaveDate > 1) { + if (info->errFlags & CLF_HAVEDATE) { 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) { + if (info->errFlags & CLF_TIME) { 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) { + if (info->errFlags & CLF_ZONE) { 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) { + if (info->errFlags & CLF_DAYOFWEEK) { 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) { + if (info->errFlags & CLF_ORDINALMONTH) { Tcl_SetObjResult(interp, Tcl_NewStringObj("more than one ordinal month in string", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); diff --git a/generic/tclDate.h b/generic/tclDate.h index 568aef1..5616b13 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -37,6 +37,7 @@ #define CLF_LOCALSEC (1 << 2) #define CLF_JULIANDAY (1 << 3) #define CLF_TIME (1 << 4) +#define CLF_ZONE (1 << 5) #define CLF_CENTURY (1 << 6) #define CLF_DAYOFMONTH (1 << 7) #define CLF_DAYOFYEAR (1 << 8) @@ -46,12 +47,19 @@ #define CLF_ISO8601YEAR (1 << 12) #define CLF_ISO8601WEAK (1 << 13) #define CLF_ISO8601CENTURY (1 << 14) -#define CLF_SIGNED (1 << 15) + +#define CLF_SIGNED (1 << 16) + +/* extra flags used outside of scan/format-tokens too (int, not a short int) */ +#define CLF_RELCONV (1 << 17) +#define CLF_ORDINALMONTH (1 << 18) + /* On demand (lazy) assemble flags */ #define CLF_ASSEMBLE_DATE (1 << 28) /* assemble year, month, etc. using julianDay */ #define CLF_ASSEMBLE_JULIANDAY (1 << 29) /* assemble julianDay using year, month, etc. */ #define CLF_ASSEMBLE_SECONDS (1 << 30) /* assemble localSeconds (and seconds at end) */ +#define CLF_HAVEDATE (CLF_DAYOFMONTH|CLF_MONTH|CLF_YEAR|CLF_ISO8601YEAR) #define CLF_DATE (CLF_JULIANDAY | CLF_DAYOFMONTH | CLF_DAYOFYEAR | \ CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | \ CLF_DAYOFWEEK | CLF_ISO8601WEAK) @@ -185,28 +193,22 @@ typedef struct DateInfo { TclDateFields date; - int flags; - - int dateHaveDate; + int flags; /* Signals parts of date/time get found */ + int errFlags; /* Signals error (part of date/time found twice) */ int dateMeridian; - int dateHaveTime; int dateTimezone; int dateDSTmode; - int dateHaveZone; int dateRelMonth; int dateRelDay; int dateRelSeconds; - int dateHaveRel; int dateMonthOrdinalIncr; int dateMonthOrdinal; - int dateHaveOrdinalMonth; int dateDayOrdinal; - int dateHaveDay; int *dateRelPointer; @@ -235,12 +237,6 @@ typedef struct DateInfo { #define yyDayOfWeek (info->date.dayOfWeek) #define yyMonthOrdinalIncr (info->dateMonthOrdinalIncr) #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 yyMeridian (info->dateMeridian) #define yyRelMonth (info->dateRelMonth) diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 88432ec..cf1f674 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -75,6 +75,13 @@ #define SECSPERDAY (24L * 60L * 60L) #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. */ @@ -163,31 +170,28 @@ spec : /* NULL */ ; 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++; + yyIncrFlags(CLF_RELCONV); } | iso { - yyHaveTime++; - yyHaveDate++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); } | trek { - yyHaveTime++; - yyHaveDate++; - yyHaveRel++; + yyIncrFlags(CLF_TIME|CLF_HAVEDATE|CLF_RELCONV); } | number ; @@ -245,32 +249,26 @@ comma : ',' day : tDAY { yyDayOrdinal = 1; yyDayOfWeek = $1; - info->flags |= CLF_DAYOFWEEK; } | tDAY comma { yyDayOrdinal = 1; yyDayOfWeek = $1; - info->flags |= CLF_DAYOFWEEK; } | tUNUMBER tDAY { yyDayOrdinal = $1; yyDayOfWeek = $2; - info->flags |= CLF_DAYOFWEEK; } | sign SP tUNUMBER tDAY { yyDayOrdinal = $1 * $3; yyDayOfWeek = $4; - info->flags |= CLF_DAYOFWEEK; } | sign tUNUMBER tDAY { yyDayOrdinal = $1 * $2; yyDayOfWeek = $3; - info->flags |= CLF_DAYOFWEEK; } | tNEXT tDAY { yyDayOrdinal = 2; yyDayOfWeek = $2; - info->flags |= CLF_DAYOFWEEK; } ; @@ -450,10 +448,10 @@ INTNUM : tUNUMBER { ; number : INTNUM { - if (yyHaveTime && yyHaveDate && !yyHaveRel) { + 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; @@ -1029,31 +1027,31 @@ TclClockFreeScan( } Tcl_DecrRefCount(info->messages); - if (yyHaveDate > 1) { + if (info->errFlags & CLF_HAVEDATE) { 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) { + if (info->errFlags & CLF_TIME) { 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) { + if (info->errFlags & CLF_ZONE) { 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) { + if (info->errFlags & CLF_DAYOFWEEK) { 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) { + if (info->errFlags & CLF_ORDINALMONTH) { Tcl_SetObjResult(interp, Tcl_NewStringObj("more than one ordinal month in string", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); -- cgit v0.12 From 9f872f5338b49bea2e8022380a50c2257e42f26d Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 15 Jul 2019 12:12:22 +0000 Subject: simplifying info-structure, usage of flags etc (normalizing in order to use same flags as by formatted scan instead of members like yyHave...); (additionally allocates info->messages object on demand, if free scan fails) --- generic/tclClock.c | 4 +-- generic/tclDate.c | 90 +++++++++++++++++++++++----------------------------- generic/tclDate.h | 4 +-- generic/tclGetDate.y | 78 +++++++++++++++++++-------------------------- 4 files changed, 75 insertions(+), 101 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 14aaf2a..828a2a6 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3817,15 +3817,13 @@ ClockValidDate( } } /* and month (used later in hath) */ - if (info->flags & (CLF_MONTH|CLF_DATE)) { - info->flags |= CLF_MONTH; + if (info->flags & CLF_MONTH) { if ( yyMonth < 1 || yyMonth > 12 ) { errMsg = "invalid month"; errCode = "month"; goto error; } } /* day of month */ if (info->flags & (CLF_DAYOFMONTH|CLF_DAYOFWEEK)) { - info->flags |= CLF_DAYOFMONTH; if ( yyDay < 1 || yyDay > 31 ) { errMsg = "invalid day"; errCode = "day"; goto error; } diff --git a/generic/tclDate.c b/generic/tclDate.c index b0979cc..df8aeb5 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -559,12 +559,12 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint16 yyrline[] = { 0, 167, 167, 168, 169, 172, 175, 178, 181, 184, - 187, 190, 193, 196, 199, 205, 211, 219, 223, 227, - 231, 235, 239, 245, 246, 249, 253, 257, 261, 265, - 269, 275, 279, 284, 289, 294, 299, 303, 308, 312, - 317, 324, 328, 334, 343, 351, 359, 368, 378, 392, - 397, 400, 403, 406, 409, 412, 415, 420, 423, 428, - 432, 436, 442, 445, 450, 468, 471 + 187, 190, 193, 197, 200, 206, 212, 220, 224, 228, + 232, 236, 240, 246, 247, 250, 254, 258, 262, 266, + 270, 276, 280, 285, 290, 295, 300, 304, 309, 313, + 318, 325, 329, 335, 344, 352, 360, 369, 379, 393, + 398, 401, 404, 407, 410, 413, 416, 421, 424, 429, + 433, 437, 443, 446, 451, 469, 472 }; #endif @@ -1548,7 +1548,7 @@ yyreduce: case 10: { - yyIncrFlags(CLF_RELCONV); + info->flags |= CLF_RELCONV; } break; @@ -1564,7 +1564,8 @@ yyreduce: case 12: { - yyIncrFlags(CLF_TIME|CLF_HAVEDATE|CLF_RELCONV); + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); + info->flags |= CLF_RELCONV; } break; @@ -2524,6 +2525,9 @@ TclDateerror( const char *s) { Tcl_Obj* t; + if (!infoPtr->messages) { + infoPtr->messages = Tcl_NewObj(); + } Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); Tcl_AppendToObj(infoPtr->messages, s, -1); Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); @@ -2821,9 +2825,7 @@ TclClockFreeScan( yyDSTmode = DSTmaybe; - info->messages = Tcl_NewObj(); info->separatrix = ""; - Tcl_IncrRefCount(info->messages); info->dateStart = yyInput; @@ -2833,58 +2835,44 @@ TclClockFreeScan( /* parse */ status = yyparse(info); if (status == 1) { - Tcl_SetObjResult(interp, info->messages); - Tcl_DecrRefCount(info->messages); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", 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", NULL); + } else { + Tcl_SetObjResult(interp, + info->messages ? info->messages : Tcl_NewObj()); + info->messages = NULL; + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + } + status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "MEMORY", 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(info->messages); Tcl_SetErrorCode(interp, "TCL", "BUG", NULL); - return TCL_ERROR; + status = TCL_ERROR; } - Tcl_DecrRefCount(info->messages); - - if (info->errFlags & CLF_HAVEDATE) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one date in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; - } - if (info->errFlags & CLF_TIME) { - 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 (info->errFlags & CLF_ZONE) { - 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 (info->errFlags & CLF_DAYOFWEEK) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one weekday in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; - } - if (info->errFlags & CLF_ORDINALMONTH) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one ordinal month in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; + if (info->messages) { + Tcl_DecrRefCount(info->messages); } - - return TCL_OK; + return status; } /* diff --git a/generic/tclDate.h b/generic/tclDate.h index 5616b13..0c9f7c3 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -48,7 +48,7 @@ #define CLF_ISO8601WEAK (1 << 13) #define CLF_ISO8601CENTURY (1 << 14) -#define CLF_SIGNED (1 << 16) +#define CLF_SIGNED (1 << 15) /* extra flags used outside of scan/format-tokens too (int, not a short int) */ #define CLF_RELCONV (1 << 17) @@ -59,7 +59,7 @@ #define CLF_ASSEMBLE_JULIANDAY (1 << 29) /* assemble julianDay using year, month, etc. */ #define CLF_ASSEMBLE_SECONDS (1 << 30) /* assemble localSeconds (and seconds at end) */ -#define CLF_HAVEDATE (CLF_DAYOFMONTH|CLF_MONTH|CLF_YEAR|CLF_ISO8601YEAR) +#define CLF_HAVEDATE (CLF_DAYOFMONTH|CLF_MONTH|CLF_YEAR) #define CLF_DATE (CLF_JULIANDAY | CLF_DAYOFMONTH | CLF_DAYOFYEAR | \ CLF_MONTH | CLF_YEAR | CLF_ISO8601YEAR | \ CLF_DAYOFWEEK | CLF_ISO8601WEAK) diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index cf1f674..8594a3e 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -185,13 +185,14 @@ item : time { yyIncrFlags(CLF_DAYOFWEEK); } | relspec { - yyIncrFlags(CLF_RELCONV); + info->flags |= CLF_RELCONV; } | iso { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); } | trek { - yyIncrFlags(CLF_TIME|CLF_HAVEDATE|CLF_RELCONV); + yyIncrFlags(CLF_TIME|CLF_HAVEDATE); + info->flags |= CLF_RELCONV; } | number ; @@ -698,6 +699,9 @@ TclDateerror( const char *s) { Tcl_Obj* t; + if (!infoPtr->messages) { + infoPtr->messages = Tcl_NewObj(); + } Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); Tcl_AppendToObj(infoPtr->messages, s, -1); Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); @@ -995,9 +999,7 @@ TclClockFreeScan( yyDSTmode = DSTmaybe; - info->messages = Tcl_NewObj(); info->separatrix = ""; - Tcl_IncrRefCount(info->messages); info->dateStart = yyInput; @@ -1007,58 +1009,44 @@ TclClockFreeScan( /* parse */ status = yyparse(info); if (status == 1) { - Tcl_SetObjResult(interp, info->messages); - Tcl_DecrRefCount(info->messages); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", 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", NULL); + } else { + Tcl_SetObjResult(interp, + info->messages ? info->messages : Tcl_NewObj()); + info->messages = NULL; + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + } + status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "MEMORY", 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(info->messages); Tcl_SetErrorCode(interp, "TCL", "BUG", NULL); - return TCL_ERROR; + status = TCL_ERROR; } - Tcl_DecrRefCount(info->messages); - - if (info->errFlags & CLF_HAVEDATE) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one date in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; - } - if (info->errFlags & CLF_TIME) { - 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 (info->errFlags & CLF_ZONE) { - 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 (info->errFlags & CLF_DAYOFWEEK) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one weekday in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; - } - if (info->errFlags & CLF_ORDINALMONTH) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("more than one ordinal month in string", -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); - return TCL_ERROR; + if (info->messages) { + Tcl_DecrRefCount(info->messages); } - - return TCL_OK; + return status; } /* -- cgit v0.12 From 8b9f762113baf4a70fff339bc583e8861c2a7e55 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 15 Jul 2019 12:18:52 +0000 Subject: Fixes sebres/tclclockmod#18 (Fails to parse short month name for June); The reason for that was the wrong length calculation by scanning through my string index tree, so the ambiguity check `j->(jan,ju->(jun,jul))` failed for 2nd element Ju(ne) with length 2. Simple fix and test-cases covering that, but it looks like this has a good potential for speedup (todo: move length calculation from search to build) --- generic/tclStrIdxTree.c | 2 +- tests/clock.test | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/generic/tclStrIdxTree.c b/generic/tclStrIdxTree.c index 88a64c6..a54b548 100644 --- a/generic/tclStrIdxTree.c +++ b/generic/tclStrIdxTree.c @@ -96,7 +96,7 @@ TclStrIdxTreeSearch( /* search in tree */ do { cinf = cin = TclGetString(item->key) + offs; - f = TclUtfFindEqualNCInLwr(s, end, cin, cin + item->length, &cinf); + f = TclUtfFindEqualNCInLwr(s, end, cin, cin + item->length - offs, &cinf); /* if something was found */ if (f > s) { /* if whole string was found */ diff --git a/tests/clock.test b/tests/clock.test index f8654e9..4a70140 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18687,10 +18687,34 @@ test clock-6.11 {input of seconds - two values} { clock scan {1 2} -format {%s %s} -gmt true } 2 -test clock-6.12 {input of unambiguous short locale token (%b)} { +test clock-6.12.0 {input of unambiguous short locale token (%b)} { list [clock scan "12 Ja 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] \ [clock scan "12 Au 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] } {979257600 997574400} +test clock-6.12.1 {input of all forms of unambiguous short locale token (%b)} { + # find all unambiguous short forms and check it'll be scanned successful and correctly: + set months {January February March April May June July August September October November December} + set res {} + foreach mon $months { + set i 0 + while {[incr i] < [string length $mon]} { + # short month form: + set shm [string range $mon 0 $i] + # ignore ambiguous: + if {[llength [lsearch -all -glob $months "${shm}*"]] > 1} continue + set s "12 $shm 2001" + # scan and format with full month name: + set t [clock format \ + [clock scan $s -format "%d %b %Y" -locale en_US_roman -gmt 1] \ + -format "%d %B %Y" -locale en_US_roman -gmt 1] + # check it corresponds the full form: + if {$t ne "12 $mon 2001"} { + lappend res "unexpected result converting $s, expected \"12 $mon 2001\", got \"$t\"" + } + } + } + set res +} {} test clock-6.13 {input of lowercase locale token (%b)} { list [clock scan "12 ja 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] \ [clock scan "12 au 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] -- cgit v0.12 From b62e2e7fce5f6b1f7f4f5ff6ede624d5ee0522ae Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 15 Jul 2019 12:21:40 +0000 Subject: small amend to [3bec82b72c] (sebres/tclclockmod#18): test cases extended to cover error cases (on ambiguous short forms of month) too --- tests/clock.test | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/clock.test b/tests/clock.test index 4a70140..22ed2dd 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18687,7 +18687,7 @@ test clock-6.11 {input of seconds - two values} { clock scan {1 2} -format {%s %s} -gmt true } 2 -test clock-6.12.0 {input of unambiguous short locale token (%b)} { +test clock-6.12.0 {input of short forms of locale token (%b)} { list [clock scan "12 Ja 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] \ [clock scan "12 Au 2001" -format "%d %b %Y" -locale en_US_roman -gmt 1] } {979257600 997574400} @@ -18700,16 +18700,22 @@ test clock-6.12.1 {input of all forms of unambiguous short locale token (%b)} { while {[incr i] < [string length $mon]} { # short month form: set shm [string range $mon 0 $i] - # ignore ambiguous: - if {[llength [lsearch -all -glob $months "${shm}*"]] > 1} continue + # differentiate ambiguous: + if {[llength [lsearch -all -glob $months "${shm}*"]] <= 1} { + # unambiguous (expected date with wull month): + set e "12 $mon 2001" + } else { + # ambiguous (expected error): + set e "input string does not match supplied format" + } set s "12 $shm 2001" # scan and format with full month name: - set t [clock format \ + catch {clock format \ [clock scan $s -format "%d %b %Y" -locale en_US_roman -gmt 1] \ - -format "%d %B %Y" -locale en_US_roman -gmt 1] + -format "%d %B %Y" -locale en_US_roman -gmt 1} t # check it corresponds the full form: - if {$t ne "12 $mon 2001"} { - lappend res "unexpected result converting $s, expected \"12 $mon 2001\", got \"$t\"" + if {$t ne $e} { + lappend res "unexpected result converting $s, expected \"$e\", got \"$t\"" } } } -- cgit v0.12 From b8d9b4e99692ca26fba5686fd79fc8bfe0b65bdb Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:30:47 +0000 Subject: improve tests, since timerate supporting max-count too --- tests-perf/clock.perf.tcl | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests-perf/clock.perf.tcl b/tests-perf/clock.perf.tcl index c0da0ab..3682387 100644 --- a/tests-perf/clock.perf.tcl +++ b/tests-perf/clock.perf.tcl @@ -2,18 +2,18 @@ # ------------------------------------------------------------------------ # # test-performance.tcl -- -# +# # This file provides common performance tests for comparison of tcl-speed # degradation by switching between branches. # (currently for clock ensemble only) # # ------------------------------------------------------------------------ -# +# # Copyright (c) 2014 Serg G. Brester (aka sebres) -# +# # See the file "license.terms" for information on usage and redistribution # of this file. -# +# array set in {-time 500} if {[info exists ::argv0] && [file tail $::argv0] eq [file tail [info script]]} { @@ -215,7 +215,7 @@ proc test-freescan {{reptime 1000}} { {clock scan "next January" -base 0 -gmt 1} # FreeScan : relative week {clock scan "next Fri" -base 0 -gmt 1} - # FreeScan : relative weekday and week offset + # FreeScan : relative weekday and week offset {clock scan "next January + 2 week" -base 0 -gmt 1} # FreeScan : time only with base {clock scan "19:18:30" -base 148863600 -gmt 1} @@ -300,7 +300,7 @@ proc test-convert {{reptime 1000}} { {clock format [clock scan "19:18:30 EST" -base 148863600] -format "%H:%M:%S %z" -timezone EST} # Format locale 1x: comparison values - {clock format 0 -gmt 1 -locale en} + {clock format 0 -gmt 1 -locale en} {clock format 0 -gmt 1 -locale de} {clock format 0 -gmt 1 -locale fr} # Format locale 2x: without switching locale (en, en) @@ -340,7 +340,7 @@ proc test-convert {{reptime 1000}} { {clock scan "19:18:30 MST" -base 148863600; clock scan "19:18:30 EST" -base 148863600} # FreeScan TZ 2x (+1 gmt, +1 system-default) {clock scan "19:18:30 MST" -base 148863600 -gmt 1; clock scan "19:18:30 EST" -base 148863600} - + # Scan TZ: comparison included in scan string vs. given {clock scan "2009-06-30T18:30:00 CEST" -format "%Y-%m-%dT%H:%M:%S %z"} {clock scan "2009-06-30T18:30:00 CET" -format "%Y-%m-%dT%H:%M:%S %z"} @@ -356,10 +356,16 @@ proc test-other {{reptime 1000}} { # Scan : julian day (overflow) {catch {clock scan 5373485 -format %J}} + setup {set _(org-reptime) $_(reptime); lset _(reptime) 1 50} + # Scan : test rotate of GC objects (format is dynamic, so tcl-obj removed with last reference) - {set i 0; time { clock scan "[incr i] - 25.11.2015" -format "$i - %d.%m.%Y" -base 0 -gmt 1 } 50} + setup {set i -1} + {clock scan "[incr i] - 25.11.2015" -format "$i - %d.%m.%Y" -base 0 -gmt 1} # Scan : test reusability of GC objects (format is dynamic, so tcl-obj removed with last reference) - {set i 50; time { clock scan "[incr i -1] - 25.11.2015" -format "$i - %d.%m.%Y" -base 0 -gmt 1 } 50} + setup {incr i; set j $i} + {clock scan "[incr j -1] - 25.11.2015" -format "$j - %d.%m.%Y" -base 0 -gmt 1} + setup {set _(reptime) $_(org-reptime); set j $i} + {clock scan "[incr j -1] - 25.11.2015" -format "$j - %d.%m.%Y" -base 0 -gmt 1; if {!$j} {set j $i}} } } -- cgit v0.12 From d576bf5f4ae35a7f3f57fc76c1d8da2b9506ca2a Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:35:37 +0000 Subject: test case illustrating #19: some initialization of clock.tcl (locale/msgcat, etc) could overwrite interp state (errorInfo/errorCode) --- tests/clock.test | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index 22ed2dd..d7e5796 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -300,6 +300,20 @@ test clock-0.1 "initial: auto-loading of ensemble and stubs on demand" no_tclclo set ret } {ens:0 ens:1 stubs:0 stubs:1} +test clock-0.2 "initial: loading of format/locale does not overwrite interp state (errorInfo)" -setup { + # be sure - we have no cached locale/msgcat, etc: + if {[namespace which -command ::tcl::clock::ClearCaches] ne ""} { + ::tcl::clock::ClearCaches + } +} -body { + if {[catch { + return -level 0 -code error -errorcode {EXPERR TEST-ERROR} -errorinfo "ERROR expected error" test + }]} { + clock format -now -locale de; # should not overwrite error code/info + list $::errorCode $::errorInfo + } +} -result {{EXPERR TEST-ERROR} {ERROR expected error}} + # Test some of the basics of [clock format] set syntax "clock format clockval|-now ?-format string? ?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?" -- cgit v0.12 From fb474e354f9db6e20c53eebac82db276b0212a9f Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:42:31 +0000 Subject: avoid change of interp state in ::tcl::clock::LocalizeFormat --- library/clock.tcl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/clock.tcl b/library/clock.tcl index 330c185..1c0d898 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -822,14 +822,14 @@ proc ::tcl::clock::LocalizeFormat { locale format {fmtkey {}} } { variable LocaleFormats if { $fmtkey eq {} } { set fmtkey FMT_$format } - if { [catch { - set locfmt [dict get $LocaleFormats $locale $fmtkey] - }] } { + if {[dict exists $LocaleFormats $locale $fmtkey]} { + set locfmt [dict get $LocaleFormats $locale $fmtkey] + } else { - # get map list cached or build it: - if { [catch { + # get map list cached or build it: + if {[dict exists $LocaleFormats $locale MLST]} { set mlst [dict get $LocaleFormats $locale MLST] - }] } { + } else { # message catalog dictionary: set mcd [mcget $locale] -- cgit v0.12 From 1ccbe8c2d0611eb72c23c85593ef44b9c7c9f024 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:44:35 +0000 Subject: avoid overwrite of interp state by select and setup timezone --- generic/tclClock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 828a2a6..1325f80 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -1261,6 +1261,7 @@ ClockGetSystemTimeZone( Tcl_Interp *interp) /* Tcl interpreter */ { ClockClientData *dataPtr = clientData; + Tcl_InterpState interpState; /* if known (cached and same epoch) - return now */ if (dataPtr->systemTimeZone != NULL @@ -1268,16 +1269,19 @@ ClockGetSystemTimeZone( return dataPtr->systemTimeZone; } + interpState = Tcl_SaveInterpState(interp, 0); + Tcl_UnsetObjRef(dataPtr->systemTimeZone); Tcl_UnsetObjRef(dataPtr->systemSetupTZData); if (Tcl_EvalObjv(interp, 1, &dataPtr->literals[LIT_GETSYSTEMTIMEZONE], 0) != TCL_OK) { + Tcl_DiscardInterpState(interpState); return NULL; } if (dataPtr->systemTimeZone == NULL) { Tcl_SetObjRef(dataPtr->systemTimeZone, Tcl_GetObjResult(interp)); } - Tcl_ResetResult(interp); + (void) Tcl_RestoreInterpState(interp, interpState); return dataPtr->systemTimeZone; } @@ -1301,6 +1305,7 @@ ClockSetupTimeZone( Tcl_Obj *timezoneObj) { ClockClientData *dataPtr = clientData; + Tcl_InterpState interpState; int loaded; Tcl_Obj *callargs[2]; @@ -1338,11 +1343,14 @@ ClockSetupTimeZone( } /* setup now */ callargs[0] = dataPtr->literals[LIT_SETUPTIMEZONE]; + interpState = Tcl_SaveInterpState(interp, 0); if (Tcl_EvalObjv(interp, 2, callargs, 0) == TCL_OK) { /* save unnormalized last used */ Tcl_SetObjRef(dataPtr->lastSetupTimeZoneUnnorm, timezoneObj); + (void) Tcl_RestoreInterpState(interp, interpState); return callargs[1]; } + Tcl_DiscardInterpState(interpState); return NULL; } -- cgit v0.12 From 9ba7c4aa1c392193c454eda0aea6eff3afab8961 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:51:41 +0000 Subject: close #19: implements safe "catch" in clock NS - avoid overwrite of interp state by select and setup timezone (as well as in other "catched" blocks on lazy loading or initialization); windows: load registry package on demand only (if possible, using same safe "catch" command). --- generic/tclClock.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++------- library/clock.tcl | 55 +++++++++++++++++++--------------- 2 files changed, 108 insertions(+), 33 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 1325f80..75ef831 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -143,6 +143,9 @@ static struct tm * ThreadSafeLocalTime(const time_t *); static size_t TzsetIfNecessary(void); static void ClockDeleteCmdProc(ClientData); +static int ClockSafeCatchCmd( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]); /* * Structure containing description of "native" clock commands to create. */ @@ -175,6 +178,7 @@ static const struct ClockCommand clockCommands[] = { ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL}, {"GetJulianDayFromEraYearWeekDay", ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL}, + {"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL}, {NULL, NULL, NULL, NULL} }; @@ -1261,7 +1265,6 @@ ClockGetSystemTimeZone( Tcl_Interp *interp) /* Tcl interpreter */ { ClockClientData *dataPtr = clientData; - Tcl_InterpState interpState; /* if known (cached and same epoch) - return now */ if (dataPtr->systemTimeZone != NULL @@ -1269,19 +1272,16 @@ ClockGetSystemTimeZone( return dataPtr->systemTimeZone; } - interpState = Tcl_SaveInterpState(interp, 0); - Tcl_UnsetObjRef(dataPtr->systemTimeZone); Tcl_UnsetObjRef(dataPtr->systemSetupTZData); if (Tcl_EvalObjv(interp, 1, &dataPtr->literals[LIT_GETSYSTEMTIMEZONE], 0) != TCL_OK) { - Tcl_DiscardInterpState(interpState); return NULL; } if (dataPtr->systemTimeZone == NULL) { Tcl_SetObjRef(dataPtr->systemTimeZone, Tcl_GetObjResult(interp)); } - (void) Tcl_RestoreInterpState(interp, interpState); + Tcl_ResetResult(interp); return dataPtr->systemTimeZone; } @@ -1305,7 +1305,6 @@ ClockSetupTimeZone( Tcl_Obj *timezoneObj) { ClockClientData *dataPtr = clientData; - Tcl_InterpState interpState; int loaded; Tcl_Obj *callargs[2]; @@ -1343,14 +1342,11 @@ ClockSetupTimeZone( } /* setup now */ callargs[0] = dataPtr->literals[LIT_SETUPTIMEZONE]; - interpState = Tcl_SaveInterpState(interp, 0); if (Tcl_EvalObjv(interp, 2, callargs, 0) == TCL_OK) { - /* save unnormalized last used */ + /* save unnormalized last used */ Tcl_SetObjRef(dataPtr->lastSetupTimeZoneUnnorm, timezoneObj); - (void) Tcl_RestoreInterpState(interp, interpState); return callargs[1]; } - Tcl_DiscardInterpState(interpState); return NULL; } @@ -4533,6 +4529,76 @@ ClockSecondsObjCmd( /* *---------------------------------------------------------------------- * + * ClockSafeCatchCmd -- + * + * Same as "::catch" command but avoids overwriting of interp state. + * + * See [554117edde] for more info (and proper solution). + * + *---------------------------------------------------------------------- + */ +int +ClockSafeCatchCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + typedef struct InterpState { + int status; /* return code status */ + int flags; /* Each remaining field saves the */ + int returnLevel; /* corresponding field of the Interp */ + int returnCode; /* struct. These fields taken together are */ + Tcl_Obj *errorInfo; /* the "state" of the interp. */ + Tcl_Obj *errorCode; + Tcl_Obj *returnOpts; + Tcl_Obj *objResult; + Tcl_Obj *errorStack; + int resetErrorStack; + } InterpState; + + Interp *iPtr = (Interp *)interp; + int ret, flags = 0; + InterpState *statePtr; + + if (objc == 1) { + /* wrong # args : */ + return Tcl_CatchObjCmd(NULL, interp, objc, objv); + } + + statePtr = (InterpState *)Tcl_SaveInterpState(interp, 0); + if (!statePtr->errorInfo) { + /* todo: avoid traced get of errorInfo here */ + Tcl_InitObjRef(statePtr->errorInfo, + Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, 0)); + flags |= ERR_LEGACY_COPY; + } + if (!statePtr->errorCode) { + /* todo: avoid traced get of errorCode here */ + Tcl_InitObjRef(statePtr->errorCode, + Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, 0)); + flags |= ERR_LEGACY_COPY; + } + + /* original catch */ + ret = Tcl_CatchObjCmd(NULL, interp, objc, objv); + + if (ret == TCL_ERROR) { + Tcl_DiscardInterpState((Tcl_InterpState)statePtr); + return TCL_ERROR; + } + /* overwrite result in state with catch result */ + Tcl_SetObjRef(statePtr->objResult, Tcl_GetObjResult(interp)); + /* set result (together with restore state) to interpreter */ + (void) Tcl_RestoreInterpState(interp, (Tcl_InterpState)statePtr); + /* todo: unless ERR_LEGACY_COPY not set in restore (branch [bug-554117edde] not merged yet) */ + iPtr->flags |= (flags & ERR_LEGACY_COPY); + return ret; +} + +/* + *---------------------------------------------------------------------- + * * TzsetIfNecessary -- * * Calls the tzset() library function if the contents of the TZ diff --git a/library/clock.tcl b/library/clock.tcl index 1c0d898..4a16f7f 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -16,25 +16,9 @@ # #---------------------------------------------------------------------- -# We must have message catalogs that support the root locale, and we need -# access to the Registry on Windows systems. +# We must have message catalogs that support the root locale. -uplevel \#0 { - package require msgcat 1.6 - if { $::tcl_platform(platform) eq {windows} } { - if { [catch { package require registry 1.1 }] } { - # try to load registry directly from root (if uninstalled / development env): - if {![regexp {[/\\]library$} [info library]] || [catch { - load [lindex \ - [glob -tails -directory [file dirname [info nameofexecutable]] \ - tclreg*[expr {[::tcl::pkgconfig get debug] ? {g} : {}}].dll] 0 \ - ] registry - }]} { - namespace eval ::tcl::clock [list variable NoRegistry {}] - } - } - } -} +package require msgcat 1.6 # Put the library directory into the namespace for the ensemble so that the # library code can find message catalogs and time zone definition files. @@ -673,6 +657,33 @@ proc ::tcl::clock::EnterLocale { locale } { #---------------------------------------------------------------------- # +# _hasRegistry -- +# +# Helper that checks whether registry module is available (Windows only) +# and loads it on demand. +# +#---------------------------------------------------------------------- +proc ::tcl::clock::_hasRegistry {} { + if { $::tcl_platform(platform) eq {windows} } { + if { [catch { package require registry 1.1 }] } { + # try to load registry directly from root (if uninstalled / development env): + if {[regexp {[/\\]library$} [info library]]} {catch { + load [lindex \ + [glob -tails -directory [file dirname [info nameofexecutable]] \ + tclreg*[expr {[::tcl::pkgconfig get debug] ? {g} : {}}].dll] 0 \ + ] registry + }} + } + } + if { $::tcl_platform(platform) ne {windows} || [namespace which -command ::registry] eq "" } { + proc ::tcl::clock::_hasRegistry {} {return 0} + return 0 + } + return 1 +} + +#---------------------------------------------------------------------- +# # LoadWindowsDateTimeFormats -- # # Load the date/time formats from the Control Panel in Windows and @@ -696,8 +707,7 @@ proc ::tcl::clock::EnterLocale { locale } { proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } { # Bail out if we can't find the Registry - variable NoRegistry - if { [info exists NoRegistry] } return + if { ![_hasRegistry] } return if { ![catch { registry get "HKEY_CURRENT_USER\\Control Panel\\International" \ @@ -957,7 +967,7 @@ proc ::tcl::clock::SetupTimeZone { timezone {alias {}} } { if {! [info exists TZData($timezone)] } { - variable TimeZoneBad + variable TimeZoneBad if { [dict exists $TimeZoneBad $timezone] } { return -code error \ -errorcode [list CLOCK badTimeZone $timezone] \ @@ -1078,10 +1088,9 @@ proc ::tcl::clock::SetupTimeZone { timezone {alias {}} } { proc ::tcl::clock::GuessWindowsTimeZone {} { variable WinZoneInfo - variable NoRegistry variable TimeZoneBad - if { [info exists NoRegistry] } { + if { ![_hasRegistry] } { return :localtime } -- cgit v0.12 From 03e761f84241cf9f7934428a1180d54a7f4bfc6e Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 16:52:21 +0000 Subject: windows: small amend (speedup _hasRegistry in positive case) --- library/clock.tcl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/clock.tcl b/library/clock.tcl index 4a16f7f..11deafe 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -664,6 +664,7 @@ proc ::tcl::clock::EnterLocale { locale } { # #---------------------------------------------------------------------- proc ::tcl::clock::_hasRegistry {} { + set res 0 if { $::tcl_platform(platform) eq {windows} } { if { [catch { package require registry 1.1 }] } { # try to load registry directly from root (if uninstalled / development env): @@ -674,12 +675,12 @@ proc ::tcl::clock::_hasRegistry {} { ] registry }} } + if { [namespace which -command ::registry] ne "" } { + set res 1 + } } - if { $::tcl_platform(platform) ne {windows} || [namespace which -command ::registry] eq "" } { - proc ::tcl::clock::_hasRegistry {} {return 0} - return 0 - } - return 1 + proc ::tcl::clock::_hasRegistry {} [list return $res] + return $res } #---------------------------------------------------------------------- -- cgit v0.12 From fdc6c737b407148b143c86ccf668699a9609e312 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 17:19:19 +0000 Subject: added test case illustrating bug #20 - wrong relative clock calculation on negative month offset over threshold of a year --- tests/clock.test | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index d7e5796..9b1b06c 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -35510,6 +35510,24 @@ test clock-30.8 {clock add months, negative} { set x4 [clock format $f4 -format %Y-%m-%d -timezone :UTC] list $x1 $x2 $x3 $x4 } {2000-02-29 2000-01-31 1999-12-31 1999-11-30} +test clock-30.8a {clock add months, negative, over threshold of a year} { + set t [clock scan 2019-01-31 -format %Y-%m-%d -timezone :UTC] + list [clock format [clock add $t -1 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ + [clock format [clock add $t -2 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ + [clock format [clock add $t -3 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ + [clock format [clock add $t -4 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] +} {2018-12-31 2018-11-30 2018-10-31 2018-09-30} +test clock-30.8b {clock add months, negative, over threshold of a year} { + set t [clock scan 2000-01-28 -format %Y-%m-%d -timezone :UTC] + for {set i 1} {$i < 24} {incr i 1} { + set f1 [clock add $t -$i month -timezone :UTC] + set f2 [clock add $f1 $i month -timezone :UTC] + if {$f2 != $t} { + error "\[clock add $t -$i month -timezone :UTC\] does not consider\ + \[clock add $f1 $i month -timezone :UTC\] != $t" + } + } +} {} test clock-30.9 {clock add days} { set t [clock scan {2000-01-01 12:34:56} -format {%Y-%m-%d %H:%M:%S} \ -timezone :UTC] -- cgit v0.12 From 369a1d740465c776814cd9e9ebc451420b7da625 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 17:19:34 +0000 Subject: fixed relative clock calculation on negative month offset over threshold of a year: compiler/platform fix for negative offs if -1 % 12 results to -1 instead of 11 (removed by compilers where remainder is always positive) --- generic/tclClock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/generic/tclClock.c b/generic/tclClock.c index 75ef831..8e93310 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -4115,6 +4115,11 @@ repeat_rel: yyMonth += yyRelMonth - 1; yyYear += yyMonth / 12; m = yyMonth % 12; + /* compiler fix for negative offs - wrap y, m = (0, -1) -> (-1, 11) */ + if (m < 0) { + yyYear--; + m = 12 + m; + } yyMonth = m + 1; /* if the day doesn't exist in the current month, repair it */ -- cgit v0.12 -- cgit v0.12 From 5551e41e7a45a5eb226fc42d25176b7f6d852bb8 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 17:28:38 +0000 Subject: simplification of new tests --- tests/clock.test | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/clock.test b/tests/clock.test index 9b1b06c..b218793 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -35511,20 +35511,20 @@ test clock-30.8 {clock add months, negative} { list $x1 $x2 $x3 $x4 } {2000-02-29 2000-01-31 1999-12-31 1999-11-30} test clock-30.8a {clock add months, negative, over threshold of a year} { - set t [clock scan 2019-01-31 -format %Y-%m-%d -timezone :UTC] - list [clock format [clock add $t -1 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ - [clock format [clock add $t -2 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ - [clock format [clock add $t -3 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] \ - [clock format [clock add $t -4 month -timezone :UTC] -format %Y-%m-%d -timezone :UTC] + set t [clock scan 2019-01-31 -format %Y-%m-%d -gmt 1] + list [clock format [clock add $t -1 month -gmt 1] -format %Y-%m-%d -gmt 1] \ + [clock format [clock add $t -2 month -gmt 1] -format %Y-%m-%d -gmt 1] \ + [clock format [clock add $t -3 month -gmt 1] -format %Y-%m-%d -gmt 1] \ + [clock format [clock add $t -4 month -gmt 1] -format %Y-%m-%d -gmt 1] } {2018-12-31 2018-11-30 2018-10-31 2018-09-30} test clock-30.8b {clock add months, negative, over threshold of a year} { - set t [clock scan 2000-01-28 -format %Y-%m-%d -timezone :UTC] + set t [clock scan 2000-01-28 -format %Y-%m-%d -gmt 1] for {set i 1} {$i < 24} {incr i 1} { - set f1 [clock add $t -$i month -timezone :UTC] - set f2 [clock add $f1 $i month -timezone :UTC] + set f1 [clock add $t -$i month -gmt 1] + set f2 [clock add $f1 $i month -gmt 1] if {$f2 != $t} { - error "\[clock add $t -$i month -timezone :UTC\] does not consider\ - \[clock add $f1 $i month -timezone :UTC\] != $t" + error "\[clock add $t -$i month -gmt 1\] does not consider\ + \[clock add $f1 $i month -gmt 1\] != $t" } } } {} -- cgit v0.12 From 32cb6e1608b379ff45355ddb8b5ff0b0ab426053 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 17:36:11 +0000 Subject: compatibility to future 8.6 version ([6596c4af31e29b5d] introduced new internals TclUtfPrev/TclUtfNext in tclInt.h), avoids conflict with own implementation for previous version --- generic/tclStrIdxTree.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/generic/tclStrIdxTree.h b/generic/tclStrIdxTree.h index 6ed5170..cd393af 100644 --- a/generic/tclStrIdxTree.h +++ b/generic/tclStrIdxTree.h @@ -111,19 +111,6 @@ TclUtfFindEqualNCInLwr( return ret; } -static inline const char * -TclUtfNext( - register const char *src) /* The current location in the string. */ -{ - if (((unsigned char) *(src)) < 0xC0) { - return ++src; - } else { - Tcl_UniChar ch; - return src + TclUtfToUniChar(src, &ch); - } -} - - /* * Primitives to safe set, reset and free references. */ -- cgit v0.12 From 584d98d7036b54df0f42ec52de8bb6d4c8db278a Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:19:14 +0000 Subject: more tests time-zone independent --- tests/clock.test | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/clock.test b/tests/clock.test index 01a99b1..cb68a92 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36171,33 +36171,34 @@ test clock-34.11.3 {clock scan tests: same century switch} { set times [clock scan "1/1/39" -gmt true] } [clock scan "1/1/39" -format "%m/%d/%y" -gmt true] test clock-34.12 {clock scan, relative times} { - set time [clock scan "Oct 23, 1992 -1 day"] - clock format $time -format {%b %d, %Y} + set time [clock scan "Oct 23, 1992 -1 day" -gmt true] + clock format $time -format {%b %d, %Y} -gmt true } "Oct 22, 1992" test clock-34.13 {clock scan, ISO 8601 base date format} { - set time [clock scan "19921023"] - clock format $time -format {%b %d, %Y} + set time [clock scan "19921023" -gmt true] + clock format $time -format {%b %d, %Y} -gmt true } "Oct 23, 1992" test clock-34.14 {clock scan, ISO 8601 expanded date format} { - set time [clock scan "1992-10-23"] - clock format $time -format {%b %d, %Y} + set time [clock scan "1992-10-23" -gmt true] + clock format $time -format {%b %d, %Y} -gmt true } "Oct 23, 1992" test clock-34.15 {clock scan, DD-Mon-YYYY format} { - set time [clock scan "23-Oct-1992"] - clock format $time -format {%b %d, %Y} + set time [clock scan "23-Oct-1992" -gmt true] + clock format $time -format {%b %d, %Y} -gmt true } "Oct 23, 1992" test clock-34.16 {clock scan, ISO 8601 point in time format} { - set time [clock scan "19921023T235959"] - clock format $time -format {%b %d, %Y %H:%M:%S} + set time [clock scan "19921023T235959" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" test clock-34.17 {clock scan, ISO 8601 point in time format} { - set time [clock scan "19921023 235959"] - clock format $time -format {%b %d, %Y %H:%M:%S} + set time [clock scan "19921023 235959" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" test clock-34.18 {clock scan, ISO 8601 point in time format} { - set time [clock scan "19921023T000000"] - clock format $time -format {%b %d, %Y %H:%M:%S} + set time [clock scan "19921023T000000" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 00:00:00" + test clock-34.20.1 {clock scan tests (-TZ)} { set time [clock scan "31 Jan 14 23:59:59 -0100"] clock format $time -format {%b %d,%Y %H:%M:%S %Z} -gmt true -- cgit v0.12 From ac6a529dff6ba534d6228be196ab56632e205104 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:21:14 +0000 Subject: added test-cases illustrating bug #21: literal may be mistakenly recognized as a time-zone (doesn't consider word-boundaries) --- tests/clock.test | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index cb68a92..dd6356b 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36174,6 +36174,7 @@ test clock-34.12 {clock scan, relative times} { set time [clock scan "Oct 23, 1992 -1 day" -gmt true] clock format $time -format {%b %d, %Y} -gmt true } "Oct 22, 1992" + test clock-34.13 {clock scan, ISO 8601 base date format} { set time [clock scan "19921023" -gmt true] clock format $time -format {%b %d, %Y} -gmt true @@ -36190,14 +36191,52 @@ test clock-34.16 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023T235959" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" +test clock-34.16.2 {clock scan, ISO 8601 extended date time} { + set time [clock scan "1992-10-23T23:59:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" test clock-34.17 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023 235959" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" +test clock-34.17.2 {clock scan, ISO 8601 extended date time} { + set time [clock scan "1992-10-23 23:59:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" +test clock-34.17.3 {clock scan, TZ-word boundaries - Z is not TZ here } -body { + set time [clock scan "1992-10-23Z23:59:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} -returnCodes error -match glob \ + -result {unable to convert date-time string*} +test clock-34.17.4 {clock scan, TZ-word boundaries - Z is TZ UTC here} { + set time [clock scan "1992-10-23 Z 23:59:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" +test clock-34.17.5 {clock scan, ISO 8601 extended date time with UTC TZ} { + set time [clock scan "1992-10-23T23:59:59Z" -timezone :America/Detroit] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" test clock-34.18 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023T000000" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 00:00:00" +test clock-34.18.2 {clock scan, ISO 8601 extended date time} { + set time [clock scan "1992-10-23T00:00:00" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 00:00:00" +test clock-34.18.3 {clock scan, TZ-word boundaries - Z is not TZ here } -body { + set time [clock scan "1992-10-23Z00:00:00" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} -returnCodes error -match glob \ + -result {unable to convert date-time string*} +test clock-34.18.4 {clock scan, TZ-word boundaries - Z is TZ UTC here} { + set time [clock scan "1992-10-23 Z 00:00:00" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 00:00:00" +test clock-34.18.5 {clock scan, ISO 8601 extended date time with UTC TZ} { + set time [clock scan "1992-10-23T00:00:00Z" -timezone :America/Detroit] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 00:00:00" test clock-34.20.1 {clock scan tests (-TZ)} { set time [clock scan "31 Jan 14 23:59:59 -0100"] -- cgit v0.12 From 207e44ee21ca10f2b770aa1e2f64921524af2c03 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:21:59 +0000 Subject: ISO 8601 timestamp format accepts extended date and time (YYYY-MM-DD and hh:mm:ss); implements more strict TZ recognition rules by word-lookup (lookahead considering word boundaries, see test-cases), so avoid several conflicts, also confusing literal T in ISO timestamp with military TZ; closes #21 --- generic/tclDate.c | 374 +++++++++++++++++++++++++-------------------------- generic/tclGetDate.y | 72 +++++----- 2 files changed, 216 insertions(+), 230 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index df8aeb5..2ff30ac 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -501,16 +501,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 116 +#define YYLAST 114 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 28 +#define YYNTOKENS 29 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 18 +#define YYNNTS 21 /* YYNRULES -- Number of rules. */ -#define YYNRULES 66 +#define YYNRULES 70 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 106 +#define YYNSTATES 105 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -528,11 +528,11 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 27, 23, 25, 26, 24, 2, 2, + 2, 2, 2, 28, 23, 24, 27, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -559,12 +559,13 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint16 yyrline[] = { 0, 167, 167, 168, 169, 172, 175, 178, 181, 184, - 187, 190, 193, 197, 200, 206, 212, 220, 224, 228, - 232, 236, 240, 246, 247, 250, 254, 258, 262, 266, - 270, 276, 280, 285, 290, 295, 300, 304, 309, 313, - 318, 325, 329, 335, 344, 352, 360, 369, 379, 393, - 398, 401, 404, 407, 410, 413, 416, 421, 424, 429, - 433, 437, 443, 446, 451, 469, 472 + 187, 190, 193, 197, 200, 206, 212, 218, 223, 227, + 231, 235, 239, 243, 249, 250, 253, 257, 261, 265, + 269, 273, 279, 285, 289, 294, 299, 304, 305, 309, + 314, 318, 323, 330, 334, 340, 340, 342, 350, 355, + 363, 364, 367, 381, 386, 389, 392, 395, 398, 401, + 404, 409, 412, 417, 421, 425, 431, 434, 439, 457, + 460 }; #endif @@ -576,10 +577,11 @@ static const char *const yytname[] = "$end", "error", "$undefined", "tAGO", "tDAY", "tDAYZONE", "tID", "tMERIDIAN", "tMONTH", "tMONTH_UNIT", "tSTARDATE", "tSEC_UNIT", "tUNUMBER", "tZONE", "tZONEwO4", "tZONEwO2", "tEPOCH", "tDST", - "tISOBASE", "tDAY_UNIT", "tNEXT", "SP", "':'", "','", "'/'", "'-'", - "'.'", "'+'", "$accept", "spec", "item", "time", "zone", "comma", "day", - "date", "ordMonth", "iso", "trek", "relspec", "relunits", "sign", "unit", - "INTNUM", "number", "o_merid", YY_NULLPTR + "tISOBASE", "tDAY_UNIT", "tNEXT", "SP", "':'", "','", "'-'", "'/'", + "'T'", "'.'", "'+'", "$accept", "spec", "item", "iextime", "time", + "zone", "comma", "day", "iexdate", "date", "ordMonth", "isosep", "iso", + "trek", "relspec", "relunits", "sign", "unit", "INTNUM", "number", + "o_merid", YY_NULLPTR }; #endif @@ -590,14 +592,14 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 58, 44, 47, 45, 46, 43 + 275, 276, 58, 44, 45, 47, 84, 46, 43 }; # endif -#define YYPACT_NINF -17 +#define YYPACT_NINF -25 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-17))) + (!!((Yystate) == (-25))) #define YYTABLE_NINF -1 @@ -608,17 +610,17 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - -17, 48, -17, -9, -17, 34, -17, 19, -17, -2, - 30, -10, -10, -17, 8, -17, 0, 72, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, 52, - 18, -17, 16, -17, 49, -17, -9, -17, -17, 25, - -17, -17, 59, 60, 62, -5, -17, 19, 19, 20, - -17, 31, -17, -17, 70, -17, 16, -17, -17, 75, - 32, 16, -17, -17, 77, 81, -17, 6, 71, 69, - 73, -17, -17, 74, -17, 78, -17, -17, -17, -17, - 97, 16, -17, -17, -17, -17, 90, -17, 91, 92, - 93, 94, 95, -17, -17, 101, -17, -17, -17, 87, - 88, -17, 99, 100, -17, -17 + -25, 46, -25, -19, -25, 4, -25, 21, -25, -1, + 20, 60, 60, -25, 10, -25, 1, 67, -25, -25, + -25, 42, -25, -25, -25, -4, -25, -25, -25, -25, + -25, 49, 14, -25, 6, -25, 68, -25, -19, -25, + -25, 63, -25, -25, 80, 81, 26, 82, -25, 21, + 21, -25, -25, -25, 29, -25, -25, 88, -25, 6, + -25, -25, -25, 75, 86, -25, -25, 95, 30, 6, + -25, -25, 89, 90, -25, 7, 76, 79, 83, -25, + -25, -25, -25, -25, -25, 92, -25, -25, 101, 6, + -25, -25, -25, 94, -25, 97, 98, 99, 85, -25, + -25, -25, -25, -25, -25 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -626,31 +628,33 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 2, 0, 1, 25, 19, 0, 61, 0, 59, 62, - 18, 0, 0, 39, 33, 60, 0, 0, 57, 58, - 3, 5, 6, 9, 7, 8, 11, 12, 10, 50, - 0, 56, 64, 13, 23, 26, 36, 62, 63, 0, - 27, 14, 38, 0, 0, 0, 17, 0, 0, 0, - 44, 0, 30, 41, 62, 54, 0, 4, 49, 62, - 0, 22, 53, 24, 0, 0, 40, 65, 31, 0, - 0, 20, 21, 0, 43, 0, 47, 42, 55, 29, - 62, 0, 52, 37, 48, 66, 0, 15, 0, 0, - 0, 0, 0, 28, 51, 65, 32, 34, 35, 0, - 0, 16, 0, 0, 46, 45 + 2, 0, 1, 26, 20, 0, 65, 0, 63, 66, + 19, 0, 0, 41, 35, 64, 0, 0, 61, 62, + 3, 69, 5, 6, 9, 37, 7, 8, 11, 12, + 10, 54, 0, 60, 68, 13, 24, 27, 38, 66, + 67, 0, 28, 15, 40, 0, 0, 0, 18, 0, + 0, 49, 46, 45, 0, 31, 43, 66, 58, 0, + 4, 70, 17, 0, 0, 51, 53, 66, 0, 23, + 57, 25, 0, 0, 42, 69, 0, 0, 33, 21, + 22, 47, 48, 44, 59, 0, 50, 30, 66, 0, + 56, 39, 52, 0, 16, 0, 0, 0, 0, 29, + 55, 14, 36, 32, 34 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -17, -17, 96, -17, -17, 79, -17, -17, -17, -17, - -17, -17, -17, 22, -16, -6, -17, 21 + -25, -25, 96, -24, -25, -25, 74, -25, -25, -25, + -25, -25, -25, -25, -25, -25, 57, -16, -5, -25, + 39 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 1, 20, 21, 22, 35, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 87 + -1, 1, 20, 21, 22, 23, 37, 24, 25, 26, + 27, 54, 28, 29, 30, 31, 32, 33, 34, 35, + 62 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -658,75 +662,77 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 55, 39, 40, 69, 52, 41, 42, 70, 53, 6, - 56, 8, 54, 85, 34, 18, 62, 19, 38, 15, - 43, 49, 44, 45, 61, 6, 50, 8, 86, 51, - 59, 37, 73, 47, 48, 15, 38, 38, 74, 60, - 78, 71, 72, 75, 80, 82, 36, 46, 2, 76, - 38, 65, 3, 4, 81, 58, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 94, 14, 15, 16, 17, - 63, 66, 67, 18, 68, 19, 3, 4, 77, 79, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 83, - 14, 15, 16, 84, 89, 88, 91, 18, 90, 19, - 92, 93, 95, 96, 97, 98, 99, 100, 85, 102, - 103, 104, 105, 57, 0, 64, 101 + 58, 65, 41, 42, 36, 55, 43, 44, 63, 56, + 6, 59, 8, 57, 61, 6, 38, 8, 70, 40, + 15, 45, 64, 46, 47, 15, 67, 69, 51, 93, + 82, 52, 40, 39, 76, 68, 53, 48, 77, 40, + 86, 63, 88, 84, 79, 80, 2, 81, 40, 61, + 3, 4, 66, 90, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 89, 14, 15, 16, 17, 49, 50, + 18, 3, 4, 100, 19, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 18, 14, 15, 16, 19, 71, + 73, 18, 74, 75, 78, 19, 83, 85, 63, 87, + 95, 91, 92, 96, 98, 99, 101, 93, 97, 102, + 103, 104, 72, 60, 94 }; -static const yytype_int8 yycheck[] = +static const yytype_uint8 yycheck[] = { - 16, 7, 4, 8, 4, 7, 8, 12, 8, 9, - 16, 11, 12, 7, 23, 25, 32, 27, 18, 19, - 22, 13, 24, 25, 30, 9, 18, 11, 22, 21, - 12, 12, 12, 11, 12, 19, 18, 18, 18, 21, - 56, 47, 48, 12, 12, 61, 12, 17, 0, 18, - 18, 26, 4, 5, 60, 3, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 81, 18, 19, 20, 21, - 21, 12, 12, 25, 12, 27, 4, 5, 8, 4, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 12, - 18, 19, 20, 12, 25, 24, 22, 25, 25, 27, - 22, 4, 12, 12, 12, 12, 12, 12, 7, 22, - 22, 12, 12, 17, -1, 36, 95 + 16, 25, 7, 4, 23, 4, 7, 8, 12, 8, + 9, 16, 11, 12, 7, 9, 12, 11, 34, 18, + 19, 22, 26, 24, 25, 19, 12, 32, 18, 22, + 54, 21, 18, 12, 8, 21, 26, 17, 12, 18, + 64, 12, 12, 59, 49, 50, 0, 18, 18, 7, + 4, 5, 3, 69, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 68, 18, 19, 20, 21, 11, 12, + 24, 4, 5, 89, 28, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 24, 18, 19, 20, 28, 21, + 27, 24, 12, 12, 12, 28, 8, 22, 12, 4, + 24, 12, 12, 24, 12, 4, 12, 22, 25, 12, + 12, 12, 38, 17, 75 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 29, 0, 4, 5, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 18, 19, 20, 21, 25, 27, - 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 23, 33, 12, 12, 18, 43, - 4, 7, 8, 22, 24, 25, 17, 41, 41, 13, - 18, 21, 4, 8, 12, 42, 43, 30, 3, 12, - 21, 43, 42, 21, 33, 26, 12, 12, 12, 8, - 12, 43, 43, 12, 18, 12, 18, 8, 42, 4, - 12, 43, 42, 12, 12, 7, 22, 45, 24, 25, - 25, 22, 22, 4, 42, 12, 12, 12, 12, 12, - 12, 45, 22, 22, 12, 12 + 0, 30, 0, 4, 5, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 18, 19, 20, 21, 24, 28, + 31, 32, 33, 34, 36, 37, 38, 39, 41, 42, + 43, 44, 45, 46, 47, 48, 23, 35, 12, 12, + 18, 47, 4, 7, 8, 22, 24, 25, 17, 45, + 45, 18, 21, 26, 40, 4, 8, 12, 46, 47, + 31, 7, 49, 12, 26, 32, 3, 12, 21, 47, + 46, 21, 35, 27, 12, 12, 8, 12, 12, 47, + 47, 18, 32, 8, 46, 22, 32, 4, 12, 47, + 46, 12, 12, 22, 49, 24, 24, 25, 12, 4, + 46, 12, 12, 12, 12 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 28, 29, 29, 29, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, - 32, 32, 32, 33, 33, 34, 34, 34, 34, 34, - 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 36, 36, 37, 37, 37, 37, 37, 38, 39, - 39, 40, 40, 40, 40, 40, 40, 41, 41, 42, - 42, 42, 43, 43, 44, 45, 45 + 0, 29, 30, 30, 30, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 32, 33, 33, 33, 34, 34, + 34, 34, 34, 34, 35, 35, 36, 36, 36, 36, + 36, 36, 37, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 39, 39, 40, 40, 41, 41, 41, + 41, 41, 42, 43, 43, 44, 44, 44, 44, 44, + 44, 45, 45, 46, 46, 46, 47, 47, 48, 49, + 49 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 4, 6, 2, 1, 1, - 3, 3, 2, 1, 2, 1, 2, 2, 4, 3, - 2, 3, 5, 1, 5, 5, 2, 4, 2, 1, - 3, 2, 3, 3, 2, 7, 7, 3, 4, 2, - 1, 4, 3, 2, 2, 3, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1 + 1, 1, 1, 1, 5, 2, 4, 2, 2, 1, + 1, 3, 3, 2, 1, 2, 1, 2, 2, 4, + 3, 2, 5, 3, 5, 1, 5, 1, 2, 4, + 2, 1, 3, 2, 3, 1, 1, 3, 3, 2, + 3, 2, 4, 2, 1, 4, 3, 2, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1 }; @@ -1573,6 +1579,16 @@ yyreduce: case 14: { + yyHour = (yyvsp[-4].Number); + yyMinutes = (yyvsp[-2].Number); + yySeconds = (yyvsp[0].Number); + } + + break; + + case 15: + + { yyHour = (yyvsp[-1].Number); yyMinutes = 0; yySeconds = 0; @@ -1581,7 +1597,7 @@ yyreduce: break; - case 15: + case 16: { yyHour = (yyvsp[-3].Number); @@ -1592,18 +1608,15 @@ yyreduce: break; - case 16: + case 17: { - yyHour = (yyvsp[-5].Number); - yyMinutes = (yyvsp[-3].Number); - yySeconds = (yyvsp[-1].Number); yyMeridian = (yyvsp[0].Meridian); } break; - case 17: + case 18: { yyTimezone = (yyvsp[-1].Number); @@ -1612,7 +1625,7 @@ yyreduce: break; - case 18: + case 19: { yyTimezone = (yyvsp[0].Number); @@ -1621,7 +1634,7 @@ yyreduce: break; - case 19: + case 20: { yyTimezone = (yyvsp[0].Number); @@ -1630,7 +1643,7 @@ yyreduce: break; - case 20: + case 21: { /* GMT+0100, GMT-1000, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); @@ -1639,7 +1652,7 @@ yyreduce: break; - case 21: + case 22: { /* GMT+1, GMT-10, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) * 60); @@ -1648,7 +1661,7 @@ yyreduce: break; - case 22: + case 23: { /* +0100, -0100 */ yyTimezone = -(yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); @@ -1657,7 +1670,7 @@ yyreduce: break; - case 25: + case 26: { yyDayOrdinal = 1; @@ -1666,7 +1679,7 @@ yyreduce: break; - case 26: + case 27: { yyDayOrdinal = 1; @@ -1675,7 +1688,7 @@ yyreduce: break; - case 27: + case 28: { yyDayOrdinal = (yyvsp[-1].Number); @@ -1684,7 +1697,7 @@ yyreduce: break; - case 28: + case 29: { yyDayOrdinal = (yyvsp[-3].Number) * (yyvsp[-1].Number); @@ -1693,7 +1706,7 @@ yyreduce: break; - case 29: + case 30: { yyDayOrdinal = (yyvsp[-2].Number) * (yyvsp[-1].Number); @@ -1702,7 +1715,7 @@ yyreduce: break; - case 30: + case 31: { yyDayOrdinal = 2; @@ -1711,16 +1724,26 @@ yyreduce: break; - case 31: + case 32: { yyMonth = (yyvsp[-2].Number); yyDay = (yyvsp[0].Number); + yyYear = (yyvsp[-4].Number); } break; - case 32: + case 33: + + { + yyMonth = (yyvsp[-2].Number); + yyDay = (yyvsp[0].Number); + } + + break; + + case 34: { yyMonth = (yyvsp[-4].Number); @@ -1730,7 +1753,7 @@ yyreduce: break; - case 33: + case 35: { yyYear = (yyvsp[0].Number) / 10000; @@ -1740,7 +1763,7 @@ yyreduce: break; - case 34: + case 36: { yyDay = (yyvsp[-4].Number); @@ -1750,17 +1773,7 @@ yyreduce: break; - case 35: - - { - yyMonth = (yyvsp[-2].Number); - yyDay = (yyvsp[0].Number); - yyYear = (yyvsp[-4].Number); - } - - break; - - case 36: + case 38: { yyMonth = (yyvsp[-1].Number); @@ -1769,7 +1782,7 @@ yyreduce: break; - case 37: + case 39: { yyMonth = (yyvsp[-3].Number); @@ -1779,7 +1792,7 @@ yyreduce: break; - case 38: + case 40: { yyMonth = (yyvsp[0].Number); @@ -1788,7 +1801,7 @@ yyreduce: break; - case 39: + case 41: { yyMonth = 1; @@ -1798,7 +1811,7 @@ yyreduce: break; - case 40: + case 42: { yyMonth = (yyvsp[-1].Number); @@ -1808,7 +1821,7 @@ yyreduce: break; - case 41: + case 43: { yyMonthOrdinalIncr = 1; @@ -1817,7 +1830,7 @@ yyreduce: break; - case 42: + case 44: { yyMonthOrdinalIncr = (yyvsp[-1].Number); @@ -1826,10 +1839,9 @@ yyreduce: break; - case 43: + case 47: { - if ((yyvsp[-1].Number) != HOUR( 7)) YYABORT; /* T */ yyYear = (yyvsp[-2].Number) / 10000; yyMonth = ((yyvsp[-2].Number) % 10000)/100; yyDay = (yyvsp[-2].Number) % 100; @@ -1840,52 +1852,22 @@ yyreduce: break; - case 44: - - { - yyYear = (yyvsp[-1].Number) / 10000; - yyMonth = ((yyvsp[-1].Number) % 10000)/100; - yyDay = (yyvsp[-1].Number) % 100; - yyHour = (yyvsp[0].Number) / 10000; - yyMinutes = ((yyvsp[0].Number) % 10000)/100; - yySeconds = (yyvsp[0].Number) % 100; - } - - break; - - case 45: - - { - yyYear = (yyvsp[-6].Number) / 10000; - yyMonth = ((yyvsp[-6].Number) % 10000)/100; - yyDay = (yyvsp[-6].Number) % 100; - yyHour = (yyvsp[-4].Number); - yyMinutes = (yyvsp[-2].Number); - yySeconds = (yyvsp[0].Number); - } - - break; - - case 46: + case 48: { - if ((yyvsp[-5].Number) != HOUR( 7)) YYABORT; /* T */ - yyYear = (yyvsp[-6].Number) / 10000; - yyMonth = ((yyvsp[-6].Number) % 10000)/100; - yyDay = (yyvsp[-6].Number) % 100; - yyHour = (yyvsp[-4].Number); - yyMinutes = (yyvsp[-2].Number); - yySeconds = (yyvsp[0].Number); + yyYear = (yyvsp[-2].Number) / 10000; + yyMonth = ((yyvsp[-2].Number) % 10000)/100; + yyDay = (yyvsp[-2].Number) % 100; } break; - case 47: + case 49: { - yyYear = (yyvsp[-2].Number) / 10000; - yyMonth = ((yyvsp[-2].Number) % 10000)/100; - yyDay = (yyvsp[-2].Number) % 100; + yyYear = (yyvsp[-1].Number) / 10000; + yyMonth = ((yyvsp[-1].Number) % 10000)/100; + yyDay = (yyvsp[-1].Number) % 100; yyHour = (yyvsp[0].Number) / 10000; yyMinutes = ((yyvsp[0].Number) % 10000)/100; yySeconds = (yyvsp[0].Number) % 100; @@ -1893,7 +1875,7 @@ yyreduce: break; - case 48: + case 52: { /* @@ -1910,7 +1892,7 @@ yyreduce: break; - case 49: + case 53: { yyRelSeconds *= -1; @@ -1920,7 +1902,7 @@ yyreduce: break; - case 51: + case 55: { *yyRelPointer += (yyvsp[-3].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1928,7 +1910,7 @@ yyreduce: break; - case 52: + case 56: { *yyRelPointer += (yyvsp[-2].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1936,7 +1918,7 @@ yyreduce: break; - case 53: + case 57: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1944,7 +1926,7 @@ yyreduce: break; - case 54: + case 58: { *yyRelPointer += (yyvsp[0].Number); @@ -1952,7 +1934,7 @@ yyreduce: break; - case 55: + case 59: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1960,7 +1942,7 @@ yyreduce: break; - case 56: + case 60: { *yyRelPointer += (yyvsp[0].Number); @@ -1968,7 +1950,7 @@ yyreduce: break; - case 57: + case 61: { (yyval.Number) = -1; @@ -1976,7 +1958,7 @@ yyreduce: break; - case 58: + case 62: { (yyval.Number) = 1; @@ -1984,7 +1966,7 @@ yyreduce: break; - case 59: + case 63: { (yyval.Number) = (yyvsp[0].Number); @@ -1993,7 +1975,7 @@ yyreduce: break; - case 60: + case 64: { (yyval.Number) = (yyvsp[0].Number); @@ -2002,7 +1984,7 @@ yyreduce: break; - case 61: + case 65: { (yyval.Number) = (yyvsp[0].Number); @@ -2011,7 +1993,7 @@ yyreduce: break; - case 62: + case 66: { (yyval.Number) = (yyvsp[0].Number); @@ -2019,7 +2001,7 @@ yyreduce: break; - case 63: + case 67: { (yyval.Number) = (yyvsp[0].Number); @@ -2027,7 +2009,7 @@ yyreduce: break; - case 64: + case 68: { if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { @@ -2048,7 +2030,7 @@ yyreduce: break; - case 65: + case 69: { (yyval.Meridian) = MER24; @@ -2056,7 +2038,7 @@ yyreduce: break; - case 66: + case 70: { (yyval.Meridian) = (yyvsp[0].Meridian); @@ -2752,6 +2734,7 @@ TclDatelex( } if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ int ret; + const char *litStart = yyInput; for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { @@ -2763,12 +2746,19 @@ TclDatelex( location->last_column = yyInput - info->dateStart - 1; ret = LookupWord(yylvalPtr, buff); /* - * lookahead for +/- digit, to differentiate between "GMT+1000 day" and "GMT +1000 day", + * 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(c)) { /* literal not a TZ */ + yyInput = litStart; + return *yyInput++; + } if ((c == '+' || c == '-') && isdigit(UCHAR(*(yyInput+1)))) { if ( !isdigit(UCHAR(*(yyInput+2))) || !isdigit(UCHAR(*(yyInput+3)))) { diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 8594a3e..761324b 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -197,6 +197,12 @@ item : time { | number ; +iextime : tUNUMBER ':' tUNUMBER ':' tUNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + } + ; time : tUNUMBER tMERIDIAN { yyHour = $1; yyMinutes = 0; @@ -209,11 +215,8 @@ time : tUNUMBER tMERIDIAN { yySeconds = 0; yyMeridian = $4; } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = $6; + | iextime o_merid { + yyMeridian = $2; } ; @@ -273,6 +276,12 @@ day : tDAY { } ; +iexdate : tUNUMBER '-' tUNUMBER '-' tUNUMBER { + yyMonth = $3; + yyDay = $5; + yyYear = $1; + } + ; date : tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; @@ -292,11 +301,7 @@ date : tUNUMBER '/' tUNUMBER { yyMonth = $3; yyYear = $5; } - | tUNUMBER '-' tUNUMBER '-' tUNUMBER { - yyMonth = $3; - yyDay = $5; - yyYear = $1; - } + | iexdate | tMONTH tUNUMBER { yyMonth = $1; yyDay = $2; @@ -332,8 +337,9 @@ ordMonth: tNEXT tMONTH { } ; -iso : tISOBASE tZONE tISOBASE { - if ($2 != HOUR( 7)) YYABORT; /* T */ +isosep : 'T'|SP + ; +iso : tISOBASE isosep tISOBASE { yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; @@ -341,39 +347,21 @@ iso : tISOBASE tZONE tISOBASE { yyMinutes = ($3 % 10000)/100; yySeconds = $3 % 100; } - | tISOBASE tISOBASE { + | tISOBASE isosep iextime { yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; - yyHour = $2 / 10000; - yyMinutes = ($2 % 10000)/100; - yySeconds = $2 % 100; - } - | tISOBASE SP tUNUMBER ':' tUNUMBER ':' tUNUMBER { - yyYear = $1 / 10000; - yyMonth = ($1 % 10000)/100; - yyDay = $1 % 100; - yyHour = $3; - yyMinutes = $5; - yySeconds = $7; } - | tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER { - if ($2 != HOUR( 7)) YYABORT; /* T */ - yyYear = $1 / 10000; - yyMonth = ($1 % 10000)/100; - yyDay = $1 % 100; - yyHour = $3; - yyMinutes = $5; - yySeconds = $7; - } - | tISOBASE SP tISOBASE { + | tISOBASE tISOBASE { yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; - yyHour = $3 / 10000; - yyMinutes = ($3 % 10000)/100; - yySeconds = $3 % 100; + yyHour = $2 / 10000; + yyMinutes = ($2 % 10000)/100; + yySeconds = $2 % 100; } + | iexdate 'T' iextime + | iexdate iextime ; trek : tSTARDATE INTNUM '.' tUNUMBER { @@ -926,6 +914,7 @@ TclDatelex( } if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ int ret; + const char *litStart = yyInput; for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { @@ -937,12 +926,19 @@ TclDatelex( location->last_column = yyInput - info->dateStart - 1; ret = LookupWord(yylvalPtr, buff); /* - * lookahead for +/- digit, to differentiate between "GMT+1000 day" and "GMT +1000 day", + * 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(c)) { /* literal not a TZ */ + yyInput = litStart; + return *yyInput++; + } if ((c == '+' || c == '-') && isdigit(UCHAR(*(yyInput+1)))) { if ( !isdigit(UCHAR(*(yyInput+2))) || !isdigit(UCHAR(*(yyInput+3)))) { -- cgit v0.12 From 4a1bdef486f74a006c874f0faa7d32837b575ee9 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:22:09 +0000 Subject: optimized ISO 8601 timestamp (with extended formats, T literal is optional now, more tests); decreases conflicts (10 shift/reduce and 9 reduce/reduce only); --- generic/tclDate.c | 383 +++++++++++++++++++++++++++++---------------------- generic/tclGetDate.y | 101 +++++++++----- tests/clock.test | 8 ++ 3 files changed, 293 insertions(+), 199 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index 2ff30ac..77961a2 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -196,10 +196,12 @@ extern int TclDatedebug; tZONEwO2 = 270, tEPOCH = 271, tDST = 272, - tISOBASE = 273, - tDAY_UNIT = 274, - tNEXT = 275, - SP = 276 + tISOBAS8 = 273, + tISOBAS6 = 274, + tISOBASL = 275, + tDAY_UNIT = 276, + tNEXT = 277, + SP = 278 }; #endif @@ -501,21 +503,21 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 114 +#define YYLAST 121 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 29 +#define YYNTOKENS 31 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 21 +#define YYNNTS 23 /* YYNRULES -- Number of rules. */ -#define YYNRULES 70 +#define YYNRULES 73 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 105 +#define YYNSTATES 108 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 276 +#define YYMAXUTOK 278 #define YYTRANSLATE(YYX) \ ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -528,11 +530,11 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 28, 23, 24, 27, 25, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, + 2, 2, 2, 30, 25, 26, 29, 27, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -551,21 +553,21 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21 + 15, 16, 17, 18, 19, 20, 21, 22, 23 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 167, 167, 168, 169, 172, 175, 178, 181, 184, - 187, 190, 193, 197, 200, 206, 212, 218, 223, 227, - 231, 235, 239, 243, 249, 250, 253, 257, 261, 265, - 269, 273, 279, 285, 289, 294, 299, 304, 305, 309, - 314, 318, 323, 330, 334, 340, 340, 342, 350, 355, - 363, 364, 367, 381, 386, 389, 392, 395, 398, 401, - 404, 409, 412, 417, 421, 425, 431, 434, 439, 457, - 460 + 0, 171, 171, 172, 173, 176, 179, 182, 185, 188, + 191, 194, 197, 201, 204, 210, 216, 222, 227, 231, + 235, 239, 243, 247, 253, 254, 257, 261, 265, 269, + 273, 277, 283, 289, 293, 298, 299, 304, 308, 313, + 317, 322, 329, 333, 339, 339, 341, 346, 351, 353, + 358, 360, 361, 369, 380, 394, 399, 402, 405, 408, + 411, 414, 417, 422, 425, 430, 434, 438, 444, 447, + 450, 455, 473, 476 }; #endif @@ -577,11 +579,11 @@ static const char *const yytname[] = "$end", "error", "$undefined", "tAGO", "tDAY", "tDAYZONE", "tID", "tMERIDIAN", "tMONTH", "tMONTH_UNIT", "tSTARDATE", "tSEC_UNIT", "tUNUMBER", "tZONE", "tZONEwO4", "tZONEwO2", "tEPOCH", "tDST", - "tISOBASE", "tDAY_UNIT", "tNEXT", "SP", "':'", "','", "'-'", "'/'", - "'T'", "'.'", "'+'", "$accept", "spec", "item", "iextime", "time", - "zone", "comma", "day", "iexdate", "date", "ordMonth", "isosep", "iso", - "trek", "relspec", "relunits", "sign", "unit", "INTNUM", "number", - "o_merid", YY_NULLPTR + "tISOBAS8", "tISOBAS6", "tISOBASL", "tDAY_UNIT", "tNEXT", "SP", "':'", + "','", "'-'", "'/'", "'T'", "'.'", "'+'", "$accept", "spec", "item", + "iextime", "time", "zone", "comma", "day", "iexdate", "date", "ordMonth", + "isosep", "isodate", "isotime", "iso", "trek", "relspec", "relunits", + "sign", "unit", "INTNUM", "numitem", "o_merid", YY_NULLPTR }; #endif @@ -592,16 +594,17 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 58, 44, 45, 47, 84, 46, 43 + 275, 276, 277, 278, 58, 44, 45, 47, 84, 46, + 43 }; # endif -#define YYPACT_NINF -25 +#define YYPACT_NINF -21 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-25))) + (!!((Yystate) == (-21))) -#define YYTABLE_NINF -1 +#define YYTABLE_NINF -69 #define yytable_value_is_error(Yytable_value) \ 0 @@ -610,17 +613,17 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - -25, 46, -25, -19, -25, 4, -25, 21, -25, -1, - 20, 60, 60, -25, 10, -25, 1, 67, -25, -25, - -25, 42, -25, -25, -25, -4, -25, -25, -25, -25, - -25, 49, 14, -25, 6, -25, 68, -25, -19, -25, - -25, 63, -25, -25, 80, 81, 26, 82, -25, 21, - 21, -25, -25, -25, 29, -25, -25, 88, -25, 6, - -25, -25, -25, 75, 86, -25, -25, 95, 30, 6, - -25, -25, 89, 90, -25, 7, 76, 79, 83, -25, - -25, -25, -25, -25, -25, 92, -25, -25, 101, 6, - -25, -25, -25, 94, -25, 97, 98, 99, 85, -25, - -25, -25, -25, -25, -25 + -21, 66, -21, -20, -21, -5, -21, -9, -21, 86, + 24, 10, 10, -21, -21, -21, -4, -21, 97, 12, + -21, -21, -21, 6, -21, -21, -21, -21, -21, -21, + -17, -21, -21, -21, 54, 27, -21, -7, -21, 36, + -21, -20, -21, -21, -21, 31, -21, -21, 49, 50, + 46, 51, -21, -9, -9, -21, -21, -21, -21, 57, + -21, -7, -21, -21, -21, -21, -21, 25, -21, 63, + 37, -7, -21, -21, 56, 60, -21, 11, 43, 65, + 71, -21, -21, -21, -21, 59, -21, -21, -21, -21, + 95, -7, -21, -21, -21, 88, -21, 90, 91, 92, + 99, -21, -21, -21, -21, -21, -21, 93 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -628,98 +631,100 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 2, 0, 1, 26, 20, 0, 65, 0, 63, 66, - 19, 0, 0, 41, 35, 64, 0, 0, 61, 62, - 3, 69, 5, 6, 9, 37, 7, 8, 11, 12, - 10, 54, 0, 60, 68, 13, 24, 27, 38, 66, - 67, 0, 28, 15, 40, 0, 0, 0, 18, 0, - 0, 49, 46, 45, 0, 31, 43, 66, 58, 0, - 4, 70, 17, 0, 0, 51, 53, 66, 0, 23, - 57, 25, 0, 0, 42, 69, 0, 0, 33, 21, - 22, 47, 48, 44, 59, 0, 50, 30, 66, 0, - 56, 39, 52, 0, 16, 0, 0, 0, 0, 29, - 55, 14, 36, 32, 34 + 2, 0, 1, 26, 20, 0, 67, 0, 65, 71, + 19, 0, 0, 40, 46, 47, 0, 66, 0, 0, + 63, 64, 3, 72, 5, 6, 9, 48, 7, 8, + 35, 11, 12, 10, 56, 0, 62, 0, 13, 24, + 27, 37, 68, 70, 69, 0, 28, 15, 39, 0, + 0, 0, 18, 0, 0, 53, 52, 31, 42, 68, + 60, 0, 4, 73, 17, 45, 44, 0, 55, 68, + 0, 23, 59, 25, 0, 0, 41, 72, 0, 0, + 33, 21, 22, 43, 61, 0, 49, 50, 51, 30, + 68, 0, 58, 38, 54, 0, 16, 0, 0, 0, + 0, 29, 57, 14, 36, 32, 34, 0 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -25, -25, 96, -24, -25, -25, 74, -25, -25, -25, - -25, -25, -25, -25, -25, -25, 57, -16, -5, -25, - 39 + -21, -21, 100, 47, -21, -21, 79, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, 40, -18, + -6, -21, 44 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 1, 20, 21, 22, 23, 37, 24, 25, 26, - 27, 54, 28, 29, 30, 31, 32, 33, 34, 35, - 62 + -1, 1, 22, 23, 24, 25, 40, 26, 27, 28, + 29, 67, 30, 88, 31, 32, 33, 34, 35, 36, + 37, 38, 64 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_uint8 yytable[] = +static const yytype_int8 yytable[] = { - 58, 65, 41, 42, 36, 55, 43, 44, 63, 56, - 6, 59, 8, 57, 61, 6, 38, 8, 70, 40, - 15, 45, 64, 46, 47, 15, 67, 69, 51, 93, - 82, 52, 40, 39, 76, 68, 53, 48, 77, 40, - 86, 63, 88, 84, 79, 80, 2, 81, 40, 61, - 3, 4, 66, 90, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 89, 14, 15, 16, 17, 49, 50, - 18, 3, 4, 100, 19, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 18, 14, 15, 16, 19, 71, - 73, 18, 74, 75, 78, 19, 83, 85, 63, 87, - 95, 91, 92, 96, 98, 99, 101, 93, 97, 102, - 103, 104, 72, 60, 94 + 60, 45, 6, 42, 8, 39, 65, 41, 55, 43, + 44, 66, 61, 63, 17, 56, 3, 4, 63, 72, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 71, + 14, 15, 16, 17, 18, 95, 20, 85, 20, 69, + 21, 52, 21, 84, 86, 43, 44, 81, 82, 90, + 70, 53, 54, 92, 78, 43, 44, 68, 79, 73, + 75, 76, 77, 80, 91, 83, 2, 89, 93, 97, + 3, 4, 94, 102, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 100, 14, 15, 16, 17, 18, 19, + 46, 98, 20, 47, 48, -68, 21, -68, 99, 101, + 103, 57, 104, 105, 106, 58, 6, -68, 8, 59, + 49, 107, 50, 51, 87, 43, 44, 95, 17, 62, + 74, 96 }; static const yytype_uint8 yycheck[] = { - 16, 25, 7, 4, 23, 4, 7, 8, 12, 8, - 9, 16, 11, 12, 7, 9, 12, 11, 34, 18, - 19, 22, 26, 24, 25, 19, 12, 32, 18, 22, - 54, 21, 18, 12, 8, 21, 26, 17, 12, 18, - 64, 12, 12, 59, 49, 50, 0, 18, 18, 7, - 4, 5, 3, 69, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 68, 18, 19, 20, 21, 11, 12, - 24, 4, 5, 89, 28, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 24, 18, 19, 20, 28, 21, - 27, 24, 12, 12, 12, 28, 8, 22, 12, 4, - 24, 12, 12, 24, 12, 4, 12, 22, 25, 12, - 12, 12, 38, 17, 75 + 18, 7, 9, 12, 11, 25, 23, 12, 12, 18, + 19, 28, 18, 7, 21, 19, 4, 5, 7, 37, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 35, + 18, 19, 20, 21, 22, 24, 26, 12, 26, 12, + 30, 17, 30, 61, 19, 18, 19, 53, 54, 12, + 23, 11, 12, 71, 8, 18, 19, 3, 12, 23, + 29, 12, 12, 12, 70, 8, 0, 4, 12, 26, + 4, 5, 12, 91, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 24, 18, 19, 20, 21, 22, 23, + 4, 26, 26, 7, 8, 9, 30, 11, 27, 4, + 12, 4, 12, 12, 12, 8, 9, 21, 11, 12, + 24, 12, 26, 27, 67, 18, 19, 24, 21, 19, + 41, 77 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 30, 0, 4, 5, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 18, 19, 20, 21, 24, 28, - 31, 32, 33, 34, 36, 37, 38, 39, 41, 42, - 43, 44, 45, 46, 47, 48, 23, 35, 12, 12, - 18, 47, 4, 7, 8, 22, 24, 25, 17, 45, - 45, 18, 21, 26, 40, 4, 8, 12, 46, 47, - 31, 7, 49, 12, 26, 32, 3, 12, 21, 47, - 46, 21, 35, 27, 12, 12, 8, 12, 12, 47, - 47, 18, 32, 8, 46, 22, 32, 4, 12, 47, - 46, 12, 12, 22, 49, 24, 24, 25, 12, 4, - 46, 12, 12, 12, 12 + 0, 32, 0, 4, 5, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, + 26, 30, 33, 34, 35, 36, 38, 39, 40, 41, + 43, 45, 46, 47, 48, 49, 50, 51, 52, 25, + 37, 12, 12, 18, 19, 51, 4, 7, 8, 24, + 26, 27, 17, 49, 49, 12, 19, 4, 8, 12, + 50, 51, 33, 7, 53, 23, 28, 42, 3, 12, + 23, 51, 50, 23, 37, 29, 12, 12, 8, 12, + 12, 51, 51, 8, 50, 12, 19, 34, 44, 4, + 12, 51, 50, 12, 12, 24, 53, 26, 26, 27, + 24, 4, 50, 12, 12, 12, 12, 12 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 29, 30, 30, 30, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 32, 33, 33, 33, 34, 34, - 34, 34, 34, 34, 35, 35, 36, 36, 36, 36, - 36, 36, 37, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 39, 39, 40, 40, 41, 41, 41, - 41, 41, 42, 43, 43, 44, 44, 44, 44, 44, - 44, 45, 45, 46, 46, 46, 47, 47, 48, 49, - 49 + 0, 31, 32, 32, 32, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 34, 35, 35, 35, 36, 36, + 36, 36, 36, 36, 37, 37, 38, 38, 38, 38, + 38, 38, 39, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 42, 42, 43, 43, 43, 44, + 44, 45, 45, 45, 46, 47, 47, 48, 48, 48, + 48, 48, 48, 49, 49, 50, 50, 50, 51, 51, + 51, 52, 53, 53 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -728,11 +733,11 @@ static const yytype_uint8 yyr2[] = 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 2, 4, 2, 2, 1, 1, 3, 3, 2, 1, 2, 1, 2, 2, 4, - 3, 2, 5, 3, 5, 1, 5, 1, 2, 4, - 2, 1, 3, 2, 3, 1, 1, 3, 3, 2, - 3, 2, 4, 2, 1, 4, 3, 2, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 1 + 3, 2, 5, 3, 5, 1, 5, 2, 4, 2, + 1, 3, 2, 3, 1, 1, 1, 1, 1, 1, + 1, 3, 2, 2, 4, 2, 1, 4, 3, 2, + 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1 }; @@ -1753,16 +1758,6 @@ yyreduce: break; - case 35: - - { - yyYear = (yyvsp[0].Number) / 10000; - yyMonth = ((yyvsp[0].Number) % 10000)/100; - yyDay = (yyvsp[0].Number) % 100; - } - - break; - case 36: { @@ -1773,7 +1768,7 @@ yyreduce: break; - case 38: + case 37: { yyMonth = (yyvsp[-1].Number); @@ -1782,7 +1777,7 @@ yyreduce: break; - case 39: + case 38: { yyMonth = (yyvsp[-3].Number); @@ -1792,7 +1787,7 @@ yyreduce: break; - case 40: + case 39: { yyMonth = (yyvsp[0].Number); @@ -1801,7 +1796,7 @@ yyreduce: break; - case 41: + case 40: { yyMonth = 1; @@ -1811,7 +1806,7 @@ yyreduce: break; - case 42: + case 41: { yyMonth = (yyvsp[-1].Number); @@ -1821,7 +1816,7 @@ yyreduce: break; - case 43: + case 42: { yyMonthOrdinalIncr = 1; @@ -1830,7 +1825,7 @@ yyreduce: break; - case 44: + case 43: { yyMonthOrdinalIncr = (yyvsp[-1].Number); @@ -1839,25 +1834,22 @@ yyreduce: break; - case 47: + case 46: - { - yyYear = (yyvsp[-2].Number) / 10000; - yyMonth = ((yyvsp[-2].Number) % 10000)/100; - yyDay = (yyvsp[-2].Number) % 100; - yyHour = (yyvsp[0].Number) / 10000; - yyMinutes = ((yyvsp[0].Number) % 10000)/100; - yySeconds = (yyvsp[0].Number) % 100; + { /* YYYYMMDD */ + yyYear = (yyvsp[0].Number) / 10000; + yyMonth = ((yyvsp[0].Number) % 10000)/100; + yyDay = (yyvsp[0].Number) % 100; } break; - case 48: + case 47: - { - yyYear = (yyvsp[-2].Number) / 10000; - yyMonth = ((yyvsp[-2].Number) % 10000)/100; - yyDay = (yyvsp[-2].Number) % 100; + { /* YYMMDD */ + yyYear = (yyvsp[0].Number) / 10000; + yyMonth = ((yyvsp[0].Number) % 10000)/100; + yyDay = (yyvsp[0].Number) % 100; } break; @@ -1865,6 +1857,16 @@ yyreduce: case 49: { + yyHour = (yyvsp[0].Number) / 10000; + yyMinutes = ((yyvsp[0].Number) % 10000)/100; + yySeconds = (yyvsp[0].Number) % 100; + } + + break; + + case 52: + + { /* YYYYMMDDhhmmss */ yyYear = (yyvsp[-1].Number) / 10000; yyMonth = ((yyvsp[-1].Number) % 10000)/100; yyDay = (yyvsp[-1].Number) % 100; @@ -1875,7 +1877,21 @@ yyreduce: break; - case 52: + case 53: + + { /* YYYYMMDDhhmm */ + if (yyDigitCount != 4) YYABORT; /* normally unreached */ + yyYear = (yyvsp[-1].Number) / 10000; + yyMonth = ((yyvsp[-1].Number) % 10000)/100; + yyDay = (yyvsp[-1].Number) % 100; + yyHour = (yyvsp[0].Number) / 100; + yyMinutes = ((yyvsp[0].Number) % 100); + yySeconds = 0; + } + + break; + + case 54: { /* @@ -1892,7 +1908,7 @@ yyreduce: break; - case 53: + case 55: { yyRelSeconds *= -1; @@ -1902,7 +1918,7 @@ yyreduce: break; - case 55: + case 57: { *yyRelPointer += (yyvsp[-3].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1910,7 +1926,7 @@ yyreduce: break; - case 56: + case 58: { *yyRelPointer += (yyvsp[-2].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1918,7 +1934,7 @@ yyreduce: break; - case 57: + case 59: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1926,7 +1942,7 @@ yyreduce: break; - case 58: + case 60: { *yyRelPointer += (yyvsp[0].Number); @@ -1934,7 +1950,7 @@ yyreduce: break; - case 59: + case 61: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1942,7 +1958,7 @@ yyreduce: break; - case 60: + case 62: { *yyRelPointer += (yyvsp[0].Number); @@ -1950,7 +1966,7 @@ yyreduce: break; - case 61: + case 63: { (yyval.Number) = -1; @@ -1958,7 +1974,7 @@ yyreduce: break; - case 62: + case 64: { (yyval.Number) = 1; @@ -1966,7 +1982,7 @@ yyreduce: break; - case 63: + case 65: { (yyval.Number) = (yyvsp[0].Number); @@ -1975,7 +1991,7 @@ yyreduce: break; - case 64: + case 66: { (yyval.Number) = (yyvsp[0].Number); @@ -1984,7 +2000,7 @@ yyreduce: break; - case 65: + case 67: { (yyval.Number) = (yyvsp[0].Number); @@ -1993,7 +2009,7 @@ yyreduce: break; - case 66: + case 68: { (yyval.Number) = (yyvsp[0].Number); @@ -2001,7 +2017,7 @@ yyreduce: break; - case 67: + case 69: { (yyval.Number) = (yyvsp[0].Number); @@ -2009,7 +2025,15 @@ yyreduce: break; - case 68: + case 70: + + { + (yyval.Number) = (yyvsp[0].Number); + } + + break; + + case 71: { if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { @@ -2030,7 +2054,7 @@ yyreduce: break; - case 69: + case 72: { (yyval.Meridian) = MER24; @@ -2038,7 +2062,7 @@ yyreduce: break; - case 70: + case 73: { (yyval.Meridian) = (yyvsp[0].Meridian); @@ -2690,6 +2714,7 @@ TclDatelex( register char *p; char buff[20]; int Count; + const char *tokStart; location->first_column = yyInput - info->dateStart; for ( ; ; ) { @@ -2702,6 +2727,7 @@ TclDatelex( return SP; } } + tokStart = yyInput; if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ @@ -2711,30 +2737,51 @@ TclDatelex( register int num = c - '0'; p = (char *)yyInput; while (isdigit(UCHAR(c = *(++p)))) { - num *= 10; - num += c - '0'; - }; + if (num >= 0) { + num *= 10; num += c - '0'; + } + } yylvalPtr->Number = num; yyDigitCount = p - yyInput; yyInput = p; - /* ignore spaces after digits (optional) */ - yyInput = bypassSpaces(yyInput); /* * A number with 6 or more digits is considered an ISO 8601 base. */ + location->last_column = yyInput - info->dateStart - 1; if (yyDigitCount >= 6) { - location->last_column = yyInput - info->dateStart - 1; - return tISOBASE; - } else { - location->last_column = yyInput - info->dateStart - 1; - return tUNUMBER; + 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 *)tokStart; + num = *p++ - '0'; + do { + num *= 10; num += *p++ - '0'; + } while (p - tokStart < 8); + yylvalPtr->Number = num; + yyDigitCount = 8; + yyInput = p; + location->last_column = yyInput - info->dateStart - 1; + return tISOBASL; + } + if (num < 0) { /* overflow */ + return tID; + } + 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; - const char *litStart = yyInput; for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { @@ -2756,7 +2803,7 @@ TclDatelex( if (ret == tZONE || ret == tDAYZONE) { c = *yyInput; if (isdigit(c)) { /* literal not a TZ */ - yyInput = litStart; + yyInput = tokStart; return *yyInput++; } if ((c == '+' || c == '-') && isdigit(UCHAR(*(yyInput+1)))) { diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 761324b..c3df99e 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -137,7 +137,9 @@ MODULE_SCOPE int yyparse(DateInfo*); %token tZONEwO2 %token tEPOCH %token tDST -%token tISOBASE +%token tISOBAS8 +%token tISOBAS6 +%token tISOBASL %token tDAY_UNIT %token tNEXT %token SP @@ -153,7 +155,9 @@ MODULE_SCOPE int yyparse(DateInfo*); %type tZONE %type tZONEwO4 %type tZONEwO2 -%type tISOBASE +%type tISOBAS8 +%type tISOBAS6 +%type tISOBASL %type tDAY_UNIT %type unit %type sign @@ -194,7 +198,7 @@ item : time { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); info->flags |= CLF_RELCONV; } - | number + | numitem ; iextime : tUNUMBER ':' tUNUMBER ':' tUNUMBER { @@ -291,17 +295,12 @@ 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; } - | iexdate | tMONTH tUNUMBER { yyMonth = $1; yyDay = $2; @@ -339,20 +338,27 @@ ordMonth: tNEXT tMONTH { isosep : 'T'|SP ; -iso : tISOBASE isosep tISOBASE { +isodate : tISOBAS8 { /* YYYYMMDD */ yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; - yyHour = $3 / 10000; - yyMinutes = ($3 % 10000)/100; - yySeconds = $3 % 100; } - | tISOBASE isosep iextime { + | tISOBAS6 { /* YYMMDD */ yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; } - | 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; @@ -360,8 +366,15 @@ iso : tISOBASE isosep tISOBASE { yyMinutes = ($2 % 10000)/100; yySeconds = $2 % 100; } - | iexdate 'T' iextime - | iexdate iextime + | 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 INTNUM '.' tUNUMBER { @@ -431,12 +444,15 @@ unit : tSEC_UNIT { INTNUM : tUNUMBER { $$ = $1; } - | tISOBASE { + | tISOBAS6 { + $$ = $1; + } + | tISOBAS8 { $$ = $1; } ; -number : INTNUM { +numitem : tUNUMBER { if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { yyYear = $1; } else { @@ -870,6 +886,7 @@ TclDatelex( register char *p; char buff[20]; int Count; + const char *tokStart; location->first_column = yyInput - info->dateStart; for ( ; ; ) { @@ -882,6 +899,7 @@ TclDatelex( return SP; } } + tokStart = yyInput; if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ @@ -891,30 +909,51 @@ TclDatelex( register int num = c - '0'; p = (char *)yyInput; while (isdigit(UCHAR(c = *(++p)))) { - num *= 10; - num += c - '0'; - }; + if (num >= 0) { + num *= 10; num += c - '0'; + } + } yylvalPtr->Number = num; yyDigitCount = p - yyInput; yyInput = p; - /* ignore spaces after digits (optional) */ - yyInput = bypassSpaces(yyInput); /* * A number with 6 or more digits is considered an ISO 8601 base. */ + location->last_column = yyInput - info->dateStart - 1; if (yyDigitCount >= 6) { - location->last_column = yyInput - info->dateStart - 1; - return tISOBASE; - } else { - location->last_column = yyInput - info->dateStart - 1; - return tUNUMBER; + 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 *)tokStart; + num = *p++ - '0'; + do { + num *= 10; num += *p++ - '0'; + } while (p - tokStart < 8); + yylvalPtr->Number = num; + yyDigitCount = 8; + yyInput = p; + location->last_column = yyInput - info->dateStart - 1; + return tISOBASL; + } + if (num < 0) { /* overflow */ + return tID; + } + 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; - const char *litStart = yyInput; for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { @@ -936,7 +975,7 @@ TclDatelex( if (ret == tZONE || ret == tDAYZONE) { c = *yyInput; if (isdigit(c)) { /* literal not a TZ */ - yyInput = litStart; + yyInput = tokStart; return *yyInput++; } if ((c == '+' || c == '-') && isdigit(UCHAR(*(yyInput+1)))) { diff --git a/tests/clock.test b/tests/clock.test index dd6356b..5f18bf3 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36191,6 +36191,14 @@ test clock-34.16 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023T235959" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" +test clock-34.16.1a {clock scan, ISO 8601 T literal optional (YYYYMMDDhhmmss)} { + set time [clock scan "19921023235959" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" +test clock-34.16.1b {clock scan, ISO 8601 T literal optional (YYYYMMDDhhmm)} { + set time [clock scan "199210232359" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:00" test clock-34.16.2 {clock scan, ISO 8601 extended date time} { set time [clock scan "1992-10-23T23:59:59" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true -- cgit v0.12 From 65f65c4def78019de7475eeb66b9744ec60aa5ec Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:22:19 +0000 Subject: small amend to #21 allowing time without seconds part "hh:mm" as extended ISO time (with and without T literal) --- generic/tclDate.c | 119 +++++++++++++++++++++++++-------------------------- generic/tclGetDate.y | 11 +++-- tests/clock.test | 14 +++++- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index 77961a2..dd59d7e 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -512,7 +512,7 @@ union yyalloc /* YYNRULES -- Number of rules. */ #define YYNRULES 73 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 108 +#define YYNSTATES 105 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -561,13 +561,13 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint16 yyrline[] = { 0, 171, 171, 172, 173, 176, 179, 182, 185, 188, - 191, 194, 197, 201, 204, 210, 216, 222, 227, 231, - 235, 239, 243, 247, 253, 254, 257, 261, 265, 269, - 273, 277, 283, 289, 293, 298, 299, 304, 308, 313, - 317, 322, 329, 333, 339, 339, 341, 346, 351, 353, - 358, 360, 361, 369, 380, 394, 399, 402, 405, 408, - 411, 414, 417, 422, 425, 430, 434, 438, 444, 447, - 450, 455, 473, 476 + 191, 194, 197, 201, 204, 209, 215, 221, 226, 230, + 234, 238, 242, 246, 252, 253, 256, 260, 264, 268, + 272, 276, 282, 288, 292, 297, 298, 303, 307, 312, + 316, 321, 328, 332, 338, 338, 340, 345, 350, 352, + 357, 359, 360, 368, 379, 393, 398, 401, 404, 407, + 410, 413, 416, 421, 424, 429, 433, 437, 443, 446, + 449, 454, 472, 475 }; #endif @@ -613,17 +613,17 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - -21, 66, -21, -20, -21, -5, -21, -9, -21, 86, - 24, 10, 10, -21, -21, -21, -4, -21, 97, 12, - -21, -21, -21, 6, -21, -21, -21, -21, -21, -21, - -17, -21, -21, -21, 54, 27, -21, -7, -21, 36, - -21, -20, -21, -21, -21, 31, -21, -21, 49, 50, - 46, 51, -21, -9, -9, -21, -21, -21, -21, 57, - -21, -7, -21, -21, -21, -21, -21, 25, -21, 63, - 37, -7, -21, -21, 56, 60, -21, 11, 43, 65, - 71, -21, -21, -21, -21, 59, -21, -21, -21, -21, - 95, -7, -21, -21, -21, 88, -21, 90, 91, 92, - 99, -21, -21, -21, -21, -21, -21, 93 + -21, 66, -21, -20, -21, 1, -21, -9, -21, 86, + 18, 14, 14, -21, -21, -21, -4, -21, 97, 12, + -21, -21, -21, 30, -21, -21, -21, -21, -21, -21, + 13, -21, -21, -21, 48, 27, -21, -7, -21, 29, + -21, -20, -21, -21, -21, 28, -21, -21, 47, 49, + 46, 50, -21, -9, -9, -21, -21, -21, -21, 52, + -21, -7, -21, -21, -21, -21, -21, -1, -21, 59, + 37, -7, -21, -21, 53, 55, -21, 44, 43, 57, + 45, -21, -21, -21, -21, 67, -21, -21, -21, -21, + 94, -7, -21, -21, -21, 87, 88, 90, 91, -21, + -21, -21, -21, -21, -21 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -635,21 +635,21 @@ static const yytype_uint8 yydefact[] = 19, 0, 0, 40, 46, 47, 0, 66, 0, 0, 63, 64, 3, 72, 5, 6, 9, 48, 7, 8, 35, 11, 12, 10, 56, 0, 62, 0, 13, 24, - 27, 37, 68, 70, 69, 0, 28, 15, 39, 0, + 27, 37, 68, 70, 69, 0, 28, 16, 39, 0, 0, 0, 18, 0, 0, 53, 52, 31, 42, 68, 60, 0, 4, 73, 17, 45, 44, 0, 55, 68, - 0, 23, 59, 25, 0, 0, 41, 72, 0, 0, + 0, 23, 59, 25, 0, 0, 41, 15, 0, 0, 33, 21, 22, 43, 61, 0, 49, 50, 51, 30, - 68, 0, 58, 38, 54, 0, 16, 0, 0, 0, - 0, 29, 57, 14, 36, 32, 34, 0 + 68, 0, 58, 38, 54, 0, 0, 0, 0, 29, + 57, 14, 36, 32, 34 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -21, -21, 100, 47, -21, -21, 79, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, 40, -18, - -6, -21, 44 + -21, -21, 85, 54, -21, -21, 70, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -5, -18, + -6, -21, -21 }; /* YYDEFGOTO[NTERM-NUM]. */ @@ -665,36 +665,36 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { - 60, 45, 6, 42, 8, 39, 65, 41, 55, 43, - 44, 66, 61, 63, 17, 56, 3, 4, 63, 72, + 60, 45, 6, 42, 8, 39, 53, 54, 55, 43, + 44, 85, 61, 41, 17, 56, 3, 4, 86, 72, 5, 6, 7, 8, 9, 10, 11, 12, 13, 71, - 14, 15, 16, 17, 18, 95, 20, 85, 20, 69, - 21, 52, 21, 84, 86, 43, 44, 81, 82, 90, - 70, 53, 54, 92, 78, 43, 44, 68, 79, 73, - 75, 76, 77, 80, 91, 83, 2, 89, 93, 97, - 3, 4, 94, 102, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 100, 14, 15, 16, 17, 18, 19, - 46, 98, 20, 47, 48, -68, 21, -68, 99, 101, - 103, 57, 104, 105, 106, 58, 6, -68, 8, 59, - 49, 107, 50, 51, 87, 43, 44, 95, 17, 62, - 74, 96 + 14, 15, 16, 17, 18, 52, 65, 63, 20, 69, + 20, 66, 21, 84, 21, 43, 44, 81, 82, 90, + 70, 68, 73, 92, 78, 43, 44, 75, 79, 76, + 83, 77, 80, 89, 91, 93, 2, 94, 95, 96, + 3, 4, 98, 100, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 97, 14, 15, 16, 17, 18, 19, + 46, 49, 20, 47, 48, -68, 21, -68, 99, 101, + 102, 57, 103, 104, 62, 58, 6, -68, 8, 59, + 49, 74, 50, 51, 0, 43, 44, 0, 17, 0, + 0, 87 }; -static const yytype_uint8 yycheck[] = +static const yytype_int8 yycheck[] = { - 18, 7, 9, 12, 11, 25, 23, 12, 12, 18, - 19, 28, 18, 7, 21, 19, 4, 5, 7, 37, + 18, 7, 9, 12, 11, 25, 11, 12, 12, 18, + 19, 12, 18, 12, 21, 19, 4, 5, 19, 37, 8, 9, 10, 11, 12, 13, 14, 15, 16, 35, - 18, 19, 20, 21, 22, 24, 26, 12, 26, 12, - 30, 17, 30, 61, 19, 18, 19, 53, 54, 12, - 23, 11, 12, 71, 8, 18, 19, 3, 12, 23, - 29, 12, 12, 12, 70, 8, 0, 4, 12, 26, - 4, 5, 12, 91, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 24, 18, 19, 20, 21, 22, 23, - 4, 26, 26, 7, 8, 9, 30, 11, 27, 4, - 12, 4, 12, 12, 12, 8, 9, 21, 11, 12, - 24, 12, 26, 27, 67, 18, 19, 24, 21, 19, - 41, 77 + 18, 19, 20, 21, 22, 17, 23, 7, 26, 12, + 26, 28, 30, 61, 30, 18, 19, 53, 54, 12, + 23, 3, 23, 71, 8, 18, 19, 29, 12, 12, + 8, 12, 12, 4, 70, 12, 0, 12, 24, 26, + 4, 5, 27, 91, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 26, 18, 19, 20, 21, 22, 23, + 4, 24, 26, 7, 8, 9, 30, 11, 4, 12, + 12, 4, 12, 12, 19, 8, 9, 21, 11, 12, + 24, 41, 26, 27, -1, 18, 19, -1, 21, -1, + -1, 67 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -710,15 +710,15 @@ static const yytype_uint8 yystos[] = 50, 51, 33, 7, 53, 23, 28, 42, 3, 12, 23, 51, 50, 23, 37, 29, 12, 12, 8, 12, 12, 51, 51, 8, 50, 12, 19, 34, 44, 4, - 12, 51, 50, 12, 12, 24, 53, 26, 26, 27, - 24, 4, 50, 12, 12, 12, 12, 12 + 12, 51, 50, 12, 12, 24, 26, 26, 27, 4, + 50, 12, 12, 12, 12 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 31, 32, 32, 32, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 34, 35, 35, 35, 36, 36, + 33, 33, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 38, 38, 38, 38, 38, 38, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 42, 42, 43, 43, 43, 44, @@ -731,7 +731,7 @@ static const yytype_uint8 yyr1[] = static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 5, 2, 4, 2, 2, 1, + 1, 1, 1, 1, 5, 3, 2, 2, 2, 1, 1, 3, 3, 2, 1, 2, 1, 2, 2, 4, 3, 2, 5, 3, 5, 1, 5, 2, 4, 2, 1, 3, 2, 3, 1, 1, 1, 1, 1, 1, @@ -1594,10 +1594,9 @@ yyreduce: case 15: { - yyHour = (yyvsp[-1].Number); - yyMinutes = 0; + yyHour = (yyvsp[-2].Number); + yyMinutes = (yyvsp[0].Number); yySeconds = 0; - yyMeridian = (yyvsp[0].Meridian); } break; @@ -1605,8 +1604,8 @@ yyreduce: case 16: { - yyHour = (yyvsp[-3].Number); - yyMinutes = (yyvsp[-1].Number); + yyHour = (yyvsp[-1].Number); + yyMinutes = 0; yySeconds = 0; yyMeridian = (yyvsp[0].Meridian); } diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index c3df99e..0941d73 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -206,6 +206,11 @@ iextime : tUNUMBER ':' tUNUMBER ':' tUNUMBER { yyMinutes = $3; yySeconds = $5; } + | tUNUMBER ':' tUNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + } ; time : tUNUMBER tMERIDIAN { yyHour = $1; @@ -213,12 +218,6 @@ time : tUNUMBER tMERIDIAN { yySeconds = 0; yyMeridian = $2; } - | tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = 0; - yyMeridian = $4; - } | iextime o_merid { yyMeridian = $2; } diff --git a/tests/clock.test b/tests/clock.test index 5f18bf3..cffc803 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36207,10 +36207,22 @@ test clock-34.17 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023 235959" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" -test clock-34.17.2 {clock scan, ISO 8601 extended date time} { +test clock-34.17.2a {clock scan, ISO 8601 extended date time (YYYY-MM-DD hh:mm:ss)} { set time [clock scan "1992-10-23 23:59:59" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true } "Oct 23, 1992 23:59:59" +test clock-34.17.2b {clock scan, ISO 8601 extended date time (YYYY-MM-DDThh:mm:ss)} { + set time [clock scan "1992-10-23T23:59:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:59" +test clock-34.17.2c {clock scan, ISO 8601 extended date time (YYYY-MM-DD hh:mm)} { + set time [clock scan "1992-10-23 23:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:00" +test clock-34.17.2d {clock scan, ISO 8601 extended date time (YYYY-MM-DDThh:mm)} { + set time [clock scan "1992-10-23T23:59" -gmt true] + clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true +} "Oct 23, 1992 23:59:00" test clock-34.17.3 {clock scan, TZ-word boundaries - Z is not TZ here } -body { set time [clock scan "1992-10-23Z23:59:59" -gmt true] clock format $time -format {%b %d, %Y %H:%M:%S} -gmt true -- cgit v0.12 From 6e5bb624e6e80551a95eab130b1ee22a06dc90e6 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:26:46 +0000 Subject: resolves more shift/reduce conflicts (since SP token is expected by few items only, otherwise silently ignored) --- generic/tclDate.c | 286 +++++++++++++++++++++++++-------------------------- generic/tclGetDate.y | 2 +- 2 files changed, 142 insertions(+), 146 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index df8aeb5..f9173c5 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -501,16 +501,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 116 +#define YYLAST 97 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 28 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 18 /* YYNRULES -- Number of rules. */ -#define YYNRULES 66 +#define YYNRULES 65 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 106 +#define YYNSTATES 104 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -558,13 +558,13 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 167, 167, 168, 169, 172, 175, 178, 181, 184, - 187, 190, 193, 197, 200, 206, 212, 220, 224, 228, - 232, 236, 240, 246, 247, 250, 254, 258, 262, 266, - 270, 276, 280, 285, 290, 295, 300, 304, 309, 313, - 318, 325, 329, 335, 344, 352, 360, 369, 379, 393, - 398, 401, 404, 407, 410, 413, 416, 421, 424, 429, - 433, 437, 443, 446, 451, 469, 472 + 0, 167, 167, 168, 172, 175, 178, 181, 184, 187, + 190, 193, 197, 200, 206, 212, 220, 224, 228, 232, + 236, 240, 246, 247, 250, 254, 258, 262, 266, 270, + 276, 280, 285, 290, 295, 300, 304, 309, 313, 318, + 325, 329, 335, 344, 352, 360, 369, 379, 393, 398, + 401, 404, 407, 410, 413, 416, 421, 424, 429, 433, + 437, 443, 446, 451, 469, 472 }; #endif @@ -594,10 +594,10 @@ static const yytype_uint16 yytoknum[] = }; # endif -#define YYPACT_NINF -17 +#define YYPACT_NINF -18 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-17))) + (!!((Yystate) == (-18))) #define YYTABLE_NINF -1 @@ -608,17 +608,17 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - -17, 48, -17, -9, -17, 34, -17, 19, -17, -2, - 30, -10, -10, -17, 8, -17, 0, 72, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, 52, - 18, -17, 16, -17, 49, -17, -9, -17, -17, 25, - -17, -17, 59, 60, 62, -5, -17, 19, 19, 20, - -17, 31, -17, -17, 70, -17, 16, -17, -17, 75, - 32, 16, -17, -17, 77, 81, -17, 6, 71, 69, - 73, -17, -17, 74, -17, 78, -17, -17, -17, -17, - 97, 16, -17, -17, -17, -17, 90, -17, 91, 92, - 93, 94, 95, -17, -17, 101, -17, -17, -17, 87, - 88, -17, 99, 100, -17, -17 + -18, 17, -18, -17, -18, 45, -18, -5, -18, 42, + 30, 44, 44, -18, 35, -18, 0, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, 55, 33, + -18, 5, -18, 39, -18, -17, -18, -18, 46, -18, + -18, 58, 61, 62, 26, -18, -5, -5, 43, -18, + 47, -18, -18, 67, -18, 5, -18, 72, 50, 5, + -18, -18, 65, 66, -18, -2, 56, 54, 57, -18, + -18, 59, -18, 63, -18, -18, -18, -18, 79, 5, + -18, -18, -18, -18, 74, -18, 75, 76, 77, 78, + 80, -18, -18, 84, -18, -18, -18, 71, 73, -18, + 82, 85, -18, -18 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -626,31 +626,31 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 2, 0, 1, 25, 19, 0, 61, 0, 59, 62, - 18, 0, 0, 39, 33, 60, 0, 0, 57, 58, - 3, 5, 6, 9, 7, 8, 11, 12, 10, 50, - 0, 56, 64, 13, 23, 26, 36, 62, 63, 0, - 27, 14, 38, 0, 0, 0, 17, 0, 0, 0, - 44, 0, 30, 41, 62, 54, 0, 4, 49, 62, - 0, 22, 53, 24, 0, 0, 40, 65, 31, 0, - 0, 20, 21, 0, 43, 0, 47, 42, 55, 29, - 62, 0, 52, 37, 48, 66, 0, 15, 0, 0, - 0, 0, 0, 28, 51, 65, 32, 34, 35, 0, - 0, 16, 0, 0, 46, 45 + 2, 0, 1, 24, 18, 0, 60, 0, 58, 61, + 17, 0, 0, 38, 32, 59, 0, 56, 57, 3, + 4, 5, 8, 6, 7, 10, 11, 9, 49, 0, + 55, 63, 12, 22, 25, 35, 61, 62, 0, 26, + 13, 37, 0, 0, 0, 16, 0, 0, 0, 43, + 0, 29, 40, 61, 53, 0, 48, 61, 0, 21, + 52, 23, 0, 0, 39, 64, 30, 0, 0, 19, + 20, 0, 42, 0, 46, 41, 54, 28, 61, 0, + 51, 36, 47, 65, 0, 14, 0, 0, 0, 0, + 0, 27, 50, 64, 31, 33, 34, 0, 0, 15, + 0, 0, 45, 44 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -17, -17, 96, -17, -17, 79, -17, -17, -17, -17, - -17, -17, -17, 22, -16, -6, -17, 21 + -18, -18, -18, -18, -18, 49, -18, -18, -18, -18, + -18, -18, -18, -9, -16, -6, -18, 3 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 1, 20, 21, 22, 35, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 87 + -1, 1, 19, 20, 21, 34, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 85 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -658,34 +658,30 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 55, 39, 40, 69, 52, 41, 42, 70, 53, 6, - 56, 8, 54, 85, 34, 18, 62, 19, 38, 15, - 43, 49, 44, 45, 61, 6, 50, 8, 86, 51, - 59, 37, 73, 47, 48, 15, 38, 38, 74, 60, - 78, 71, 72, 75, 80, 82, 36, 46, 2, 76, - 38, 65, 3, 4, 81, 58, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 94, 14, 15, 16, 17, - 63, 66, 67, 18, 68, 19, 3, 4, 77, 79, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 83, - 14, 15, 16, 84, 89, 88, 91, 18, 90, 19, - 92, 93, 95, 96, 97, 98, 99, 100, 85, 102, - 103, 104, 105, 57, 0, 64, 101 + 54, 38, 46, 47, 51, 83, 33, 36, 52, 6, + 55, 8, 53, 37, 6, 60, 8, 2, 37, 15, + 84, 3, 4, 59, 15, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 67, 14, 15, 16, 68, 76, + 69, 70, 17, 80, 18, 57, 39, 45, 48, 40, + 41, 37, 79, 49, 58, 71, 50, 35, 56, 73, + 61, 72, 78, 92, 42, 74, 43, 44, 37, 17, + 64, 18, 63, 65, 66, 75, 77, 81, 82, 87, + 86, 89, 88, 91, 62, 90, 93, 94, 95, 96, + 97, 83, 98, 100, 102, 101, 99, 103 }; -static const yytype_int8 yycheck[] = +static const yytype_uint8 yycheck[] = { - 16, 7, 4, 8, 4, 7, 8, 12, 8, 9, - 16, 11, 12, 7, 23, 25, 32, 27, 18, 19, - 22, 13, 24, 25, 30, 9, 18, 11, 22, 21, - 12, 12, 12, 11, 12, 19, 18, 18, 18, 21, - 56, 47, 48, 12, 12, 61, 12, 17, 0, 18, - 18, 26, 4, 5, 60, 3, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 81, 18, 19, 20, 21, - 21, 12, 12, 25, 12, 27, 4, 5, 8, 4, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 12, - 18, 19, 20, 12, 25, 24, 22, 25, 25, 27, - 22, 4, 12, 12, 12, 12, 12, 12, 7, 22, - 22, 12, 12, 17, -1, 36, 95 + 16, 7, 11, 12, 4, 7, 23, 12, 8, 9, + 16, 11, 12, 18, 9, 31, 11, 0, 18, 19, + 22, 4, 5, 29, 19, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 8, 18, 19, 20, 12, 55, + 46, 47, 25, 59, 27, 12, 4, 17, 13, 7, + 8, 18, 58, 18, 21, 12, 21, 12, 3, 12, + 21, 18, 12, 79, 22, 18, 24, 25, 18, 25, + 12, 27, 26, 12, 12, 8, 4, 12, 12, 25, + 24, 22, 25, 4, 35, 22, 12, 12, 12, 12, + 12, 7, 12, 22, 12, 22, 93, 12 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -693,40 +689,40 @@ static const yytype_int8 yycheck[] = static const yytype_uint8 yystos[] = { 0, 29, 0, 4, 5, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 18, 19, 20, 21, 25, 27, - 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 23, 33, 12, 12, 18, 43, - 4, 7, 8, 22, 24, 25, 17, 41, 41, 13, - 18, 21, 4, 8, 12, 42, 43, 30, 3, 12, - 21, 43, 42, 21, 33, 26, 12, 12, 12, 8, - 12, 43, 43, 12, 18, 12, 18, 8, 42, 4, - 12, 43, 42, 12, 12, 7, 22, 45, 24, 25, - 25, 22, 22, 4, 42, 12, 12, 12, 12, 12, - 12, 45, 22, 22, 12, 12 + 13, 14, 15, 16, 18, 19, 20, 25, 27, 30, + 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 23, 33, 12, 12, 18, 43, 4, + 7, 8, 22, 24, 25, 17, 41, 41, 13, 18, + 21, 4, 8, 12, 42, 43, 3, 12, 21, 43, + 42, 21, 33, 26, 12, 12, 12, 8, 12, 43, + 43, 12, 18, 12, 18, 8, 42, 4, 12, 43, + 42, 12, 12, 7, 22, 45, 24, 25, 25, 22, + 22, 4, 42, 12, 12, 12, 12, 12, 12, 45, + 22, 22, 12, 12 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 28, 29, 29, 29, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, - 32, 32, 32, 33, 33, 34, 34, 34, 34, 34, - 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 36, 36, 37, 37, 37, 37, 37, 38, 39, - 39, 40, 40, 40, 40, 40, 40, 41, 41, 42, - 42, 42, 43, 43, 44, 45, 45 + 0, 28, 29, 29, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, + 32, 32, 33, 33, 34, 34, 34, 34, 34, 34, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 36, 36, 37, 37, 37, 37, 37, 38, 39, 39, + 40, 40, 40, 40, 40, 40, 41, 41, 42, 42, + 42, 43, 43, 44, 45, 45 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 0, 2, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 4, 6, 2, 1, 1, - 3, 3, 2, 1, 2, 1, 2, 2, 4, 3, - 2, 3, 5, 1, 5, 5, 2, 4, 2, 1, - 3, 2, 3, 3, 2, 7, 7, 3, 4, 2, - 1, 4, 3, 2, 2, 3, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1 + 0, 2, 0, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 4, 6, 2, 1, 1, 3, + 3, 2, 1, 2, 1, 2, 2, 4, 3, 2, + 3, 5, 1, 5, 5, 2, 4, 2, 1, 3, + 2, 3, 3, 2, 7, 7, 3, 4, 2, 1, + 4, 3, 2, 2, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1 }; @@ -1505,7 +1501,7 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 5: + case 4: { yyIncrFlags(CLF_TIME); @@ -1513,7 +1509,7 @@ yyreduce: break; - case 6: + case 5: { yyIncrFlags(CLF_ZONE); @@ -1521,7 +1517,7 @@ yyreduce: break; - case 7: + case 6: { yyIncrFlags(CLF_HAVEDATE); @@ -1529,7 +1525,7 @@ yyreduce: break; - case 8: + case 7: { yyIncrFlags(CLF_ORDINALMONTH); @@ -1537,7 +1533,7 @@ yyreduce: break; - case 9: + case 8: { yyIncrFlags(CLF_DAYOFWEEK); @@ -1545,7 +1541,7 @@ yyreduce: break; - case 10: + case 9: { info->flags |= CLF_RELCONV; @@ -1553,7 +1549,7 @@ yyreduce: break; - case 11: + case 10: { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); @@ -1561,7 +1557,7 @@ yyreduce: break; - case 12: + case 11: { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); @@ -1570,7 +1566,7 @@ yyreduce: break; - case 14: + case 13: { yyHour = (yyvsp[-1].Number); @@ -1581,7 +1577,7 @@ yyreduce: break; - case 15: + case 14: { yyHour = (yyvsp[-3].Number); @@ -1592,7 +1588,7 @@ yyreduce: break; - case 16: + case 15: { yyHour = (yyvsp[-5].Number); @@ -1603,7 +1599,7 @@ yyreduce: break; - case 17: + case 16: { yyTimezone = (yyvsp[-1].Number); @@ -1612,7 +1608,7 @@ yyreduce: break; - case 18: + case 17: { yyTimezone = (yyvsp[0].Number); @@ -1621,7 +1617,7 @@ yyreduce: break; - case 19: + case 18: { yyTimezone = (yyvsp[0].Number); @@ -1630,7 +1626,7 @@ yyreduce: break; - case 20: + case 19: { /* GMT+0100, GMT-1000, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); @@ -1639,7 +1635,7 @@ yyreduce: break; - case 21: + case 20: { /* GMT+1, GMT-10, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) * 60); @@ -1648,7 +1644,7 @@ yyreduce: break; - case 22: + case 21: { /* +0100, -0100 */ yyTimezone = -(yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); @@ -1657,7 +1653,7 @@ yyreduce: break; - case 25: + case 24: { yyDayOrdinal = 1; @@ -1666,7 +1662,7 @@ yyreduce: break; - case 26: + case 25: { yyDayOrdinal = 1; @@ -1675,7 +1671,7 @@ yyreduce: break; - case 27: + case 26: { yyDayOrdinal = (yyvsp[-1].Number); @@ -1684,7 +1680,7 @@ yyreduce: break; - case 28: + case 27: { yyDayOrdinal = (yyvsp[-3].Number) * (yyvsp[-1].Number); @@ -1693,7 +1689,7 @@ yyreduce: break; - case 29: + case 28: { yyDayOrdinal = (yyvsp[-2].Number) * (yyvsp[-1].Number); @@ -1702,7 +1698,7 @@ yyreduce: break; - case 30: + case 29: { yyDayOrdinal = 2; @@ -1711,7 +1707,7 @@ yyreduce: break; - case 31: + case 30: { yyMonth = (yyvsp[-2].Number); @@ -1720,7 +1716,7 @@ yyreduce: break; - case 32: + case 31: { yyMonth = (yyvsp[-4].Number); @@ -1730,7 +1726,7 @@ yyreduce: break; - case 33: + case 32: { yyYear = (yyvsp[0].Number) / 10000; @@ -1740,7 +1736,7 @@ yyreduce: break; - case 34: + case 33: { yyDay = (yyvsp[-4].Number); @@ -1750,7 +1746,7 @@ yyreduce: break; - case 35: + case 34: { yyMonth = (yyvsp[-2].Number); @@ -1760,7 +1756,7 @@ yyreduce: break; - case 36: + case 35: { yyMonth = (yyvsp[-1].Number); @@ -1769,7 +1765,7 @@ yyreduce: break; - case 37: + case 36: { yyMonth = (yyvsp[-3].Number); @@ -1779,7 +1775,7 @@ yyreduce: break; - case 38: + case 37: { yyMonth = (yyvsp[0].Number); @@ -1788,7 +1784,7 @@ yyreduce: break; - case 39: + case 38: { yyMonth = 1; @@ -1798,7 +1794,7 @@ yyreduce: break; - case 40: + case 39: { yyMonth = (yyvsp[-1].Number); @@ -1808,7 +1804,7 @@ yyreduce: break; - case 41: + case 40: { yyMonthOrdinalIncr = 1; @@ -1817,7 +1813,7 @@ yyreduce: break; - case 42: + case 41: { yyMonthOrdinalIncr = (yyvsp[-1].Number); @@ -1826,7 +1822,7 @@ yyreduce: break; - case 43: + case 42: { if ((yyvsp[-1].Number) != HOUR( 7)) YYABORT; /* T */ @@ -1840,7 +1836,7 @@ yyreduce: break; - case 44: + case 43: { yyYear = (yyvsp[-1].Number) / 10000; @@ -1853,7 +1849,7 @@ yyreduce: break; - case 45: + case 44: { yyYear = (yyvsp[-6].Number) / 10000; @@ -1866,7 +1862,7 @@ yyreduce: break; - case 46: + case 45: { if ((yyvsp[-5].Number) != HOUR( 7)) YYABORT; /* T */ @@ -1880,7 +1876,7 @@ yyreduce: break; - case 47: + case 46: { yyYear = (yyvsp[-2].Number) / 10000; @@ -1893,7 +1889,7 @@ yyreduce: break; - case 48: + case 47: { /* @@ -1910,7 +1906,7 @@ yyreduce: break; - case 49: + case 48: { yyRelSeconds *= -1; @@ -1920,7 +1916,7 @@ yyreduce: break; - case 51: + case 50: { *yyRelPointer += (yyvsp[-3].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1928,7 +1924,7 @@ yyreduce: break; - case 52: + case 51: { *yyRelPointer += (yyvsp[-2].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1936,7 +1932,7 @@ yyreduce: break; - case 53: + case 52: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1944,7 +1940,7 @@ yyreduce: break; - case 54: + case 53: { *yyRelPointer += (yyvsp[0].Number); @@ -1952,7 +1948,7 @@ yyreduce: break; - case 55: + case 54: { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); @@ -1960,7 +1956,7 @@ yyreduce: break; - case 56: + case 55: { *yyRelPointer += (yyvsp[0].Number); @@ -1968,7 +1964,7 @@ yyreduce: break; - case 57: + case 56: { (yyval.Number) = -1; @@ -1976,7 +1972,7 @@ yyreduce: break; - case 58: + case 57: { (yyval.Number) = 1; @@ -1984,7 +1980,7 @@ yyreduce: break; - case 59: + case 58: { (yyval.Number) = (yyvsp[0].Number); @@ -1993,7 +1989,7 @@ yyreduce: break; - case 60: + case 59: { (yyval.Number) = (yyvsp[0].Number); @@ -2002,7 +1998,7 @@ yyreduce: break; - case 61: + case 60: { (yyval.Number) = (yyvsp[0].Number); @@ -2011,7 +2007,7 @@ yyreduce: break; - case 62: + case 61: { (yyval.Number) = (yyvsp[0].Number); @@ -2019,7 +2015,7 @@ yyreduce: break; - case 63: + case 62: { (yyval.Number) = (yyvsp[0].Number); @@ -2027,7 +2023,7 @@ yyreduce: break; - case 64: + case 63: { if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { @@ -2048,7 +2044,7 @@ yyreduce: break; - case 65: + case 64: { (yyval.Meridian) = MER24; @@ -2056,7 +2052,7 @@ yyreduce: break; - case 66: + case 65: { (yyval.Meridian) = (yyvsp[0].Meridian); diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 8594a3e..6e37e20 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -166,7 +166,7 @@ MODULE_SCOPE int yyparse(DateInfo*); spec : /* NULL */ | spec item - | spec SP item + /* | spec SP item */ ; item : time { -- cgit v0.12 From b716ab245a4d7dc88ee33112cd7f08d2625da25f Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:35:05 +0000 Subject: rebuilt with bison 3.5; replace deprecated `%pure-parser` with `%define api.pure` --- generic/tclDate.c | 715 +++++++++++++++++++++++++-------------------------- generic/tclGetDate.y | 2 +- 2 files changed, 347 insertions(+), 370 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index 21e3960..625df6f 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -1,8 +1,9 @@ -/* A Bison parser, made by GNU Bison 3.1. */ +/* A Bison parser, made by GNU Bison 3.5.0. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, + Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,11 +41,14 @@ define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ +/* Undocumented macros, especially those whose name start with YY_, + are private implementation details. Do not rely on them. */ + /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.1" +#define YYBISON_VERSION "3.5.0" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -66,9 +70,7 @@ #define yydebug TclDatedebug #define yynerrs TclDatenerrs - -/* Copy the first part of user declarations. */ - +/* First part of user prologue. */ /* * tclDate.c -- @@ -150,12 +152,24 @@ typedef enum _DSTMODE { - +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif # ifndef YY_NULLPTR -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif # else -# define YY_NULLPTR 0 +# define YY_NULLPTR ((void*)0) # endif # endif @@ -207,17 +221,14 @@ extern int TclDatedebug; /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED - union YYSTYPE { - time_t Number; enum _MERIDIAN Meridian; }; - typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 @@ -243,8 +254,7 @@ int TclDateparse (DateInfo* info); -/* Copy the second part of user declarations. */ - +/* Second part of user prologue. */ /* @@ -265,28 +275,75 @@ MODULE_SCOPE int yyparse(DateInfo*); # undef short #endif -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif #endif -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; #else -typedef unsigned short yytype_uint16; +typedef short yytype_int16; #endif -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; #else -typedef short yytype_int16; +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif #endif #ifndef YYSIZE_T @@ -294,7 +351,7 @@ typedef short yytype_int16; # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t -# elif ! defined YYSIZE_T +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else @@ -302,7 +359,19 @@ typedef short yytype_int16; # endif #endif -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + +/* Stored state numbers (used for stacks). */ +typedef yytype_int8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS @@ -316,30 +385,19 @@ typedef short yytype_int16; # endif #endif -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else -# define YY_ATTRIBUTE(Spec) /* empty */ +# define YY_ATTRIBUTE_PURE # endif #endif -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - #ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# define YY_ATTRIBUTE_UNUSED # endif #endif @@ -352,11 +410,11 @@ typedef short yytype_int16; #if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value @@ -369,6 +427,20 @@ typedef short yytype_int16; # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) #if ! defined yyoverflow || YYERROR_VERBOSE @@ -446,18 +518,19 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; + yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + + YYSIZEOF (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 @@ -470,11 +543,11 @@ union yyalloc # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ - YYSIZE_T yynewbytes; \ + YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) @@ -486,12 +559,12 @@ union yyalloc # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ - YYSIZE_T yyi; \ + YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ @@ -514,17 +587,18 @@ union yyalloc /* YYNSTATES -- Number of states. */ #define YYNSTATES 103 -/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned - by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 278 + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ - ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + (0 <= (YYX) && (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, without out-of-bounds checking. */ -static const yytype_uint8 yytranslate[] = + as returned by yylex. */ +static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -558,7 +632,7 @@ static const yytype_uint8 yytranslate[] = #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = +static const yytype_int16 yyrline[] = { 0, 171, 171, 172, 176, 179, 182, 185, 188, 191, 194, 197, 201, 204, 209, 215, 221, 226, 230, 234, @@ -590,7 +664,7 @@ static const char *const yytname[] = # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ -static const yytype_uint16 yytoknum[] = +static const yytype_int16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, @@ -599,14 +673,14 @@ static const yytype_uint16 yytoknum[] = }; # endif -#define YYPACT_NINF -21 +#define YYPACT_NINF (-21) -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-21))) +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF -68 +#define YYTABLE_NINF (-68) -#define yytable_value_is_error(Yytable_value) \ +#define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing @@ -629,7 +703,7 @@ static const yytype_int8 yypact[] = /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ -static const yytype_uint8 yydefact[] = +static const yytype_int8 yydefact[] = { 2, 0, 1, 25, 19, 0, 66, 0, 64, 70, 18, 0, 0, 39, 45, 46, 0, 65, 0, 62, @@ -693,7 +767,7 @@ static const yytype_int8 yycheck[] = /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = +static const yytype_int8 yystos[] = { 0, 32, 0, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 26, @@ -709,7 +783,7 @@ static const yytype_uint8 yystos[] = }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = +static const yytype_int8 yyr1[] = { 0, 31, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 35, 35, 36, 36, 36, @@ -722,7 +796,7 @@ static const yytype_uint8 yyr1[] = }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = +static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 3, 2, 2, 2, 1, 1, @@ -747,22 +821,22 @@ static const yytype_uint8 yyr2[] = #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (&yylloc, info, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (0) +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, info, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) /* Error token number */ #define YYTERROR 1 @@ -821,10 +895,10 @@ do { \ /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED -static unsigned +static int yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { - unsigned res = 0; + int res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { @@ -867,41 +941,43 @@ do { \ } while (0) -/*----------------------------------------. -| Print this symbol's value on YYOUTPUT. | -`----------------------------------------*/ +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) +yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) { - FILE *yyo = yyoutput; - YYUSE (yyo); + FILE *yyoutput = yyo; + YYUSE (yyoutput); YYUSE (yylocationp); YYUSE (info); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); + YYPRINT (yyo, yytoknum[yytype], *yyvaluep); # endif + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END } -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) +yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) { - YYFPRINTF (yyoutput, "%s %s (", + YYFPRINTF (yyo, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - YY_LOCATION_PRINT (yyoutput, *yylocationp); - YYFPRINTF (yyoutput, ": "); - yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, info); - YYFPRINTF (yyoutput, ")"); + YY_LOCATION_PRINT (yyo, *yylocationp); + YYFPRINTF (yyo, ": "); + yy_symbol_value_print (yyo, yytype, yyvaluep, yylocationp, info); + YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. @@ -910,7 +986,7 @@ yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYL `------------------------------------------------------------------*/ static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) @@ -933,12 +1009,12 @@ do { \ `------------------------------------------------*/ static void -yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, DateInfo* info) +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, DateInfo* info) { - unsigned long yylno = yyrline[yyrule]; + int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) @@ -946,7 +1022,7 @@ yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], - &(yyvsp[(yyi + 1) - (yynrhs)]) + &yyvsp[(yyi + 1) - (yynrhs)] , &(yylsp[(yyi + 1) - (yynrhs)]) , info); YYFPRINTF (stderr, "\n"); } @@ -990,13 +1066,13 @@ int yydebug; # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) # else /* Return the length of YYSTR. */ -static YYSIZE_T +static YYPTRDIFF_T yystrlen (const char *yystr) { - YYSIZE_T yylen; + YYPTRDIFF_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; @@ -1032,12 +1108,12 @@ yystpcpy (char *yydest, const char *yysrc) backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ -static YYSIZE_T +static YYPTRDIFF_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { - YYSIZE_T yyn = 0; + YYPTRDIFF_T yyn = 0; char const *yyp = yystr; for (;;) @@ -1050,7 +1126,10 @@ yytnamerr (char *yyres, const char *yystr) case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; - /* Fall through. */ + else + goto append; + + append: default: if (yyres) yyres[yyn] = *yyp; @@ -1065,10 +1144,10 @@ yytnamerr (char *yyres, const char *yystr) do_not_strip_quotes: ; } - if (! yyres) + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; } # endif @@ -1081,19 +1160,19 @@ yytnamerr (char *yyres, const char *yystr) *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + yy_state_t *yyssp, int yytoken) { - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat. */ + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ + /* Actual size of YYARG. */ int yycount = 0; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then @@ -1121,6 +1200,8 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; + YYPTRDIFF_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + yysize = yysize0; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { @@ -1145,11 +1226,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } yyarg[yycount++] = yytname[yyx]; { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else return 2; - yysize = yysize1; } } } @@ -1172,10 +1254,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + /* Don't count the "%s"s in the final size, but reserve room for + the terminator. */ + YYPTRDIFF_T yysize1 = yysize + (yystrlen (yyformat) - 2 * yycount) + 1; + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else return 2; - yysize = yysize1; } if (*yymsg_alloc < yysize) @@ -1201,8 +1286,8 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, } else { - yyp++; - yyformat++; + ++yyp; + ++yyformat; } } return 0; @@ -1259,7 +1344,7 @@ YYLTYPE yylloc = yyloc_default; /* Number of syntax errors so far. */ int yynerrs; - int yystate; + yy_state_fast_t yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -1272,9 +1357,9 @@ YYLTYPE yylloc = yyloc_default; to reallocate them elsewhere. */ /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss; + yy_state_t *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; @@ -1289,7 +1374,7 @@ YYLTYPE yylloc = yyloc_default; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; - YYSIZE_T yystacksize; + YYPTRDIFF_T yystacksize; int yyn; int yyresult; @@ -1304,7 +1389,7 @@ YYLTYPE yylloc = yyloc_default; /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) @@ -1327,29 +1412,41 @@ YYLTYPE yylloc = yyloc_default; yylsp[0] = yylloc; goto yysetstate; + /*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | +| yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ - yynewstate: +yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; - yysetstate: - *yyssp = yystate; + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + goto yyexhaustedlab; +#else { /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; + YYPTRDIFF_T yysize = yyssp - yyss + 1; -#ifdef yyoverflow +# if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ + yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the @@ -1357,19 +1454,15 @@ YYLTYPE yylloc = yyloc_default; conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yyls1, yysize * YYSIZEOF (*yylsp), &yystacksize); - - yyls = yyls1; yyss = yyss1; yyvs = yyvs1; + yyls = yyls1; } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else +# else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; @@ -1378,44 +1471,45 @@ YYLTYPE yylloc = yyloc_default; yystacksize = YYMAXDEPTH; { - yytype_int16 *yyss1 = yyss; + yy_state_t *yyss1 = yyss; union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); -# undef YYSTACK_RELOCATE +# undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif -#endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long) yystacksize)); + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; + /*-----------. | yybackup. | `-----------*/ yybackup: - /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ @@ -1465,15 +1559,14 @@ yybackup: /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; + + /* Discard the shifted token. */ + yychar = YYEMPTY; goto yynewstate; @@ -1488,7 +1581,7 @@ yydefault: /*-----------------------------. -| yyreduce -- Do a reduction. | +| yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ @@ -1510,356 +1603,279 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 4: - - { + case 4: + { yyIncrFlags(CLF_TIME); } - break; case 5: - - { + { yyIncrFlags(CLF_ZONE); } - break; case 6: - - { + { yyIncrFlags(CLF_HAVEDATE); } - break; case 7: - - { + { yyIncrFlags(CLF_ORDINALMONTH); } - break; case 8: - - { + { yyIncrFlags(CLF_DAYOFWEEK); } - break; case 9: - - { + { info->flags |= CLF_RELCONV; } - break; case 10: - - { + { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); } - break; case 11: - - { + { yyIncrFlags(CLF_TIME|CLF_HAVEDATE); info->flags |= CLF_RELCONV; } - break; case 13: - - { + { yyHour = (yyvsp[-4].Number); yyMinutes = (yyvsp[-2].Number); yySeconds = (yyvsp[0].Number); } - break; case 14: - - { + { yyHour = (yyvsp[-2].Number); yyMinutes = (yyvsp[0].Number); yySeconds = 0; } - break; case 15: - - { + { yyHour = (yyvsp[-1].Number); yyMinutes = 0; yySeconds = 0; yyMeridian = (yyvsp[0].Meridian); } - break; case 16: - - { + { yyMeridian = (yyvsp[0].Meridian); } - break; case 17: - - { + { yyTimezone = (yyvsp[-1].Number); yyDSTmode = DSTon; } - break; case 18: - - { + { yyTimezone = (yyvsp[0].Number); yyDSTmode = DSToff; } - break; case 19: - - { + { yyTimezone = (yyvsp[0].Number); yyDSTmode = DSTon; } - break; case 20: - - { /* GMT+0100, GMT-1000, etc. */ + { /* GMT+0100, GMT-1000, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); yyDSTmode = DSToff; } - break; case 21: - - { /* GMT+1, GMT-10, etc. */ + { /* GMT+1, GMT-10, etc. */ yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) * 60); yyDSTmode = DSToff; } - break; case 22: - - { /* +0100, -0100 */ + { /* +0100, -0100 */ yyTimezone = -(yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60); yyDSTmode = DSToff; } - break; case 25: - - { + { yyDayOrdinal = 1; yyDayOfWeek = (yyvsp[0].Number); } - break; case 26: - - { + { yyDayOrdinal = 1; yyDayOfWeek = (yyvsp[-1].Number); } - break; case 27: - - { + { yyDayOrdinal = (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); } - break; case 28: - - { + { yyDayOrdinal = (yyvsp[-3].Number) * (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); } - break; case 29: - - { + { yyDayOrdinal = (yyvsp[-2].Number) * (yyvsp[-1].Number); yyDayOfWeek = (yyvsp[0].Number); } - break; case 30: - - { + { yyDayOrdinal = 2; yyDayOfWeek = (yyvsp[0].Number); } - break; case 31: - - { + { yyMonth = (yyvsp[-2].Number); yyDay = (yyvsp[0].Number); yyYear = (yyvsp[-4].Number); } - break; case 32: - - { + { yyMonth = (yyvsp[-2].Number); yyDay = (yyvsp[0].Number); } - break; case 33: - - { + { yyMonth = (yyvsp[-4].Number); yyDay = (yyvsp[-2].Number); yyYear = (yyvsp[0].Number); } - break; case 35: - - { + { yyDay = (yyvsp[-4].Number); yyMonth = (yyvsp[-2].Number); yyYear = (yyvsp[0].Number); } - break; case 36: - - { + { yyMonth = (yyvsp[-1].Number); yyDay = (yyvsp[0].Number); } - break; case 37: - - { + { yyMonth = (yyvsp[-3].Number); yyDay = (yyvsp[-2].Number); yyYear = (yyvsp[0].Number); } - break; case 38: - - { + { yyMonth = (yyvsp[0].Number); yyDay = (yyvsp[-1].Number); } - break; case 39: - - { + { yyMonth = 1; yyDay = 1; yyYear = EPOCH; } - break; case 40: - - { + { yyMonth = (yyvsp[-1].Number); yyDay = (yyvsp[-2].Number); yyYear = (yyvsp[0].Number); } - break; case 41: - - { + { yyMonthOrdinalIncr = 1; yyMonthOrdinal = (yyvsp[0].Number); } - break; case 42: - - { + { yyMonthOrdinalIncr = (yyvsp[-1].Number); yyMonthOrdinal = (yyvsp[0].Number); } - break; case 45: - - { /* YYYYMMDD */ + { /* YYYYMMDD */ yyYear = (yyvsp[0].Number) / 10000; yyMonth = ((yyvsp[0].Number) % 10000)/100; yyDay = (yyvsp[0].Number) % 100; } - break; case 46: - - { /* YYMMDD */ + { /* YYMMDD */ yyYear = (yyvsp[0].Number) / 10000; yyMonth = ((yyvsp[0].Number) % 10000)/100; yyDay = (yyvsp[0].Number) % 100; } - break; case 48: - - { + { yyHour = (yyvsp[0].Number) / 10000; yyMinutes = ((yyvsp[0].Number) % 10000)/100; yySeconds = (yyvsp[0].Number) % 100; } - break; case 51: - - { /* YYYYMMDDhhmmss */ + { /* YYYYMMDDhhmmss */ yyYear = (yyvsp[-1].Number) / 10000; yyMonth = ((yyvsp[-1].Number) % 10000)/100; yyDay = (yyvsp[-1].Number) % 100; @@ -1867,12 +1883,10 @@ yyreduce: yyMinutes = ((yyvsp[0].Number) % 10000)/100; yySeconds = (yyvsp[0].Number) % 100; } - break; case 52: - - { /* YYYYMMDDhhmm */ + { /* YYYYMMDDhhmm */ if (yyDigitCount != 4) YYABORT; /* normally unreached */ yyYear = (yyvsp[-1].Number) / 10000; yyMonth = ((yyvsp[-1].Number) % 10000)/100; @@ -1881,12 +1895,10 @@ yyreduce: yyMinutes = ((yyvsp[0].Number) % 100); yySeconds = 0; } - break; case 53: - - { + { /* * Offset computed year by -377 so that the returned years will be * in a range accessible with a 32 bit clock seconds value. @@ -1898,137 +1910,105 @@ yyreduce: yyRelDay += (((yyvsp[-2].Number)%1000)*(365 + IsLeapYear(yyYear)))/1000; yyRelSeconds += (yyvsp[0].Number) * 144 * 60; } - break; case 54: - - { + { yyRelSeconds *= -1; yyRelMonth *= -1; yyRelDay *= -1; } - break; case 56: - - { + { *yyRelPointer += (yyvsp[-3].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); } - break; case 57: - - { + { *yyRelPointer += (yyvsp[-2].Number) * (yyvsp[-1].Number) * (yyvsp[0].Number); } - break; case 58: - - { + { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); } - break; case 59: - - { + { *yyRelPointer += (yyvsp[0].Number); } - break; case 60: - - { + { *yyRelPointer += (yyvsp[-1].Number) * (yyvsp[0].Number); } - break; case 61: - - { + { *yyRelPointer += (yyvsp[0].Number); } - break; case 62: - - { + { (yyval.Number) = -1; } - break; case 63: - - { + { (yyval.Number) = 1; } - break; case 64: - - { + { (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelSeconds; } - break; case 65: - - { + { (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelDay; } - break; case 66: - - { + { (yyval.Number) = (yyvsp[0].Number); yyRelPointer = &yyRelMonth; } - break; case 67: - - { + { (yyval.Number) = (yyvsp[0].Number); } - break; case 68: - - { + { (yyval.Number) = (yyvsp[0].Number); } - break; case 69: - - { + { (yyval.Number) = (yyvsp[0].Number); } - break; case 70: - - { + { if ((info->flags & (CLF_TIME|CLF_HAVEDATE|CLF_RELCONV)) == (CLF_TIME|CLF_HAVEDATE)) { yyYear = (yyvsp[0].Number); } else { @@ -2044,23 +2024,18 @@ yyreduce: yyMeridian = MER24; } } - break; case 71: - - { + { (yyval.Meridian) = MER24; } - break; case 72: - - { + { (yyval.Meridian) = (yyvsp[0].Meridian); } - break; @@ -2090,14 +2065,13 @@ yyreduce: /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } goto yynewstate; @@ -2129,7 +2103,7 @@ yyerrlab: { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + yymsg = YY_CAST (char *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); if (!yymsg) { yymsg = yymsgbuf; @@ -2180,12 +2154,10 @@ yyerrlab: | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ @@ -2252,6 +2224,7 @@ yyacceptlab: yyresult = 0; goto yyreturn; + /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ @@ -2259,6 +2232,7 @@ yyabortlab: yyresult = 1; goto yyreturn; + #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | @@ -2269,6 +2243,10 @@ yyexhaustedlab: /* Fall through. */ #endif + +/*-----------------------------------------------------. +| yyreturn -- parsing is finished, return the result. | +`-----------------------------------------------------*/ yyreturn: if (yychar != YYEMPTY) { @@ -2299,7 +2277,6 @@ yyreturn: return yyresult; } - /* * Month and day table. */ diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 2febd30..04334d3 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -17,7 +17,7 @@ %parse-param {DateInfo* info} %lex-param {DateInfo* info} -%pure-parser +%define api.pure /* %error-verbose would be nice, but our token names are meaningless */ %locations -- cgit v0.12 From b50d4cd9cf51684cc3d3f0c71067617f48229644 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 22 Jun 2020 18:37:29 +0000 Subject: switch internal numbers to long (size of time_t is depending by platform, compiler, stdlib and its directives, and long is enough now for every part of input-string recognized inside of free-scan); this can drastically speedup scan (especially 32-bit platforms) --- generic/tclDate.c | 4 ++-- generic/tclGetDate.y | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index 625df6f..bb94955 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -139,7 +139,7 @@ typedef struct _TABLE { const char *name; int type; - time_t value; + long value; } TABLE; /* @@ -224,7 +224,7 @@ extern int TclDatedebug; union YYSTYPE { - time_t Number; + long Number; enum _MERIDIAN Meridian; diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 04334d3..b21320b 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -89,7 +89,7 @@ typedef struct _TABLE { const char *name; int type; - time_t value; + long value; } TABLE; /* @@ -103,7 +103,7 @@ typedef enum _DSTMODE { %} %union { - time_t Number; + long Number; enum _MERIDIAN Meridian; } -- cgit v0.12 From 1a2f289ff654579945f09d5d494fcccdc193966e Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 23 Jun 2020 19:21:22 +0000 Subject: optimizes locale cache: locale is case-sensitive key; simplifying format localization routine (cached within locale mc-catalog in C); clock::mcget - be sure we don't overwrite catalog of (common) locale {} (as it's a base of other catalogs loaded later). --- generic/tclClock.c | 34 +++++++++++--------- generic/tclClockFmt.c | 17 +++++++--- library/clock.tcl | 88 ++++++++++++++++++++++++--------------------------- 3 files changed, 72 insertions(+), 67 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 9f6a959..d0e5214 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -642,7 +642,7 @@ NormLocaleObj( if ( dataPtr->currentLocale != NULL && ( localeObj == dataPtr->currentLocale || (localeObj->length == dataPtr->currentLocale->length - && strcmp(loc, TclGetString(dataPtr->currentLocale)) == 0 + && strcasecmp(loc, TclGetString(dataPtr->currentLocale)) == 0 ) ) ) { @@ -652,7 +652,7 @@ NormLocaleObj( if ( dataPtr->lastUsedLocale != NULL && ( localeObj == dataPtr->lastUsedLocale || (localeObj->length == dataPtr->lastUsedLocale->length - && strcmp(loc, TclGetString(dataPtr->lastUsedLocale)) == 0 + && strcasecmp(loc, TclGetString(dataPtr->lastUsedLocale)) == 0 ) ) ) { @@ -663,7 +663,7 @@ NormLocaleObj( if ( dataPtr->prevUsedLocale != NULL && ( localeObj == dataPtr->prevUsedLocale || (localeObj->length == dataPtr->prevUsedLocale->length - && strcmp(loc, TclGetString(dataPtr->prevUsedLocale)) == 0 + && strcasecmp(loc, TclGetString(dataPtr->prevUsedLocale)) == 0 ) ) ) { @@ -756,18 +756,21 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) } } + /* check or obtain mcDictObj (be sure it's modifiable) */ if (opts->mcDictObj == NULL || opts->mcDictObj->refCount > 1) { - Tcl_Obj *callargs[2]; + int ref = 1; - /* first try to find it own catalog dict */ + /* first try to find locale catalog dict */ if (dataPtr->mcDicts == NULL) { Tcl_SetObjRef(dataPtr->mcDicts, Tcl_NewDictObj()); } Tcl_DictObjGet(NULL, dataPtr->mcDicts, opts->localeObj, &opts->mcDictObj); - if (opts->mcDictObj == NULL || opts->mcDictObj->refCount > 1) { + if (opts->mcDictObj == NULL) { /* get msgcat dictionary - ::tcl::clock::mcget locale */ + Tcl_Obj *callargs[2]; + callargs[0] = dataPtr->literals[LIT_MCGET]; callargs[1] = opts->localeObj; @@ -777,19 +780,20 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) opts->mcDictObj = Tcl_GetObjResult(opts->interp); Tcl_ResetResult(opts->interp); + ref = 0; /* new object is not yet referenced */ + } - /* be sure that object reference not increases (dict changeable) */ - if (opts->mcDictObj->refCount > 0) { - /* smart reference (shared dict as object with no ref-counter) */ - opts->mcDictObj = Tcl_DictObjSmartRef(opts->interp, - opts->mcDictObj); - } - - /* create exactly one reference to catalog / make it searchable for future */ - Tcl_DictObjPut(NULL, dataPtr->mcDicts, opts->localeObj, + /* be sure that object reference doesn't increase (dict changeable) */ + if (opts->mcDictObj->refCount > ref) { + /* smart reference (shared dict as object with no ref-counter) */ + opts->mcDictObj = Tcl_DictObjSmartRef(opts->interp, opts->mcDictObj); } + /* create exactly one reference to catalog / make it searchable for future */ + Tcl_DictObjPut(NULL, dataPtr->mcDicts, opts->localeObj, + opts->mcDictObj); + if ( opts->localeObj == dataPtr->literals[LIT_C] || opts->localeObj == dataPtr->defaultLocale ) { diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 2e63008..faf091e 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -844,14 +844,21 @@ ClockLocalizeFormat( callargs[0] = dataPtr->literals[LIT_LOCALIZE_FORMAT]; callargs[1] = opts->localeObj; callargs[2] = opts->formatObj; - callargs[3] = keyObj; - if (Tcl_EvalObjv(opts->interp, 4, callargs, 0) != TCL_OK + callargs[3] = opts->mcDictObj; + if (Tcl_EvalObjv(opts->interp, 4, callargs, 0) == TCL_OK ) { - goto done; + valObj = Tcl_GetObjResult(opts->interp); } - valObj = Tcl_GetObjResult(opts->interp); - + /* ensure mcDictObj remains unshared */ + if (opts->mcDictObj->refCount > 1) { + /* smart reference (shared dict as object with no ref-counter) */ + opts->mcDictObj = Tcl_DictObjSmartRef(opts->interp, + opts->mcDictObj); + } + if (!valObj) { + goto done; + } /* cache it inside mc-dictionary (this incr. ref count of keyObj/valObj) */ if (Tcl_DictObjPut(opts->interp, opts->mcDictObj, keyObj, valObj) != TCL_OK diff --git a/library/clock.tcl b/library/clock.tcl index 6638496..04d4777 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -477,8 +477,7 @@ proc ::tcl::clock::Initialize {} { # Caches - variable LocaleFormats \ - [dict create]; # Dictionary with localized formats + variable LocFmtMap [dict create]; # Dictionary with localized format maps variable TimeZoneBad [dict create]; # Dictionary whose keys are time zone # names and whose values are 1 if @@ -570,12 +569,18 @@ proc ::tcl::clock::mcMerge {locales} { set mrgcat [mcMerge [lrange $locales 1 end]] if {[dict exists $Msgs $ns $loc]} { set mrgcat [dict merge $mrgcat [dict get $Msgs $ns $loc]] + dict set mrgcat L $loc + } else { + # be sure a duplicate is created, don't overwrite {} (common) locale: + set mrgcat [dict merge $mrgcat [dict create L $loc]] } } else { if {[dict exists $Msgs $ns $loc]} { set mrgcat [dict get $Msgs $ns $loc] + dict set mrgcat L $loc } else { - set mrgcat [dict create] + # be sure a duplicate is created, don't overwrite {} (common) locale: + set mrgcat [dict create L $loc] } } dict set mcMergedCat $loc $mrgcat @@ -819,6 +824,8 @@ proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } { # locale -- Current [mclocale] locale, supplied to avoid # an extra call # format -- Format supplied to [clock scan] or [clock format] +# mcd -- Message catalog dictionary for current locale (read-only, +# don't store it to avoid shared references). # # Results: # Returns the string with locale-dependent composite format groups @@ -829,54 +836,41 @@ proc ::tcl::clock::LoadWindowsDateTimeFormats { locale } { # #---------------------------------------------------------------------- -proc ::tcl::clock::LocalizeFormat { locale format {fmtkey {}} } { - variable LocaleFormats +proc ::tcl::clock::LocalizeFormat { locale format mcd } { + variable LocFmtMap - if { $fmtkey eq {} } { set fmtkey FMT_$format } - if {[dict exists $LocaleFormats $locale $fmtkey]} { - set locfmt [dict get $LocaleFormats $locale $fmtkey] + # get map list cached or build it: + if {[dict exists $LocFmtMap $locale]} { + set mlst [dict get $LocFmtMap $locale] } else { - - # get map list cached or build it: - if {[dict exists $LocaleFormats $locale MLST]} { - set mlst [dict get $LocaleFormats $locale MLST] - } else { - - # message catalog dictionary: - set mcd [mcget $locale] - - # Handle locale-dependent format groups by mapping them out of the format - # string. Note that the order of the [string map] operations is - # significant because later formats can refer to later ones; for example - # %c can refer to %X, which in turn can refer to %T. - - set mlst { - %% %% - %D %m/%d/%Y - %+ {%a %b %e %H:%M:%S %Z %Y} - } - lappend mlst %EY [string map $mlst [dict get $mcd LOCALE_YEAR_FORMAT]] - lappend mlst %T [string map $mlst [dict get $mcd TIME_FORMAT_24_SECS]] - lappend mlst %R [string map $mlst [dict get $mcd TIME_FORMAT_24]] - lappend mlst %r [string map $mlst [dict get $mcd TIME_FORMAT_12]] - lappend mlst %X [string map $mlst [dict get $mcd TIME_FORMAT]] - lappend mlst %EX [string map $mlst [dict get $mcd LOCALE_TIME_FORMAT]] - lappend mlst %x [string map $mlst [dict get $mcd DATE_FORMAT]] - lappend mlst %Ex [string map $mlst [dict get $mcd LOCALE_DATE_FORMAT]] - lappend mlst %c [string map $mlst [dict get $mcd DATE_TIME_FORMAT]] - lappend mlst %Ec [string map $mlst [dict get $mcd LOCALE_DATE_TIME_FORMAT]] - - dict set LocaleFormats $locale MLST $mlst + # Handle locale-dependent format groups by mapping them out of the format + # string. Note that the order of the [string map] operations is + # significant because later formats can refer to later ones; for example + # %c can refer to %X, which in turn can refer to %T. + + set mlst { + %% %% + %D %m/%d/%Y + %+ {%a %b %e %H:%M:%S %Z %Y} } + lappend mlst %EY [string map $mlst [dict get $mcd LOCALE_YEAR_FORMAT]] + lappend mlst %T [string map $mlst [dict get $mcd TIME_FORMAT_24_SECS]] + lappend mlst %R [string map $mlst [dict get $mcd TIME_FORMAT_24]] + lappend mlst %r [string map $mlst [dict get $mcd TIME_FORMAT_12]] + lappend mlst %X [string map $mlst [dict get $mcd TIME_FORMAT]] + lappend mlst %EX [string map $mlst [dict get $mcd LOCALE_TIME_FORMAT]] + lappend mlst %x [string map $mlst [dict get $mcd DATE_FORMAT]] + lappend mlst %Ex [string map $mlst [dict get $mcd LOCALE_DATE_FORMAT]] + lappend mlst %c [string map $mlst [dict get $mcd DATE_TIME_FORMAT]] + lappend mlst %Ec [string map $mlst [dict get $mcd LOCALE_DATE_TIME_FORMAT]] - # translate copy of format (don't use format object here, because otherwise - # it can lose its internal representation (string map - convert to unicode) - set locfmt [string map $mlst [string range " $format" 1 end]] - - # cache it: - dict set LocaleFormats $locale $fmtkey $locfmt + dict set LocFmtMap $locale $mlst } + # translate copy of format (don't use format object here, because otherwise + # it can lose its internal representation (string map - convert to unicode) + set locfmt [string map $mlst [string range " $format" 1 end]] + # Save original format as long as possible, because of internal # representation (performance). # Note that in this case such format will be never localized (also @@ -2077,7 +2071,7 @@ proc ::tcl::clock::ChangeCurrentLocale {args} { #---------------------------------------------------------------------- proc ::tcl::clock::ClearCaches {} { - variable LocaleFormats + variable LocFmtMap variable mcMergedCat variable TimeZoneBad @@ -2087,7 +2081,7 @@ proc ::tcl::clock::ClearCaches {} { # clear msgcat cache: set mcMergedCat [dict create] - set LocaleFormats {} + set LocFmtMap {} set TimeZoneBad {} InitTZData } -- cgit v0.12 From 85ffaea615ec6d98e247362d60fecef192e26e5f Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 12 Oct 2020 16:47:09 +0000 Subject: Eliminate some eol-spacing, eliminate some gcc warnings (with -Wc++-compat) --- doc/clock.n | 6 +-- generic/tclClock.c | 40 +++++++-------- generic/tclClockFmt.c | 121 ++++++++++++++++++++++++---------------------- generic/tclDate.c | 6 +-- generic/tclDate.h | 8 +-- generic/tclGetDate.y | 6 +-- tests-perf/clock.perf.tcl | 14 +++--- 7 files changed, 104 insertions(+), 97 deletions(-) diff --git a/doc/clock.n b/doc/clock.n index 4440c4d..7f05127 100644 --- a/doc/clock.n +++ b/doc/clock.n @@ -581,7 +581,7 @@ The epoch time of 1 January 1970 corresponds to Astronomical JDN 2440588. \fB%Es\fR This affects similar to \fB%s\fR, but in opposition to \fB%s\fR it parses or formats local seconds (not the posix seconds). -Because \fB%s\fR has the same precedence as \fB%s\fR (uniquely determines +Because \fB%s\fR has the same precedence as \fB%s\fR (uniquely determines a point in time), it overrides all other input formats. .TP \fB%Ex\fR @@ -778,7 +778,7 @@ week number \fB%V\fR; programs should use \fB%G\fR for that purpose. On output, produces the current time zone, expressed in hours and minutes east (+hhmm) or west (\-hhmm) of Greenwich. On input, accepts a time zone specifier (see \fBTIME ZONES\fR below) that will be used to -determine the time zone (this token is optionally applicable on input, +determine the time zone (this token is optionally applicable on input, so the value is not mandatory and can be missing in input). .TP \fB%Z\fR @@ -994,7 +994,7 @@ precision of type of the token. In example below the second date-string contains "next January", therefore it results in next year but in January. And third date-string besides "January" contains also additionally "Fri", so it results in the nearest Friday. -Thus both win before "385 days" resp. make it more precise, because of higher +Thus both win before "385 days" resp. make it more precise, because of higher precision of this token types. .CS % clock format [clock scan "5 years 18 months 385 days" -base 0 -gmt 1] -gmt 1 diff --git a/generic/tclClock.c b/generic/tclClock.c index 8a64441..801d576 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -240,7 +240,7 @@ TclClockInit( data->validMinYear = INT_MIN; data->validMaxYear = INT_MAX; /* corresponds max of JDN in sqlite - 9999-12-31 23:59:59 per default */ - data->maxJDN = 5373484.499999994; + data->maxJDN = 5373484.499999994; data->systemTimeZone = NULL; data->systemSetupTZData = NULL; @@ -341,7 +341,7 @@ ClockConfigureClear( data->prevUsedLocaleDict = NULL; Tcl_UnsetObjRef(data->lastBase.timezoneObj); - + Tcl_UnsetObjRef(data->lastTZOffsCache[0].timezoneObj); Tcl_UnsetObjRef(data->lastTZOffsCache[0].tzName); Tcl_UnsetObjRef(data->lastTZOffsCache[1].timezoneObj); @@ -1950,7 +1950,7 @@ ConvertLocalToUTC( return TCL_OK; } else { - Tcl_WideInt rangesVal[2]; + Tcl_WideInt rangesVal[2]; if (ConvertLocalToUTCUsingTable(interp, fields, rowc, rowv, rangesVal) != TCL_OK) { @@ -1985,8 +1985,8 @@ ConvertLocalToUTC( dstHole: #if 0 printf("given local-time is outside the time-zone (in DST-hole): " - "%d - offs %d => %d <= %d < %d\n", - (int)fields->localSeconds, fields->tzOffset, + "%d - offs %d => %d <= %d < %d\n", + (int)fields->localSeconds, fields->tzOffset, (int)ltzoc->rangesVal[0], (int)seconds, (int)ltzoc->rangesVal[1]); #endif /* because we don't know real TZ (we're outsize), just invalidate local @@ -2246,7 +2246,7 @@ ConvertUTCToLocal( /* we cannot cache (ranges unknown yet) */ } else { - Tcl_WideInt rangesVal[2]; + Tcl_WideInt rangesVal[2]; if (ConvertUTCToLocalUsingTable(interp, fields, rowc, rowv, rangesVal) != TCL_OK) { @@ -2707,7 +2707,7 @@ GetMonthDay( int month; const int *dipm = daysInPriorMonths[IsGregorianLeapYear(fields)]; - /* + /* * Estimate month by calculating `dayOfYear / (365/12)` */ month = (day*12) / dipm[12]; @@ -3330,7 +3330,7 @@ ClockParseFmtScnArgs( } /* if already specified */ if (saw & (1 << optionIndex)) { - if ( !(flags & CLC_SCN_ARGS) + if ( !(flags & CLC_SCN_ARGS) && optionIndex == CLC_ARGS_BASE) { goto badOptionMsg; } @@ -3442,7 +3442,7 @@ ClockParseFmtScnArgs( } /* * Seconds could be an unsigned number that overflowed. Make sure - * that it isn't. Additionally it may be too complex to calculate + * that it isn't. Additionally it may be too complex to calculate * julianday etc (forwards/backwards) by too large/small values, thus * just let accept a bit shorter values to avoid overflow. * Note the year is currently an integer, thus avoid to overflow it also. @@ -3753,7 +3753,7 @@ ClockScanCommit( } if (info->flags & (CLF_ASSEMBLE_SECONDS|CLF_LOCALSEC)) { - if (ConvertLocalToUTC(opts->clientData, opts->interp, &yydate, + if (ConvertLocalToUTC(opts->clientData, opts->interp, &yydate, opts->timezoneObj, GREGORIAN_CHANGE_DATE) != TCL_OK) { return TCL_ERROR; } @@ -3796,7 +3796,7 @@ ClockValidDate( #if 0 printf("yyMonth %d, yyDay %d, yyDayOfYear %d, yyHour %d, yyMinutes %d, yySeconds %d, " "yySecondOfDay %d, sec %d, daySec %d, tzOffset %d\n", - yyMonth, yyDay, yydate.dayOfYear, yyHour, yyMinutes, yySeconds, + yyMonth, yyDay, yydate.dayOfYear, yyHour, yyMinutes, yySeconds, yySecondOfDay, (int)yydate.localSeconds, (int)(yydate.localSeconds % SECONDS_PER_DAY), yydate.tzOffset); #endif @@ -3814,7 +3814,7 @@ ClockValidDate( } } if (info->flags & CLF_YEAR) { - if ( yyYear < dataPtr->validMinYear + if ( yyYear < dataPtr->validMinYear || yyYear > dataPtr->validMaxYear ) { errMsg = "invalid year"; errCode = "year"; goto error; } @@ -3839,7 +3839,7 @@ ClockValidDate( if ( yyDay < 1 || yyDay > 31 ) { errMsg = "invalid day"; errCode = "day"; goto error; } - else + else if ( (info->flags & CLF_MONTH) ) { const int *h = hath[IsGregorianLeapYear(&yydate)]; if ( yyDay > h[yyMonth-1] ) { @@ -3886,7 +3886,7 @@ ClockValidDate( return TCL_OK; } - /* + /* * Further tests expected ready calculated julianDay (inclusive relative), * and time-zone conversion (local to UTC time). */ @@ -3895,14 +3895,14 @@ ClockValidDate( /* time, regarding the modifications by the time-zone (looks for given time * in between DST-time hole, so does not exist in this time-zone) */ if (info->flags & CLF_TIME) { - /* - * we don't need to do the backwards time-conversion (UTC to local) and - * compare results, because the after conversion (local to UTC) we + /* + * we don't need to do the backwards time-conversion (UTC to local) and + * compare results, because the after conversion (local to UTC) we * should have valid localSeconds (was not invalidated to TCL_INV_SECONDS), * so if it was invalidated - invalid time, outside the time-zone (in DST-hole) */ if ( yydate.localSeconds == TCL_INV_SECONDS ) { - errMsg = "invalid time (does not exist in this time-zone)"; + errMsg = "invalid time (does not exist in this time-zone)"; errCode = "out-of-time"; goto error; } } @@ -4017,7 +4017,7 @@ ClockFreeScan( info->flags |= CLF_ASSEMBLE_SECONDS; } - /* + /* * For freescan apply validation rules (stage 1) before mixed with * relative time (otherwise always valid recalculated date & time). */ @@ -4596,7 +4596,7 @@ ClockSafeCatchCmd( /* original catch */ ret = Tcl_CatchObjCmd(NULL, interp, objc, objv); - + if (ret == TCL_ERROR) { Tcl_DiscardInterpState((Tcl_InterpState)statePtr); return TCL_ERROR; diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index faf091e..18252d3 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -64,7 +64,7 @@ _str2int( const char *e, int sign) { - register int val = 0, prev = 0; + int val = 0, prev = 0; if (sign >= 0) { while (p < e) { val = val * 10 + (*p++ - '0'); @@ -94,7 +94,7 @@ _str2wideInt( const char *e, int sign) { - register Tcl_WideInt val = 0, prev = 0; + Tcl_WideInt val = 0, prev = 0; if (sign >= 0) { while (p < e) { val = val * 10 + (*p++ - '0'); @@ -135,11 +135,11 @@ _str2wideInt( static inline char * _itoaw( char *buf, - register int val, + int val, char padchar, unsigned short int width) { - register char *p; + char *p; static int wrange[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; /* positive integer */ @@ -154,7 +154,7 @@ _itoaw( p = buf + width; *p-- = '\0'; do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' + c; } while (val > 0); /* fulling with pad-char */ @@ -179,12 +179,12 @@ _itoaw( /* differentiate platforms with -1 % 10 == 1 and -1 % 10 == -1 */ if (-1 % 10 == -1) { do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' - c; } while (val < 0); } else { do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' + c; } while (val < 0); } @@ -203,11 +203,11 @@ _itoaw( static inline char * _witoaw( char *buf, - register Tcl_WideInt val, + Tcl_WideInt val, char padchar, unsigned short int width) { - register char *p; + char *p; static int wrange[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; /* positive integer */ @@ -231,7 +231,7 @@ _witoaw( p = buf + width; *p-- = '\0'; do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' + c; } while (val > 0); /* fulling with pad-char */ @@ -266,12 +266,12 @@ _witoaw( /* differentiate platforms with -1 % 10 == 1 and -1 % 10 == -1 */ if (-1 % 10 == -1) { do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' - c; } while (val < 0); } else { do { - register char c = (val % 10); val /= 10; + char c = (val % 10); val /= 10; *p-- = '0' + c; } while (val < 0); } @@ -419,18 +419,18 @@ ClockFmtScnStorageAllocProc( void *keyPtr) /* Key to store in the hash table entry. */ { ClockFmtScnStorage *fss; - const char *string = (const char *) keyPtr; Tcl_HashEntry *hPtr; unsigned int size, allocsize = sizeof(ClockFmtScnStorage) + sizeof(Tcl_HashEntry); + (void)tablePtr; allocsize += (size = strlen(string) + 1); if (size > sizeof(hPtr->key)) { allocsize -= sizeof(hPtr->key); } - fss = ckalloc(allocsize); + fss = (ClockFmtScnStorage *)ckalloc(allocsize); /* initialize */ memset(fss, 0, sizeof(*fss)); @@ -549,7 +549,7 @@ ClockFmtObj_DupInternalRep(srcPtr, copyPtr) /* if no format representation, dup string representation */ if (fss == NULL) { - copyPtr->bytes = ckalloc(srcPtr->length + 1); + copyPtr->bytes = (char *)ckalloc(srcPtr->length + 1); memcpy(copyPtr->bytes, srcPtr->bytes, srcPtr->length + 1); copyPtr->length = srcPtr->length; } @@ -588,10 +588,11 @@ ClockFmtObj_SetFromAny(interp, objPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; { - /* validate string representation before free old internal represenation */ + /* validate string representation before free old internal representation */ + (void)interp; (void)TclGetString(objPtr); - /* free old internal represenation */ + /* free old internal representation */ if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) objPtr->typePtr->freeIntRepProc(objPtr); @@ -617,7 +618,7 @@ ClockFmtObj_UpdateString(objPtr) } len = strlen(name); objPtr->length = len, - objPtr->bytes = ckalloc((size_t)++len); + objPtr->bytes = (char *)ckalloc((size_t)++len); if (objPtr->bytes) memcpy(objPtr->bytes, name, len); } @@ -697,7 +698,7 @@ FindOrCreateFmtScnStorage( { const char *strFmt = TclGetString(objPtr); ClockFmtScnStorage *fss = NULL; - int new; + int isNew; Tcl_HashEntry *hPtr; Tcl_MutexLock(&ClockFmtMutex); @@ -718,14 +719,14 @@ FindOrCreateFmtScnStorage( } /* get or create entry (and alocate storage) */ - hPtr = Tcl_CreateHashEntry(&FmtScnHashTable, strFmt, &new); + hPtr = Tcl_CreateHashEntry(&FmtScnHashTable, strFmt, &isNew); if (hPtr != NULL) { fss = FmtScn4HashEntry(hPtr); #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0 /* unlink if it is currently in GC */ - if (new == 0 && fss->objRefCount == 0) { + if (isNew == 0 && fss->objRefCount == 0) { ClockFmtScnStorage_GC_Out(fss); } #endif @@ -812,7 +813,7 @@ Tcl_Obj * ClockLocalizeFormat( ClockFmtScnCmdArgs *opts) { - ClockClientData *dataPtr = opts->clientData; + ClockClientData *dataPtr = (ClockClientData *)opts->clientData; Tcl_Obj *valObj = NULL, *keyObj; keyObj = ClockFrmObjGetLocFmtKey(opts->interp, opts->formatObj); @@ -903,8 +904,8 @@ done: static const char * FindTokenBegin( - register const char *p, - register const char *end, + const char *p, + const char *end, ClockScanToken *tok) { char c; @@ -958,9 +959,9 @@ DetermineGreedySearchLen(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok, int *minLenPtr, int *maxLenPtr) { - register int minLen = tok->map->minSize; - register int maxLen; - register const char *p = yyInput + minLen, + int minLen = tok->map->minSize; + int maxLen; + const char *p = yyInput + minLen, *end = info->dateEnd; /* if still tokens available, try to correct minimum length */ @@ -1348,9 +1349,9 @@ StaticListSearch(ClockFmtScnCmdArgs *opts, static inline const char * FindWordEnd( ClockScanToken *tok, - register const char * p, const char * end) + const char * p, const char * end) { - register const char *x = tok->tokWord.start; + const char *x = tok->tokWord.start; const char *pfnd = p; if (x == tok->tokWord.end - 1) { /* fast phase-out for single char word */ if (*p == *x) { @@ -1527,7 +1528,7 @@ static int ClockScnToken_LocaleERA_Proc(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok) { - ClockClientData *dataPtr = opts->clientData; + ClockClientData *dataPtr = (ClockClientData *)opts->clientData; int ret, val; int minLen, maxLen; @@ -1595,7 +1596,7 @@ ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok) { int minLen, maxLen; - register const char *p = yyInput, *end; const char *s; + const char *p = yyInput, *end; const char *s; Tcl_WideInt intJD; int fractJD = 0, fractJDDiv = 1; DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); @@ -1632,7 +1633,7 @@ ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts, yyInput = p; done: - /* + /* * Build a date from julian day (integer and fraction). * Note, astronomical JDN starts at noon in opposite to calendar julianday. */ @@ -1662,7 +1663,7 @@ ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts, { int minLen, maxLen; int len = 0; - register const char *p = yyInput; + const char *p = yyInput; Tcl_Obj *tzObjStor = NULL; DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); @@ -1741,7 +1742,7 @@ ClockScnToken_StarDate_Proc(ClockFmtScnCmdArgs *opts, DateInfo *info, ClockScanToken *tok) { int minLen, maxLen; - register const char *p = yyInput, *end; const char *s; + const char *p = yyInput, *end; const char *s; int year, fractYear, fractDayDiv, fractDay; static const char *stardatePref = "stardate "; @@ -1955,10 +1956,10 @@ static ClockScanTokenMap ScnWordTokenMap = { static inline unsigned int EstimateTokenCount( - register const char *fmt, - register const char *end) + const char *fmt, + const char *end) { - register const char *p = fmt; + const char *p = fmt; unsigned int tokcnt; /* estimate token count by % char and format length */ tokcnt = 0; @@ -2015,7 +2016,7 @@ ClockGetOrParseScanFormat( if (fss->scnTok == NULL) { ClockScanToken *tok, *scnTok; unsigned int tokCnt; - register const char *p, *e, *cp; + const char *p, *e, *cp; e = p = HashEntry4FmtScn(fss)->key.string; e += strlen(p); @@ -2025,7 +2026,7 @@ ClockGetOrParseScanFormat( fss->scnSpaceCount = 0; - scnTok = tok = ckalloc(sizeof(*tok) * fss->scnTokC); + scnTok = tok = (ClockScanToken *)ckalloc(sizeof(*tok) * fss->scnTokC); memset(tok, 0, sizeof(*(tok))); tokCnt = 1; while (p < e) { @@ -2168,7 +2169,7 @@ word_tok: /* correct count of real used tokens and free mem if desired * (1 is acceptable delta to prevent memory fragmentation) */ if (fss->scnTokC > tokCnt + (CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE / 2)) { - if ( (tok = ckrealloc(scnTok, tokCnt * sizeof(*tok))) != NULL ) { + if ( (tok = (ClockScanToken *)ckrealloc(scnTok, tokCnt * sizeof(*tok))) != NULL ) { scnTok = tok; } } @@ -2188,15 +2189,15 @@ done: */ int ClockScan( - register DateInfo *info, /* Date fields used for parsing & converting */ + DateInfo *info, /* Date fields used for parsing & converting */ Tcl_Obj *strObj, /* String containing the time to scan */ ClockFmtScnCmdArgs *opts) /* Command options */ { - ClockClientData *dataPtr = opts->clientData; + ClockClientData *dataPtr = (ClockClientData *)opts->clientData; ClockFmtScnStorage *fss; ClockScanToken *tok; ClockScanTokenMap *map; - register const char *p, *x, *end; + const char *p, *x, *end; unsigned short int flags = 0; int ret = TCL_ERROR; @@ -2342,7 +2343,7 @@ ClockScan( /* unmatched -> error */ goto not_match; } - /* don't decrement yySpaceCount by regular (first expected space), + /* don't decrement yySpaceCount by regular (first expected space), * already considered above with fss->scnSpaceCount */; p++; while (p < end && isspace(UCHAR(*p))) { @@ -2470,7 +2471,7 @@ ClockScan( yyYear += info->dateCentury * 100; } } - } + } if ( (flags & (CLF_ISO8601WEAK|CLF_ISO8601YEAR)) ) { if ((flags & (CLF_ISO8601YEAR|CLF_YEAR)) == CLF_YEAR) { /* for calculations expected iso year */ @@ -2536,7 +2537,7 @@ not_match: "input string \"%s\" does not match supplied format \"%s\"," " locale \"%s\" - token \"%s\"", info->dateStart, HashEntry4FmtScn(fss)->key.string, - Tcl_GetString(opts->localeObj), + Tcl_GetString(opts->localeObj), tok && tok->tokWord.start ? tok->tokWord.start : "NULL")); #endif Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", NULL); @@ -2551,7 +2552,7 @@ done: static inline int FrmResultAllocate( - register DateFormat *dateFmt, + DateFormat *dateFmt, int len) { int needed = dateFmt->output + len - dateFmt->resEnd; @@ -2561,13 +2562,13 @@ FrmResultAllocate( char *newRes; /* differentiate between stack and memory */ if (!FrmResultIsAllocated(dateFmt)) { - newRes = ckalloc(newsize); + newRes = (char *)ckalloc(newsize); if (newRes == NULL) { return TCL_ERROR; } memcpy(newRes, dateFmt->resMem, dateFmt->output - dateFmt->resMem); } else { - newRes = ckrealloc(dateFmt->resMem, newsize); + newRes = (char *)ckrealloc(dateFmt->resMem, newsize); if (newRes == NULL) { return TCL_ERROR; } @@ -2682,7 +2683,7 @@ ClockFmtToken_JDN_Proc( int fractJD; /* Convert to JDN parts (regarding start offset) and time fraction */ - fractJD = dateFmt->date.secondOfDay + fractJD = dateFmt->date.secondOfDay - (int)tok->map->offs; /* 0 for calendar or 43200 for astro JD */ if (fractJD < 0) { intJD--; @@ -2739,9 +2740,12 @@ ClockFmtToken_TimeZone_Proc( ClockFormatToken *tok, int *val) { + (void)val; + if (*tok->tokWord.start == 'z') { int z = dateFmt->date.tzOffset; char sign = '+'; + if ( z < 0 ) { z = -z; sign = '-'; @@ -2784,6 +2788,8 @@ ClockFmtToken_LocaleERA_Proc( Tcl_Obj *mcObj; const char *s; int len; + (void)tok; + (void)val; if (dateFmt->date.era == BCE) { mcObj = ClockMCGet(opts, MCLIT_BCE); @@ -3056,7 +3062,7 @@ ClockGetOrParseFmtFormat( if (fss->fmtTok == NULL) { ClockFormatToken *tok, *fmtTok; unsigned int tokCnt; - register const char *p, *e, *cp; + const char *p, *e, *cp; e = p = HashEntry4FmtScn(fss)->key.string; e += strlen(p); @@ -3064,7 +3070,7 @@ ClockGetOrParseFmtFormat( /* estimate token count by % char and format length */ fss->fmtTokC = EstimateTokenCount(p, e); - fmtTok = tok = ckalloc(sizeof(*tok) * fss->fmtTokC); + fmtTok = tok = (ClockFormatToken *)ckalloc(sizeof(*tok) * fss->fmtTokC); memset(tok, 0, sizeof(*(tok))); tokCnt = 1; while (p < e) { @@ -3151,7 +3157,7 @@ word_tok: /* correct count of real used tokens and free mem if desired * (1 is acceptable delta to prevent memory fragmentation) */ if (fss->fmtTokC > tokCnt + (CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE / 2)) { - if ( (tok = ckrealloc(fmtTok, tokCnt * sizeof(*tok))) != NULL ) { + if ( (tok = (ClockFormatToken *)ckrealloc(fmtTok, tokCnt * sizeof(*tok))) != NULL ) { fmtTok = tok; } } @@ -3171,7 +3177,7 @@ done: */ int ClockFormat( - register DateFormat *dateFmt, /* Date fields used for parsing & converting */ + DateFormat *dateFmt, /* Date fields used for parsing & converting */ ClockFmtScnCmdArgs *opts) /* Command options */ { ClockFmtScnStorage *fss; @@ -3194,7 +3200,7 @@ ClockFormat( dateFmt->resMem = resMem; dateFmt->resEnd = dateFmt->resMem + sizeof(resMem); if (fss->fmtMinAlloc > sizeof(resMem)) { - dateFmt->resMem = ckalloc(fss->fmtMinAlloc); + dateFmt->resMem = (char *)ckalloc(fss->fmtMinAlloc); dateFmt->resEnd = dateFmt->resMem + fss->fmtMinAlloc; if (dateFmt->resMem == NULL) { return TCL_ERROR; @@ -3310,13 +3316,13 @@ done: result->length = dateFmt->output - dateFmt->resMem; size = result->length+1; if (dateFmt->resMem == resMem) { - result->bytes = ckalloc(size); + result->bytes = (char *)ckalloc(size); if (result->bytes == NULL) { return TCL_ERROR; } memcpy(result->bytes, dateFmt->resMem, size); } else if ((dateFmt->resEnd - dateFmt->resMem) / size > MAX_FMT_RESULT_THRESHOLD) { - result->bytes = ckrealloc(dateFmt->resMem, size); + result->bytes = (char *)ckrealloc(dateFmt->resMem, size); if (result->bytes == NULL) { result->bytes = dateFmt->resMem; } @@ -3350,6 +3356,7 @@ static void ClockFrmScnFinalize( ClientData clientData) /* Not used. */ { + (void)clientData; Tcl_MutexLock(&ClockFmtMutex); #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0 /* clear GC */ diff --git a/generic/tclDate.c b/generic/tclDate.c index f9630e4..e077d94 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -2700,7 +2700,7 @@ TclDatelex( tokStart = yyInput; if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ - + /* * Convert the string into a number; count the number of digits. */ @@ -2762,12 +2762,12 @@ TclDatelex( yyInput--; location->last_column = yyInput - info->dateStart - 1; 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 + * bypass spaces after token (but ignore by TZ+OFFS), because should * recognize next SP token, if TZ only. */ if (ret == tZONE || ret == tDAYZONE) { diff --git a/generic/tclDate.h b/generic/tclDate.h index 0c9f7c3..ad0ca70 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -320,7 +320,7 @@ typedef struct ClockClientData { Tcl_Obj *prevSetupTimeZoneUnnorm; Tcl_Obj *prevSetupTimeZone; Tcl_Obj *prevSetupTZData; - + Tcl_Obj *defaultLocale; Tcl_Obj *defaultLocaleDict; Tcl_Obj *currentLocale; @@ -404,7 +404,7 @@ struct ClockScanToken { #define MIN_FMT_RESULT_BLOCK_ALLOC 80 #define MIN_FMT_RESULT_BLOCK_DELTA 0 -/* Maximal permitted threshold (buffer size > result size) in percent, +/* Maximal permitted threshold (buffer size > result size) in percent, * to directly return the buffer without reallocate */ #define MAX_FMT_RESULT_THRESHOLD 2 @@ -472,11 +472,11 @@ struct ClockFmtScnStorage { #endif }; -/* +/* * Clock macros. */ -/* +/* * Extracts Julian day and seconds of the day from posix seconds (tm). */ #define ClockExtractJDAndSODFromSeconds(jd, sod, tm) \ diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 485d54a..6588e0c 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -901,7 +901,7 @@ TclDatelex( tokStart = yyInput; if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ - + /* * Convert the string into a number; count the number of digits. */ @@ -963,12 +963,12 @@ TclDatelex( yyInput--; location->last_column = yyInput - info->dateStart - 1; 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 + * bypass spaces after token (but ignore by TZ+OFFS), because should * recognize next SP token, if TZ only. */ if (ret == tZONE || ret == tDAYZONE) { diff --git a/tests-perf/clock.perf.tcl b/tests-perf/clock.perf.tcl index 3682387..22b8d91 100644 --- a/tests-perf/clock.perf.tcl +++ b/tests-perf/clock.perf.tcl @@ -2,18 +2,18 @@ # ------------------------------------------------------------------------ # # test-performance.tcl -- -# +# # This file provides common performance tests for comparison of tcl-speed # degradation by switching between branches. # (currently for clock ensemble only) # # ------------------------------------------------------------------------ -# +# # Copyright (c) 2014 Serg G. Brester (aka sebres) -# +# # See the file "license.terms" for information on usage and redistribution # of this file. -# +# array set in {-time 500} if {[info exists ::argv0] && [file tail $::argv0] eq [file tail [info script]]} { @@ -215,7 +215,7 @@ proc test-freescan {{reptime 1000}} { {clock scan "next January" -base 0 -gmt 1} # FreeScan : relative week {clock scan "next Fri" -base 0 -gmt 1} - # FreeScan : relative weekday and week offset + # FreeScan : relative weekday and week offset {clock scan "next January + 2 week" -base 0 -gmt 1} # FreeScan : time only with base {clock scan "19:18:30" -base 148863600 -gmt 1} @@ -300,7 +300,7 @@ proc test-convert {{reptime 1000}} { {clock format [clock scan "19:18:30 EST" -base 148863600] -format "%H:%M:%S %z" -timezone EST} # Format locale 1x: comparison values - {clock format 0 -gmt 1 -locale en} + {clock format 0 -gmt 1 -locale en} {clock format 0 -gmt 1 -locale de} {clock format 0 -gmt 1 -locale fr} # Format locale 2x: without switching locale (en, en) @@ -340,7 +340,7 @@ proc test-convert {{reptime 1000}} { {clock scan "19:18:30 MST" -base 148863600; clock scan "19:18:30 EST" -base 148863600} # FreeScan TZ 2x (+1 gmt, +1 system-default) {clock scan "19:18:30 MST" -base 148863600 -gmt 1; clock scan "19:18:30 EST" -base 148863600} - + # Scan TZ: comparison included in scan string vs. given {clock scan "2009-06-30T18:30:00 CEST" -format "%Y-%m-%dT%H:%M:%S %z"} {clock scan "2009-06-30T18:30:00 CET" -format "%Y-%m-%dT%H:%M:%S %z"} -- cgit v0.12 From a68e4219149a933c804fbd0e1be9c2fb89fb2fdb Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 18 Feb 2021 14:19:34 +0000 Subject: tweak error-messages --- generic/tclClock.c | 8 ++++---- generic/tclClockFmt.c | 2 +- tests/clock.test | 16 ++++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 4a6f16e..237bdcd 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3496,7 +3496,7 @@ baseNow: badOptionMsg: Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad option \"%s\": should be \"%s\"", + "bad option \"%s\": must be \"%s\"", TclGetString(objv[i]), syntax) ); @@ -3560,7 +3560,7 @@ ClockFormatObjCmd( ClockInitFmtScnArgs(clientData, interp, &opts); ret = ClockParseFmtScnArgs(&opts, &dateFmt.date, objc, objv, - CLC_FMT_ARGS, syntax); + CLC_FMT_ARGS, "-format, -gmt, -locale, or -timezone"); if (ret != TCL_OK) { goto done; } @@ -3637,7 +3637,7 @@ ClockScanObjCmd( ClockInitFmtScnArgs(clientData, interp, &opts); ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv, - CLC_SCN_ARGS, syntax); + CLC_SCN_ARGS, "-base, -format, -gmt, -locale, -timezone or -validate"); if (ret != TCL_OK) { goto done; } @@ -3742,7 +3742,7 @@ ClockScanCommit( + ((double)yySecondOfDay - SECONDS_PER_DAY/2) / SECONDS_PER_DAY; if (curJDN > dataPtr->maxJDN) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( - "requested date too large to represent", -1)); + "integer value too large to represent", -1)); Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); return TCL_ERROR; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 207cdbf..58bd724 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -2521,7 +2521,7 @@ ClockScan( overflow: - Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("requested date too large to represent", + Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("integer value too large to represent", -1)); Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); goto done; diff --git a/tests/clock.test b/tests/clock.test index f062c15..c5fb354 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -332,11 +332,11 @@ test clock-1.3 "clock format - empty val" { test clock-1.4 "clock format - bad flag" { # range error message for possible extensions: list [catch {clock format 0 -oops badflag} msg] $msg $::errorCode -} [subst {1 {bad option "-oops": should be "$syntax"} {CLOCK badOption -oops}}] +} [subst {1 {bad option "-oops": must be "-format, -gmt, -locale, or -timezone"} {CLOCK badOption -oops}}] test clock-1.4.1 "clock format - unexpected option for this sub-command" { # range error message for possible extensions: list [catch {clock format 0 -base 0} msg] $msg $::errorCode -} [subst {1 {bad option "-base": should be "$syntax"} {CLOCK badOption -base}}] +} [subst {1 {bad option "-base": must be "-format, -gmt, -locale, or -timezone"} {CLOCK badOption -base}}] test clock-1.5 "clock format - bad timezone" { list [catch {clock format 0 -format "%s" -timezone :NOWHERE} msg] $msg $::errorCode @@ -18683,11 +18683,11 @@ test clock-6.8 {input of seconds} { test clock-6.9 {input of seconds - overflow} { list [catch {clock scan -9223372036854775809 -format %s -gmt true} result] $result $::errorCode -} {1 {requested date too large to represent} {CLOCK dateTooLarge}} +} {1 {integer value too large to represent} {CLOCK dateTooLarge}} test clock-6.10 {input of seconds - overflow} { list [catch {clock scan 9223372036854775808 -format %s -gmt true} result] $result $::errorCode -} {1 {requested date too large to represent} {CLOCK dateTooLarge}} +} {1 {integer value too large to represent} {CLOCK dateTooLarge}} test clock-6.11 {input of seconds - two values} { clock scan {1 2} -format {%s %s} -gmt true @@ -18917,13 +18917,13 @@ test clock-7.6 {Julian Day, overflow} { list [catch { clock scan 5373485 -format %J } result] $result $errorCode -} {1 {requested date too large to represent} {CLOCK dateTooLarge}} +} {1 {integer value too large to represent} {CLOCK dateTooLarge}} test clock-7.7 {Julian Day, overflow} { list [catch { clock scan 2147483648 -format %J } result] $result $errorCode -} {1 {requested date too large to represent} {CLOCK dateTooLarge}} +} {1 {integer value too large to represent} {CLOCK dateTooLarge}} test clock-7.8 {Julian Day, precedence below seconds} { list [clock scan {2440588 86400} -format {%J %s} -gmt true] \ @@ -18997,7 +18997,7 @@ test clock-7.16 {Astronomical JDN/JD, overflow} { [catch { clock scan 2147483648.5 -format %Ej } result] $result $errorCode -} [lrepeat 4 1 {requested date too large to represent} {CLOCK dateTooLarge}] +} [lrepeat 4 1 {integer value too large to represent} {CLOCK dateTooLarge}] test clock-7.18 {Astronomical JDN/JD, same precedence as seconds (last wins} { list [clock scan {2440588 86400} -format {%Ej %s} -gmt true] \ @@ -36150,7 +36150,7 @@ test clock-34.8 {clock scan tests} { } {Oct 23,1992 15:00 GMT} test clock-34.9 {clock scan tests} { list [catch {clock scan "Jan 12" -bad arg} msg] $msg -} [subst {1 {bad option "-bad": should be "$syntax"}}] +} [subst {1 {bad option "-bad": must be "-base, -format, -gmt, -locale, -timezone or -validate"}}] # The following two two tests test the two year date policy test clock-34.10 {clock scan tests} { set time [clock scan "1/1/71" -gmt true] -- cgit v0.12 From 16cde18103eeee3ef09dae361facb5de33bc3acc Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 18 Feb 2021 14:25:46 +0000 Subject: tweak error-messages a little more (no quotes here) --- generic/tclClock.c | 2 +- tests/clock.test | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 237bdcd..1f41b06 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3496,7 +3496,7 @@ baseNow: badOptionMsg: Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad option \"%s\": must be \"%s\"", + "bad option \"%s\": must be %s", TclGetString(objv[i]), syntax) ); diff --git a/tests/clock.test b/tests/clock.test index c5fb354..5c788e7 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -332,11 +332,11 @@ test clock-1.3 "clock format - empty val" { test clock-1.4 "clock format - bad flag" { # range error message for possible extensions: list [catch {clock format 0 -oops badflag} msg] $msg $::errorCode -} [subst {1 {bad option "-oops": must be "-format, -gmt, -locale, or -timezone"} {CLOCK badOption -oops}}] +} [subst {1 {bad option "-oops": must be -format, -gmt, -locale, or -timezone} {CLOCK badOption -oops}}] test clock-1.4.1 "clock format - unexpected option for this sub-command" { # range error message for possible extensions: list [catch {clock format 0 -base 0} msg] $msg $::errorCode -} [subst {1 {bad option "-base": must be "-format, -gmt, -locale, or -timezone"} {CLOCK badOption -base}}] +} [subst {1 {bad option "-base": must be -format, -gmt, -locale, or -timezone} {CLOCK badOption -base}}] test clock-1.5 "clock format - bad timezone" { list [catch {clock format 0 -format "%s" -timezone :NOWHERE} msg] $msg $::errorCode @@ -36150,7 +36150,7 @@ test clock-34.8 {clock scan tests} { } {Oct 23,1992 15:00 GMT} test clock-34.9 {clock scan tests} { list [catch {clock scan "Jan 12" -bad arg} msg] $msg -} [subst {1 {bad option "-bad": must be "-base, -format, -gmt, -locale, -timezone or -validate"}}] +} [subst {1 {bad option "-bad": must be -base, -format, -gmt, -locale, -timezone or -validate}}] # The following two two tests test the two year date policy test clock-34.10 {clock scan tests} { set time [clock scan "1/1/71" -gmt true] -- cgit v0.12 From c723b685c95a53e925b3b55ff4de8a0793ec26e2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 18 Feb 2021 14:32:52 +0000 Subject: One more error-message tweak --- generic/tclClock.c | 2 +- tests/clock.test | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 1f41b06..6a046e2 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3742,7 +3742,7 @@ ClockScanCommit( + ((double)yySecondOfDay - SECONDS_PER_DAY/2) / SECONDS_PER_DAY; if (curJDN > dataPtr->maxJDN) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( - "integer value too large to represent", -1)); + "requested date too large to represent", -1)); Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); return TCL_ERROR; } diff --git a/tests/clock.test b/tests/clock.test index 5c788e7..5183b28 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18917,13 +18917,13 @@ test clock-7.6 {Julian Day, overflow} { list [catch { clock scan 5373485 -format %J } result] $result $errorCode -} {1 {integer value too large to represent} {CLOCK dateTooLarge}} +} {1 {requested date too large to represent} {CLOCK dateTooLarge}} test clock-7.7 {Julian Day, overflow} { list [catch { clock scan 2147483648 -format %J } result] $result $errorCode -} {1 {integer value too large to represent} {CLOCK dateTooLarge}} +} {1 {requested date too large to represent} {CLOCK dateTooLarge}} test clock-7.8 {Julian Day, precedence below seconds} { list [clock scan {2440588 86400} -format {%J %s} -gmt true] \ @@ -18997,7 +18997,7 @@ test clock-7.16 {Astronomical JDN/JD, overflow} { [catch { clock scan 2147483648.5 -format %Ej } result] $result $errorCode -} [lrepeat 4 1 {integer value too large to represent} {CLOCK dateTooLarge}] +} [lrepeat 4 1 {requested date too large to represent} {CLOCK dateTooLarge}] test clock-7.18 {Astronomical JDN/JD, same precedence as seconds (last wins} { list [clock scan {2440588 86400} -format {%Ej %s} -gmt true] \ -- cgit v0.12 From c15d68cbc421db2f14460026dae66f67276dfff5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 19 Feb 2021 18:00:48 +0000 Subject: Experiment: Remove the "::tcl::clock::getenv" function. --- generic/tclClock.c | 48 ------------------------------------------------ library/clock.tcl | 8 ++++---- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index e4162ae..24232a2 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -107,9 +107,6 @@ static int ClockGetjuliandayfromerayearmonthdayObjCmd( static int ClockGetjuliandayfromerayearweekdayObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); -static int ClockGetenvObjCmd( - ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); static int ClockMicrosecondsObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -166,7 +163,6 @@ static const struct ClockCommand clockCommands[] = { {"add", ClockAddObjCmd, TclCompileBasicMin1ArgCmd, NULL}, {"clicks", ClockClicksObjCmd, TclCompileClockClicksCmd, NULL}, {"format", ClockFormatObjCmd, TclCompileBasicMin1ArgCmd, NULL}, - {"getenv", ClockGetenvObjCmd, TclCompileBasicMin1ArgCmd, NULL}, {"microseconds", ClockMicrosecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(1)}, {"milliseconds", ClockMillisecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(2)}, {"scan", ClockScanObjCmd, TclCompileBasicMin1ArgCmd, NULL}, @@ -3019,50 +3015,6 @@ WeekdayOnOrBefore( /* *---------------------------------------------------------------------- * - * ClockGetenvObjCmd -- - * - * Tcl command that reads an environment variable from the system - * - * Usage: - * ::tcl::clock::getEnv NAME - * - * Parameters: - * NAME - Name of the environment variable desired - * - * Results: - * Returns a standard Tcl result. Returns an error if the variable does - * not exist, with a message left in the interpreter. Returns TCL_OK and - * the value of the variable if the variable does exist, - * - *---------------------------------------------------------------------- - */ - -int -ClockGetenvObjCmd( - TCL_UNUSED(void *), - Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) -{ - const char *varName; - const char *varValue; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "name"); - return TCL_ERROR; - } - varName = TclGetString(objv[1]); - varValue = getenv(varName); - if (varValue == NULL) { - varValue = ""; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(varValue, -1)); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * * ThreadSafeLocalTime -- * * Wrapper around the 'localtime' library function to make it thread diff --git a/library/clock.tcl b/library/clock.tcl index 9e340d0..7b492a9 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -905,10 +905,10 @@ proc ::tcl::clock::LocalizeFormat { locale format mcd } { proc ::tcl::clock::GetSystemTimeZone {} { variable TimeZoneBad - if {[set result [getenv TCL_TZ]] ne {}} { - set timezone $result - } elseif {[set result [getenv TZ]] ne {}} { - set timezone $result + if {[info exist ::env(TCL_TZ)]} { + set timezone $::env(TCL_TZ) + } elseif {[info exist ::env(TZ)]} { + set timezone $::env(TZ) } if {![info exists timezone]} { # ask engine for the cached timezone: -- cgit v0.12 From 984ff0cfb4b0ad7c1e2575bb02542a2905cea389 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 5 Jul 2022 11:09:11 +0000 Subject: re-generate tclDate.c --- generic/tclDate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index 7357a61..6ca14ea 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -121,9 +121,9 @@ #define TM_YEAR_BASE 1900 -#define HOUR(x) ((int) (60 * x)) +#define HOUR(x) ((int) (60 * (x))) #define SECSPERDAY (24L * 60L * 60L) -#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) +#define IsLeapYear(x) (((x) % 4 == 0) && ((x) % 100 != 0 || (x) % 400 == 0)) #define yyIncrFlags(f) \ do { \ -- cgit v0.12