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 3596c610aa00c36454c971d84c8243f48f62fba4 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 19 Feb 2021 09:25:40 +0000 Subject: Fix various compiler warnings --- generic/tclClock.c | 57 ++++++++++---------- generic/tclClockFmt.c | 135 ++++++++++++++++++++++++++---------------------- generic/tclStrIdxTree.c | 8 +-- tests/clock.test | 6 +-- 4 files changed, 107 insertions(+), 99 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 6a046e2..bc1c33c 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -126,19 +126,19 @@ static int ClockScanObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int ClockScanCommit( - register DateInfo *info, - register ClockFmtScnCmdArgs *opts); + DateInfo *info, + ClockFmtScnCmdArgs *opts); static int ClockFreeScan( - register DateInfo *info, + DateInfo *info, Tcl_Obj *strObj, ClockFmtScnCmdArgs *opts); static int ClockCalcRelTime( - register DateInfo *info, ClockFmtScnCmdArgs *opts); + DateInfo *info); static int ClockAddObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int ClockValidDate( - register DateInfo *, - register ClockFmtScnCmdArgs *, int stage); + DateInfo *, + ClockFmtScnCmdArgs *, int stage); static struct tm * ThreadSafeLocalTime(const time_t *); static size_t TzsetIfNecessary(void); static void ClockDeleteCmdProc(ClientData); @@ -3241,7 +3241,7 @@ ClockMicrosecondsObjCmd( { (void)clientData; if (objc != 1) { - Tcl_WrongNumArgs(interp, 0, NULL, "clock microseconds"); + Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetMicroseconds())); @@ -3283,7 +3283,6 @@ ClockInitFmtScnArgs( static int ClockParseFmtScnArgs( - register ClockFmtScnCmdArgs *opts, /* Result vector: format, locale, timezone... */ TclDateFields *date, /* Extracted date-time corresponding base * (by scan or add) resp. clockval (by format) */ @@ -3420,7 +3419,7 @@ ClockParseFmtScnArgs( /* Base (by scan or add) or clock value (by format) */ if (opts->baseObj != NULL) { - register Tcl_Obj *baseObj = opts->baseObj; + Tcl_Obj *baseObj = opts->baseObj; /* bypass integer recognition if looks like option "-now" */ if ( (baseObj->length == 4 && baseObj->bytes && *(baseObj->bytes+1) == 'n') || @@ -3537,7 +3536,7 @@ ClockFormatObjCmd( { ClockClientData *dataPtr = (ClockClientData *)clientData; - static const char *syntax = "clock format clockval|-now " + static const char *syntax = "clockval|-now " "?-format string? " "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"; @@ -3547,7 +3546,7 @@ ClockFormatObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 0, NULL, syntax); + Tcl_WrongNumArgs(interp, 1, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); return TCL_ERROR; } @@ -3612,7 +3611,7 @@ ClockScanObjCmd( int objc, /* Parameter count */ Tcl_Obj *const objv[]) /* Parameter values */ { - static const char *syntax = "clock scan string " + static const char *syntax = "string " "?-base seconds? " "?-format string? " "?-gmt boolean? " @@ -3624,7 +3623,7 @@ ClockScanObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 0, NULL, syntax); + Tcl_WrongNumArgs(interp, 1, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); return TCL_ERROR; } @@ -3713,8 +3712,7 @@ done: static int ClockScanCommit( - register DateInfo *info, /* Clock scan info structure */ - register + DateInfo *info, /* Clock scan info structure */ ClockFmtScnCmdArgs *opts) /* Format, locale, timezone and base */ { /* If needed assemble julianDay using year, month, etc. */ @@ -3788,8 +3786,7 @@ ClockScanCommit( static int ClockValidDate( - register DateInfo *info, /* Clock scan info structure */ - register + DateInfo *info, /* Clock scan info structure */ ClockFmtScnCmdArgs *opts, /* Scan options */ int stage) /* Stage to validate (1, 2 or 3 for both) */ { @@ -3950,7 +3947,6 @@ ClockValidDate( int ClockFreeScan( - register DateInfo *info, /* Date fields used for parsing & converting * simultaneously a yy-parse structure of the * TclClockFreeScan */ @@ -4064,7 +4060,7 @@ ClockFreeScan( * Do relative times */ - ret = ClockCalcRelTime(info, opts); + ret = ClockCalcRelTime(info); /* Free scanning completed - date ready */ @@ -4089,9 +4085,7 @@ done: */ int ClockCalcRelTime( - register - DateInfo *info, /* Date fields used for converting */ - ClockFmtScnCmdArgs *opts) /* Command options */ + DateInfo *info) /* Date fields used for converting */ { int prevDayOfWeek = yyDayOfWeek; /* preserve unchanged day of week */ @@ -4264,10 +4258,10 @@ repeat_rel: static inline int ClockWeekdaysOffs( - register int dayOfWeek, - register int offs) + int dayOfWeek, + int offs) { - register int weeks, resDayOfWeek; + int weeks, resDayOfWeek; /* offset in days */ weeks = offs / 5; @@ -4281,7 +4275,7 @@ ClockWeekdaysOffs( /* resulting day of week */ { - register int day = (offs % 7); + int day = (offs % 7); /* compiler fix for negative offs - wrap (0, -1) -> (-1, 6) */ if (day < 0) { day = 7 + day; @@ -4354,7 +4348,7 @@ ClockAddObjCmd( int objc, /* Parameter count */ Tcl_Obj *const objv[]) /* Parameter values */ { - static const char *syntax = "clock add clockval|-now ?number units?..." + static const char *syntax = "clockval|-now ?number units?..." "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"; ClockClientData *dataPtr = (ClockClientData *)clientData; @@ -4381,7 +4375,7 @@ ClockAddObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 0, NULL, syntax); + Tcl_WrongNumArgs(interp, 1, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); return TCL_ERROR; } @@ -4443,7 +4437,7 @@ ClockAddObjCmd( || yySeconds + yyRelSeconds < 0 ) ) { - if (ClockCalcRelTime(info, &opts) != TCL_OK) { + if (ClockCalcRelTime(info) != TCL_OK) { goto done; } } @@ -4487,7 +4481,7 @@ ClockAddObjCmd( */ if (info->flags & CLF_RELCONV) { - if (ClockCalcRelTime(info, &opts) != TCL_OK) { + if (ClockCalcRelTime(info) != TCL_OK) { goto done; } } @@ -4558,7 +4552,7 @@ ClockSecondsObjCmd( */ int ClockSafeCatchCmd( - ClientData clientData, + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) @@ -4579,6 +4573,7 @@ ClockSafeCatchCmd( Interp *iPtr = (Interp *)interp; int ret, flags = 0; InterpState *statePtr; + (void)dummy; if (objc == 1) { /* wrong # args : */ diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 58bd724..9d66ad7 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -955,7 +955,7 @@ FindTokenBegin( */ static void -DetermineGreedySearchLen(ClockFmtScnCmdArgs *opts, +DetermineGreedySearchLen( DateInfo *info, ClockScanToken *tok, int *minLenPtr, int *maxLenPtr) { @@ -1054,7 +1054,7 @@ DetermineGreedySearchLen(ClockFmtScnCmdArgs *opts, */ static inline int -ObjListSearch(ClockFmtScnCmdArgs *opts, +ObjListSearch( DateInfo *info, int *val, Tcl_Obj **lstv, int lstc, int minLen, int maxLen) @@ -1121,7 +1121,7 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts, } /* search in list */ - return ObjListSearch(opts, info, val, lstv, lstc, + return ObjListSearch(info, val, lstv, lstc, minLen, maxLen); } #endif @@ -1294,7 +1294,7 @@ done: */ static inline int -ClockStrIdxTreeSearch(ClockFmtScnCmdArgs *opts, +ClockStrIdxTreeSearch( DateInfo *info, TclStrIdxTree *idxTree, int *val, int minLen, int maxLen) { @@ -1398,7 +1398,7 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts, int minLen, maxLen; TclStrIdxTree *idxTree; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); /* get or create tree in msgcat dict */ @@ -1407,7 +1407,7 @@ ClockScnToken_Month_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ClockStrIdxTreeSearch(opts, info, idxTree, &val, minLen, maxLen); + ret = ClockStrIdxTreeSearch(info, idxTree, &val, minLen, maxLen); if (ret != TCL_OK) { return ret; } @@ -1428,7 +1428,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, char curTok = *tok->tokWord.start; TclStrIdxTree *idxTree; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); /* %u %w %Ou %Ow */ if ( curTok != 'a' && curTok != 'A' @@ -1447,7 +1447,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ClockStrIdxTreeSearch(opts, info, idxTree, &val, minLen, maxLen); + ret = ClockStrIdxTreeSearch(info, idxTree, &val, minLen, maxLen); if (ret != TCL_OK) { return ret; } @@ -1478,7 +1478,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ClockStrIdxTreeSearch(opts, info, idxTree, &val, minLen, maxLen); + ret = ClockStrIdxTreeSearch(info, idxTree, &val, minLen, maxLen); if (ret != TCL_OK) { return ret; } @@ -1500,7 +1500,7 @@ ClockScnToken_amPmInd_Proc(ClockFmtScnCmdArgs *opts, int minLen, maxLen; Tcl_Obj *amPmObj[2]; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); amPmObj[0] = ClockMCGet(opts, MCLIT_AM); amPmObj[1] = ClockMCGet(opts, MCLIT_PM); @@ -1509,7 +1509,7 @@ ClockScnToken_amPmInd_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ObjListSearch(opts, info, &val, amPmObj, 2, + ret = ObjListSearch(info, &val, amPmObj, 2, minLen, maxLen); if (ret != TCL_OK) { return ret; @@ -1534,7 +1534,7 @@ ClockScnToken_LocaleERA_Proc(ClockFmtScnCmdArgs *opts, int minLen, maxLen; Tcl_Obj *eraObj[6]; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); eraObj[0] = ClockMCGet(opts, MCLIT_BCE); eraObj[1] = ClockMCGet(opts, MCLIT_CE); @@ -1547,7 +1547,7 @@ ClockScnToken_LocaleERA_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ObjListSearch(opts, info, &val, eraObj, 6, + ret = ObjListSearch(info, &val, eraObj, 6, minLen, maxLen); if (ret != TCL_OK) { return ret; @@ -1570,7 +1570,7 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts, int minLen, maxLen; TclStrIdxTree *idxTree; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); /* get or create tree in msgcat dict */ @@ -1579,7 +1579,7 @@ ClockScnToken_LocaleListMatcher_Proc(ClockFmtScnCmdArgs *opts, return TCL_ERROR; } - ret = ClockStrIdxTreeSearch(opts, info, idxTree, &val, minLen, maxLen); + ret = ClockStrIdxTreeSearch(info, idxTree, &val, minLen, maxLen); if (ret != TCL_OK) { return ret; } @@ -1598,8 +1598,9 @@ ClockScnToken_JDN_Proc(ClockFmtScnCmdArgs *opts, int minLen, maxLen; const char *p = yyInput, *end; const char *s; Tcl_WideInt intJD; int fractJD = 0, fractJDDiv = 1; + (void)opts; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); end = yyInput + maxLen; @@ -1666,7 +1667,7 @@ ClockScnToken_TimeZone_Proc(ClockFmtScnCmdArgs *opts, const char *p = yyInput; Tcl_Obj *tzObjStor = NULL; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); /* numeric timezone */ if (*p == '+' || *p == '-') { @@ -1745,8 +1746,9 @@ ClockScnToken_StarDate_Proc(ClockFmtScnCmdArgs *opts, const char *p = yyInput, *end; const char *s; int year, fractYear, fractDayDiv, fractDay; static const char *stardatePref = "stardate "; + (void)opts; - DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen); + DetermineGreedySearchLen(info, tok, &minLen, &maxLen); end = yyInput + maxLen; @@ -1820,49 +1822,49 @@ static const char *ScnSTokenMapIndex = static ClockScanTokenMap ScnSTokenMap[] = { /* %d %e */ {CTOKT_INT, CLF_DAYOFMONTH, 0, 1, 2, TclOffset(DateInfo, date.dayOfMonth), - NULL}, + NULL, NULL}, /* %m %N */ {CTOKT_INT, CLF_MONTH, 0, 1, 2, TclOffset(DateInfo, date.month), - NULL}, + NULL, NULL}, /* %b %B %h */ {CTOKT_PARSER, CLF_MONTH, 0, 0, 0xffff, 0, - ClockScnToken_Month_Proc}, + ClockScnToken_Month_Proc, NULL}, /* %y */ {CTOKT_INT, CLF_YEAR, 0, 1, 2, TclOffset(DateInfo, date.year), - NULL}, + NULL, NULL}, /* %Y */ {CTOKT_INT, CLF_YEAR | CLF_CENTURY, 0, 4, 4, TclOffset(DateInfo, date.year), - NULL}, + NULL, NULL}, /* %H %k %I %l */ {CTOKT_INT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.hour), - NULL}, + NULL, NULL}, /* %M */ {CTOKT_INT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.minutes), - NULL}, + NULL, NULL}, /* %S */ {CTOKT_INT, CLF_TIME, 0, 1, 2, TclOffset(DateInfo, date.secondOfMin), - NULL}, + NULL, NULL}, /* %p %P */ {CTOKT_PARSER, 0, 0, 0, 0xffff, 0, ClockScnToken_amPmInd_Proc, NULL}, /* %J */ {CTOKT_WIDE, CLF_JULIANDAY | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.julianDay), - NULL}, + NULL, NULL}, /* %j */ {CTOKT_INT, CLF_DAYOFYEAR, 0, 1, 3, TclOffset(DateInfo, date.dayOfYear), - NULL}, + NULL, NULL}, /* %C */ {CTOKT_INT, CLF_CENTURY|CLF_ISO8601CENTURY, 0, 1, 2, TclOffset(DateInfo, dateCentury), - NULL}, + NULL, NULL}, /* %g */ {CTOKT_INT, CLF_ISO8601YEAR, 0, 2, 2, TclOffset(DateInfo, date.iso8601Year), - NULL}, + NULL, NULL}, /* %G */ {CTOKT_INT, CLF_ISO8601YEAR | CLF_ISO8601CENTURY, 0, 4, 4, TclOffset(DateInfo, date.iso8601Year), - NULL}, + NULL, NULL}, /* %V */ {CTOKT_INT, CLF_ISO8601WEAK, 0, 1, 2, TclOffset(DateInfo, date.iso8601Week), - NULL}, + NULL, NULL}, /* %a %A %u %w */ {CTOKT_PARSER, CLF_DAYOFWEEK, 0, 0, 0xffff, 0, ClockScnToken_DayOfWeek_Proc, NULL}, @@ -1871,10 +1873,10 @@ static ClockScanTokenMap ScnSTokenMap[] = { ClockScnToken_TimeZone_Proc, NULL}, /* %U %W */ {CTOKT_INT, CLF_OPTIONAL, 0, 1, 2, 0, /* currently no capture, parse only token */ - NULL}, + NULL, NULL}, /* %s */ {CTOKT_WIDE, CLF_POSIXSEC | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.seconds), - NULL}, + NULL, NULL}, /* %n */ {CTOKT_CHAR, 0, 0, 1, 1, 0, NULL, "\n"}, /* %t */ @@ -1905,7 +1907,7 @@ static ClockScanTokenMap ScnETokenMap[] = { ClockScnToken_LocaleListMatcher_Proc, (void *)MCLIT_LOCALE_NUMERALS}, /* %Es */ {CTOKT_WIDE, CLF_LOCALSEC | CLF_SIGNED, 0, 1, 0xffff, TclOffset(DateInfo, date.localSeconds), - NULL}, + NULL, NULL}, }; static const char *ScnETokenMapAliasIndex[2] = { "", @@ -1945,12 +1947,12 @@ static const char *ScnOTokenMapAliasIndex[2] = { /* Token map reserved for CTOKT_SPACE */ static ClockScanTokenMap ScnSpaceTokenMap = { CTOKT_SPACE, 0, 0, 1, 1, 0, - NULL, + NULL, NULL }; static ClockScanTokenMap ScnWordTokenMap = { CTOKT_WORD, 0, 0, 1, 1, 0, - NULL + NULL, NULL }; @@ -2283,7 +2285,7 @@ ClockScan( if (*p == '-') { yyInput = ++p; sign = -1; }; } - DetermineGreedySearchLen(opts, info, tok, &minLen, &size); + DetermineGreedySearchLen(info, tok, &minLen, &size); if (size < map->minSize) { /* missing input -> error */ @@ -2587,6 +2589,10 @@ ClockFmtToken_HourAMPM_Proc( ClockFormatToken *tok, int *val) { + (void)opts; + (void)dateFmt; + (void)tok; + *val = ( ( *val + SECONDS_PER_DAY - 3600 ) / 3600 ) % 12 + 1; return TCL_OK; } @@ -2631,6 +2637,9 @@ ClockFmtToken_StarDate_Proc( int fractYear; /* Get day of year, zero based */ int v = dateFmt->date.dayOfYear - 1; + (void)opts; + (void)tok; + (void)val; /* Convert day of year to a fractional year */ if (IsGregorianLeapYear(&dateFmt->date)) { @@ -2663,6 +2672,8 @@ ClockFmtToken_WeekOfYear_Proc( int *val) { int dow = dateFmt->date.dayOfWeek; + (void)opts; + if (*tok->tokWord.start == 'U') { if (dow == 7) { dow = 0; @@ -2681,6 +2692,8 @@ ClockFmtToken_JDN_Proc( { Tcl_WideInt intJD = dateFmt->date.julianDay; int fractJD; + (void)opts; + (void)val; /* Convert to JDN parts (regarding start offset) and time fraction */ fractJD = dateFmt->date.secondOfDay @@ -2896,13 +2909,13 @@ static const char *FmtSTokenMapIndex = "demNbByYCHMSIklpaAuwUVzgGjJsntQ"; static ClockFormatTokenMap FmtSTokenMap[] = { /* %d */ - {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.dayOfMonth), NULL}, + {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.dayOfMonth), NULL, NULL}, /* %e */ - {CTOKT_INT, " ", 2, 0, 0, 0, TclOffset(DateFormat, date.dayOfMonth), NULL}, + {CTOKT_INT, " ", 2, 0, 0, 0, TclOffset(DateFormat, date.dayOfMonth), NULL, NULL}, /* %m */ - {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.month), NULL}, + {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.month), NULL, NULL}, /* %N */ - {CTOKT_INT, " ", 2, 0, 0, 0, TclOffset(DateFormat, date.month), NULL}, + {CTOKT_INT, " ", 2, 0, 0, 0, TclOffset(DateFormat, date.month), NULL, NULL}, /* %b %h */ {CTOKT_INT, NULL, 0, CLFMT_LOCALE_INDX | CLFMT_DECR, 0, 12, TclOffset(DateFormat, date.month), NULL, (void *)MCLIT_MONTHS_ABBREV}, @@ -2910,22 +2923,22 @@ static ClockFormatTokenMap FmtSTokenMap[] = { {CTOKT_INT, NULL, 0, CLFMT_LOCALE_INDX | CLFMT_DECR, 0, 12, TclOffset(DateFormat, date.month), NULL, (void *)MCLIT_MONTHS_FULL}, /* %y */ - {CTOKT_INT, "0", 2, 0, 0, 100, TclOffset(DateFormat, date.year), NULL}, + {CTOKT_INT, "0", 2, 0, 0, 100, TclOffset(DateFormat, date.year), NULL, NULL}, /* %Y */ - {CTOKT_INT, "0", 4, 0, 0, 0, TclOffset(DateFormat, date.year), NULL}, + {CTOKT_INT, "0", 4, 0, 0, 0, TclOffset(DateFormat, date.year), NULL, NULL}, /* %C */ - {CTOKT_INT, "0", 2, 0, 100, 0, TclOffset(DateFormat, date.year), NULL}, + {CTOKT_INT, "0", 2, 0, 100, 0, TclOffset(DateFormat, date.year), NULL, NULL}, /* %H */ - {CTOKT_INT, "0", 2, 0, 3600, 24, TclOffset(DateFormat, date.secondOfDay), NULL}, + {CTOKT_INT, "0", 2, 0, 3600, 24, TclOffset(DateFormat, date.secondOfDay), NULL, NULL}, /* %M */ - {CTOKT_INT, "0", 2, 0, 60, 60, TclOffset(DateFormat, date.secondOfDay), NULL}, + {CTOKT_INT, "0", 2, 0, 60, 60, TclOffset(DateFormat, date.secondOfDay), NULL, NULL}, /* %S */ - {CTOKT_INT, "0", 2, 0, 0, 60, TclOffset(DateFormat, date.secondOfDay), NULL}, + {CTOKT_INT, "0", 2, 0, 0, 60, TclOffset(DateFormat, date.secondOfDay), NULL, NULL}, /* %I */ {CTOKT_INT, "0", 2, CLFMT_CALC, 0, 0, TclOffset(DateFormat, date.secondOfDay), ClockFmtToken_HourAMPM_Proc, NULL}, /* %k */ - {CTOKT_INT, " ", 2, 0, 3600, 24, TclOffset(DateFormat, date.secondOfDay), NULL}, + {CTOKT_INT, " ", 2, 0, 3600, 24, TclOffset(DateFormat, date.secondOfDay), NULL, NULL}, /* %l */ {CTOKT_INT, " ", 2, CLFMT_CALC, 0, 0, TclOffset(DateFormat, date.secondOfDay), ClockFmtToken_HourAMPM_Proc, NULL}, @@ -2939,31 +2952,31 @@ static ClockFormatTokenMap FmtSTokenMap[] = { {CTOKT_INT, NULL, 0, CLFMT_LOCALE_INDX, 0, 7, TclOffset(DateFormat, date.dayOfWeek), NULL, (void *)MCLIT_DAYS_OF_WEEK_FULL}, /* %u */ - {CTOKT_INT, " ", 1, 0, 0, 0, TclOffset(DateFormat, date.dayOfWeek), NULL}, + {CTOKT_INT, " ", 1, 0, 0, 0, TclOffset(DateFormat, date.dayOfWeek), NULL, NULL}, /* %w */ - {CTOKT_INT, " ", 1, 0, 0, 7, TclOffset(DateFormat, date.dayOfWeek), NULL}, + {CTOKT_INT, " ", 1, 0, 0, 7, TclOffset(DateFormat, date.dayOfWeek), NULL, NULL}, /* %U %W */ {CTOKT_INT, "0", 2, CLFMT_CALC, 0, 0, TclOffset(DateFormat, date.dayOfYear), ClockFmtToken_WeekOfYear_Proc, NULL}, /* %V */ - {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.iso8601Week), NULL}, + {CTOKT_INT, "0", 2, 0, 0, 0, TclOffset(DateFormat, date.iso8601Week), NULL, NULL}, /* %z %Z */ {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}, + {CTOKT_INT, "0", 2, 0, 0, 100, TclOffset(DateFormat, date.iso8601Year), NULL, NULL}, /* %G */ - {CTOKT_INT, "0", 4, 0, 0, 0, TclOffset(DateFormat, date.iso8601Year), NULL}, + {CTOKT_INT, "0", 4, 0, 0, 0, TclOffset(DateFormat, date.iso8601Year), NULL, NULL}, /* %j */ - {CTOKT_INT, "0", 3, 0, 0, 0, TclOffset(DateFormat, date.dayOfYear), NULL}, + {CTOKT_INT, "0", 3, 0, 0, 0, TclOffset(DateFormat, date.dayOfYear), NULL, NULL}, /* %J */ - {CTOKT_WIDE, "0", 7, 0, 0, 0, TclOffset(DateFormat, date.julianDay), NULL}, + {CTOKT_WIDE, "0", 7, 0, 0, 0, TclOffset(DateFormat, date.julianDay), NULL, NULL}, /* %s */ - {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.seconds), NULL}, + {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.seconds), NULL, NULL}, /* %n */ - {CTOKT_CHAR, "\n", 0, 0, 0, 0, 0, NULL}, + {CTOKT_CHAR, "\n", 0, 0, 0, 0, 0, NULL, NULL}, /* %t */ - {CTOKT_CHAR, "\t", 0, 0, 0, 0, 0, NULL}, + {CTOKT_CHAR, "\t", 0, 0, 0, 0, 0, NULL, NULL}, /* %Q */ {CFMTT_PROC, NULL, 0, 0, 0, 0, 0, ClockFmtToken_StarDate_Proc, NULL}, @@ -2989,7 +3002,7 @@ static ClockFormatTokenMap FmtETokenMap[] = { {CTOKT_INT, NULL, 0, 0, 0, 0, TclOffset(DateFormat, date.year), ClockFmtToken_LocaleERAYear_Proc, NULL}, /* %Es */ - {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.localSeconds), NULL}, + {CTOKT_WIDE, "0", 1, 0, 0, 0, TclOffset(DateFormat, date.localSeconds), NULL, NULL}, }; static const char *FmtETokenMapAliasIndex[2] = { "C", @@ -3033,7 +3046,7 @@ static const char *FmtOTokenMapAliasIndex[2] = { }; static ClockFormatTokenMap FmtWordTokenMap = { - CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL + CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL, NULL }; /* diff --git a/generic/tclStrIdxTree.c b/generic/tclStrIdxTree.c index 5736d64..4d76217 100644 --- a/generic/tclStrIdxTree.c +++ b/generic/tclStrIdxTree.c @@ -166,8 +166,8 @@ TclStrIdxTreeFree( static inline void TclStrIdxTreeInsertBranch( TclStrIdxTree *parent, - register TclStrIdx *item, - register TclStrIdx *child) + TclStrIdx *item, + TclStrIdx *child) { if (parent->firstPtr == child) parent->firstPtr = item; @@ -187,8 +187,8 @@ TclStrIdxTreeInsertBranch( static inline void TclStrIdxTreeAppend( - register TclStrIdxTree *parent, - register TclStrIdx *item) + TclStrIdxTree *parent, + TclStrIdx *item) { if (parent->lastPtr != NULL) { parent->lastPtr->nextPtr = item; diff --git a/tests/clock.test b/tests/clock.test index 5183b28..02bc9f7 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -308,14 +308,14 @@ test clock-0.2 "initial: loading of format/locale does not overwrite interp stat # Test some of the basics of [clock format] -set syntax "clock format clockval|-now ?-format string? ?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?" +set syntax "clockval|-now ?-format string? ?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?" test clock-1.0 "clock format - wrong # args" { list [catch {clock format} msg] $msg $::errorCode -} [subst {1 {wrong # args: should be "$syntax"} {CLOCK wrongNumArgs}}] +} [subst {1 {wrong # args: should be "clock format $syntax"} {CLOCK wrongNumArgs}}] test clock-1.0.1 "clock format - wrong # args (compiled ensemble with invalid syntax)" { list [catch {clock format 0 -too-few-options-4-test} msg] $msg $::errorCode -} [subst {1 {wrong # args: should be "$syntax"} {CLOCK wrongNumArgs}}] +} [subst {1 {wrong # args: should be "::tcl::clock::format $syntax"} {CLOCK wrongNumArgs}}] test clock-1.1 "clock format - bad time" { list [catch {clock format foo} msg] $msg -- 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 80922e4b680e89f50b4c75e7e7ea1b891b54ebac Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Feb 2021 08:02:27 +0000 Subject: Give TzsetIfNecessary "interp" argument. --- generic/tclClock.c | 16 ++++++++-------- tests/clock.test | 4 +--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index bc1c33c..6fffb31 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -140,7 +140,7 @@ static int ClockValidDate( DateInfo *, ClockFmtScnCmdArgs *, int stage); static struct tm * ThreadSafeLocalTime(const time_t *); -static size_t TzsetIfNecessary(void); +static size_t TzsetIfNecessary(Tcl_Interp *interp); static void ClockDeleteCmdProc(ClientData); static int ClockSafeCatchCmd( @@ -1014,7 +1014,7 @@ ClockConfigureObjCmd( case CLOCK_SYSTEM_TZ: if (1) { /* validate current tz-epoch */ - size_t lastTZEpoch = TzsetIfNecessary(); + size_t lastTZEpoch = TzsetIfNecessary(interp); if (i < objc) { if (dataPtr->systemTimeZone != objv[i]) { Tcl_SetObjRef(dataPtr->systemTimeZone, objv[i]); @@ -1272,7 +1272,7 @@ ClockGetSystemTimeZone( /* if known (cached and same epoch) - return now */ if (dataPtr->systemTimeZone != NULL - && dataPtr->lastTZEpoch == TzsetIfNecessary()) { + && dataPtr->lastTZEpoch == TzsetIfNecessary(interp)) { return dataPtr->systemTimeZone; } @@ -2137,7 +2137,7 @@ ConvertLocalToUTCUsingC( * platforms, so seize a mutex before attempting this. */ - TzsetIfNecessary(); + TzsetIfNecessary(interp); Tcl_MutexLock(&clockMutex); errno = 0; fields->seconds = (Tcl_WideInt) mktime(&timeVal); @@ -2373,7 +2373,7 @@ ConvertUTCToLocalUsingC( Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL); return TCL_ERROR; } - TzsetIfNecessary(); + TzsetIfNecessary(interp); timeVal = ThreadSafeLocalTime(&tock); if (timeVal == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -4628,7 +4628,7 @@ ClockSafeCatchCmd( */ static size_t -TzsetIfNecessary(void) +TzsetIfNecessary(Tcl_Interp *interp) { static char* tzWas = (char *)INT2PTR(-1); /* Previous value of TZ, protected by * clockMutex. */ @@ -4654,9 +4654,9 @@ TzsetIfNecessary(void) /* check in lock */ Tcl_MutexLock(&clockMutex); - tzIsNow = getenv("TCL_TZ"); + tzIsNow = Tcl_GetVar2(interp, "env", "TCL_TZ", TCL_GLOBAL_ONLY); if (tzIsNow == NULL) { - tzIsNow = getenv("TZ"); + tzIsNow = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY); } if (tzIsNow != NULL && (tzWas == NULL || tzWas == (char*)INT2PTR(-1) || strcmp(tzIsNow, tzWas) != 0)) { diff --git a/tests/clock.test b/tests/clock.test index 02bc9f7..641dbf6 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -31,8 +31,6 @@ testConstraint detroit \ [expr {![catch {clock format 0 -timezone :America/Detroit -format %z}]}] testConstraint y2038 \ [expr {[clock format 2158894800 -format %z -timezone :America/Detroit] eq {-0400}}] -testConstraint no_tclclockmod \ - [expr {[namespace which -command ::tcl::clock::configure] eq {}}] # Test with both validity modes - validate on / off: @@ -276,7 +274,7 @@ proc ::testClock::registry { cmd path key } { # Base test cases: -test clock-0.1 "initial: auto-loading of ensemble and stubs on demand" no_tclclockmod { +test clock-0.1 "initial: auto-loading of ensemble and stubs on demand" { set i [interp create]; # because clock can be used somewhere, test it in new interp: set ret [$i eval { -- cgit v0.12 From f6e9d201d539d7e38ef875e94133bc3708617574 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Feb 2021 13:14:55 +0000 Subject: Fix regression in msvc OPTS=static,msvcrt build. I think I finally got it now. --- generic/tclClock.c | 9 ++++----- library/clock.tcl | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 6fffb31..2cf9eb7 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3045,7 +3045,7 @@ ClockGetenvObjCmd( Tcl_Obj *const objv[]) { const char *varName; - const char *varValue; + Tcl_Obj *varValue; (void)clientData; if (objc != 2) { @@ -3053,11 +3053,10 @@ ClockGetenvObjCmd( return TCL_ERROR; } varName = TclGetString(objv[1]); - varValue = getenv(varName); - if (varValue == NULL) { - varValue = ""; + varValue = Tcl_GetVar2Ex(interp, "env", varName, TCL_GLOBAL_ONLY); + if (varValue != NULL) { + Tcl_SetObjResult(interp, varValue); } - Tcl_SetObjResult(interp, Tcl_NewStringObj(varValue, -1)); return TCL_OK; } diff --git a/library/clock.tcl b/library/clock.tcl index f06e033..1f1571a 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -905,12 +905,11 @@ 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 exists timezone]} { + if {[info exist ::env(TCL_TZ)]} { + set timezone $::env(TCL_TZ) + } elseif {[info exist ::env(TZ)]} { + set timezone $::env(TZ) + } elseif {![info exists timezone]} { # ask engine for the cached timezone: set timezone [configure -system-tz] if { $timezone ne "" } { -- cgit v0.12 From 3da138a42931159eb283ff3fae50444798c3e4f6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Feb 2021 13:32:44 +0000 Subject: Unneeded if() --- library/clock.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/clock.tcl b/library/clock.tcl index 1f1571a..68dd1c4 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -909,7 +909,7 @@ proc ::tcl::clock::GetSystemTimeZone {} { set timezone $::env(TCL_TZ) } elseif {[info exist ::env(TZ)]} { set timezone $::env(TZ) - } elseif {![info exists timezone]} { + } else { # ask engine for the cached timezone: set timezone [configure -system-tz] if { $timezone ne "" } { -- cgit v0.12 From 6caf32205752b3ee1e08cc4c19db4818dcd38f68 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Feb 2021 15:39:59 +0000 Subject: Better solution for msvc OPTS=static,msvcrt regression: On win32 we cannot thrust the getenv() function, so use _wgetenv() --- generic/tclBasic.c | 4 ++++ generic/tclClock.c | 67 ++++++++++++++++++++++++++++++++++++++---------------- library/clock.tcl | 8 +++---- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 895d160..2f1819f 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -583,6 +583,10 @@ Tcl_CreateInterp(void) Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS); iPtr->packageUnknown = NULL; +#ifdef _WIN32 +# define getenv(x) _wgetenv(L##x) /* On Windows, use _wgetenv below */ +#endif + /* TIP #268 */ if (getenv("TCL_PKG_PREFER_LATEST") == NULL) { iPtr->packagePrefer = PKG_PREFER_STABLE; diff --git a/generic/tclClock.c b/generic/tclClock.c index 2cf9eb7..9512b8d 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -140,7 +140,7 @@ static int ClockValidDate( DateInfo *, ClockFmtScnCmdArgs *, int stage); static struct tm * ThreadSafeLocalTime(const time_t *); -static size_t TzsetIfNecessary(Tcl_Interp *interp); +static size_t TzsetIfNecessary(void); static void ClockDeleteCmdProc(ClientData); static int ClockSafeCatchCmd( @@ -1014,7 +1014,7 @@ ClockConfigureObjCmd( case CLOCK_SYSTEM_TZ: if (1) { /* validate current tz-epoch */ - size_t lastTZEpoch = TzsetIfNecessary(interp); + size_t lastTZEpoch = TzsetIfNecessary(); if (i < objc) { if (dataPtr->systemTimeZone != objv[i]) { Tcl_SetObjRef(dataPtr->systemTimeZone, objv[i]); @@ -1272,7 +1272,7 @@ ClockGetSystemTimeZone( /* if known (cached and same epoch) - return now */ if (dataPtr->systemTimeZone != NULL - && dataPtr->lastTZEpoch == TzsetIfNecessary(interp)) { + && dataPtr->lastTZEpoch == TzsetIfNecessary()) { return dataPtr->systemTimeZone; } @@ -2137,7 +2137,7 @@ ConvertLocalToUTCUsingC( * platforms, so seize a mutex before attempting this. */ - TzsetIfNecessary(interp); + TzsetIfNecessary(); Tcl_MutexLock(&clockMutex); errno = 0; fields->seconds = (Tcl_WideInt) mktime(&timeVal); @@ -2373,7 +2373,7 @@ ConvertUTCToLocalUsingC( Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL); return TCL_ERROR; } - TzsetIfNecessary(interp); + TzsetIfNecessary(); timeVal = ThreadSafeLocalTime(&tock); if (timeVal == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -3044,19 +3044,37 @@ ClockGetenvObjCmd( int objc, Tcl_Obj *const objv[]) { +#ifdef _WIN32 + const WCHAR *varName; + const WCHAR *varValue; + Tcl_DString ds; +#else const char *varName; - Tcl_Obj *varValue; + const char *varValue; +#endif (void)clientData; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "name"); return TCL_ERROR; } +#ifdef _WIN32 + varName = (const WCHAR *)Tcl_WinUtfToTChar(TclGetString(objv[1]), -1, &ds); + varValue = _wgetenv(varName); + Tcl_DStringFree(&ds); + if (varValue == NULL) { + varValue = L""; + } + Tcl_WinTCharToUtf((TCHAR *)varValue, -1, &ds); + Tcl_DStringResult(interp, &ds); +#else varName = TclGetString(objv[1]); - varValue = Tcl_GetVar2Ex(interp, "env", varName, TCL_GLOBAL_ONLY); - if (varValue != NULL) { - Tcl_SetObjResult(interp, varValue); + varValue = getenv(varName); + if (varValue == NULL) { + varValue = ""; } + Tcl_SetObjResult(interp, Tcl_NewStringObj(varValue, -1)); +#endif return TCL_OK; } @@ -4626,16 +4644,25 @@ ClockSafeCatchCmd( *---------------------------------------------------------------------- */ +#ifdef _WIN32 +#define getenv(x) _wgetenv(L##x) +#else +#define WCHAR char +#define wcslen strlen +#define wcscmp strcmp +#define wcscpy strcpy +#endif + static size_t -TzsetIfNecessary(Tcl_Interp *interp) +TzsetIfNecessary(void) { - static char* tzWas = (char *)INT2PTR(-1); /* Previous value of TZ, protected by + static WCHAR* tzWas = (WCHAR *)INT2PTR(-1); /* Previous value of TZ, protected by * clockMutex. */ static long tzLastRefresh = 0; /* Used for latency before next refresh */ static size_t tzWasEpoch = 0; /* Epoch, signals that TZ changed */ static size_t tzEnvEpoch = 0; /* Last env epoch, for faster signaling, that TZ changed via TCL */ - const char *tzIsNow; /* Current value of TZ */ + const WCHAR *tzIsNow; /* Current value of TZ */ /* * Prevent performance regression on some platforms by resolving of system time zone: @@ -4653,22 +4680,22 @@ TzsetIfNecessary(Tcl_Interp *interp) /* check in lock */ Tcl_MutexLock(&clockMutex); - tzIsNow = Tcl_GetVar2(interp, "env", "TCL_TZ", TCL_GLOBAL_ONLY); + tzIsNow = getenv("TCL_TZ"); if (tzIsNow == NULL) { - tzIsNow = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY); + tzIsNow = getenv("TZ"); } - if (tzIsNow != NULL && (tzWas == NULL || tzWas == (char*)INT2PTR(-1) - || strcmp(tzIsNow, tzWas) != 0)) { + if (tzIsNow != NULL && (tzWas == NULL || tzWas == (WCHAR *)INT2PTR(-1) + || wcscmp(tzIsNow, tzWas) != 0)) { tzset(); - if (tzWas != NULL && tzWas != (char*)INT2PTR(-1)) { + if (tzWas != NULL && tzWas != (WCHAR *)INT2PTR(-1)) { ckfree(tzWas); } - tzWas = (char *)ckalloc(strlen(tzIsNow) + 1); - strcpy(tzWas, tzIsNow); + tzWas = (WCHAR *)ckalloc(sizeof(WCHAR) * (wcslen(tzIsNow) + 1)); + wcscpy(tzWas, tzIsNow); tzWasEpoch++; } else if (tzIsNow == NULL && tzWas != NULL) { tzset(); - if (tzWas != (char*)INT2PTR(-1)) ckfree(tzWas); + if (tzWas != (WCHAR *)INT2PTR(-1)) ckfree(tzWas); tzWas = NULL; tzWasEpoch++; } diff --git a/library/clock.tcl b/library/clock.tcl index 68dd1c4..529a4f9 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 {[info exist ::env(TCL_TZ)]} { - set timezone $::env(TCL_TZ) - } elseif {[info exist ::env(TZ)]} { - set timezone $::env(TZ) + if {[set result [getenv TCL_TZ]] ne {}} { + set timezone $result + } elseif {[set result [getenv TZ]] ne {}} { + set timezone $result } else { # ask engine for the cached timezone: set timezone [configure -system-tz] -- cgit v0.12 From 888ce88c144ed91f566873e6b29cda26ac71e8db Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 22 Feb 2021 15:45:09 +0000 Subject: Fix one more usage of getenv() on Windows --- generic/tclIOUtil.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 5566f3e..312fd08 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -3158,6 +3158,13 @@ Tcl_FSLoadFile( * present and set to true (any integer > 0) then the unlink is skipped. */ +#ifdef _WIN32 +#define getenv(x) _wgetenv(L##x) +#define atoi(x) _wtoi(x) +#else +#define WCHAR char +#endif + static int skipUnlink (Tcl_Obj* shlibFile) { @@ -3178,9 +3185,9 @@ skipUnlink (Tcl_Obj* shlibFile) #ifdef hpux return 1; #else - char* skipstr; + WCHAR *skipstr; - skipstr = getenv ("TCL_TEMPLOAD_NO_UNLINK"); + skipstr = getenv("TCL_TEMPLOAD_NO_UNLINK"); if (skipstr && (skipstr[0] != '\0')) { return atoi(skipstr); } -- 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 From 4cf5a76f8e6fa37f1c3bdc6637086910ad4e9a7d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 26 Feb 2024 13:04:02 +0000 Subject: More tweaks --- generic/tclClock.c | 40 +++++++++++++++++++--------------------- generic/tclClockFmt.c | 13 ++++++------- generic/tclDate.c | 8 ++++---- generic/tclGetDate.y | 8 ++++---- 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index b1caa01..e156cf3 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -740,7 +740,7 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) if (opts->localeObj == NULL) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("locale not specified and no default locale set", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", (char *)NULL); return NULL; } opts->flags |= CLF_LOCALE_USED; @@ -1007,7 +1007,7 @@ ClockConfigureObjCmd( if (Tcl_GetIndexFromObj(interp, objv[i++], options, "option", 0, &optionIndex) != TCL_OK) { Tcl_SetErrorCode(interp, "CLOCK", "badOption", - Tcl_GetString(objv[i-1]), NULL); + Tcl_GetString(objv[i-1]), (char *)NULL); return TCL_ERROR; } switch (optionIndex) { @@ -2370,7 +2370,7 @@ ConvertUTCToLocalUsingC( if ((Tcl_WideInt) tock != fields->seconds) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "number too large to represent as a Posix time", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", (char *)NULL); return TCL_ERROR; } TzsetIfNecessary(); @@ -2379,7 +2379,7 @@ ConvertUTCToLocalUsingC( Tcl_SetObjResult(interp, Tcl_NewStringObj( "localtime failed (clock value may be too " "large/small to represent)", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", (char *)NULL); return TCL_ERROR; } @@ -3062,18 +3062,16 @@ ClockGetenvObjCmd( varName = (const WCHAR *)Tcl_WinUtfToTChar(TclGetString(objv[1]), -1, &ds); varValue = _wgetenv(varName); Tcl_DStringFree(&ds); - if (varValue == NULL) { - varValue = L""; + if (varValue != NULL) { + Tcl_WinTCharToUtf((TCHAR *)varValue, -1, &ds); + Tcl_DStringResult(interp, &ds); } - Tcl_WinTCharToUtf((TCHAR *)varValue, -1, &ds); - Tcl_DStringResult(interp, &ds); #else varName = TclGetString(objv[1]); varValue = getenv(varName); - if (varValue == NULL) { - varValue = ""; + if (varValue != NULL) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(varValue, -1)); } - Tcl_SetObjResult(interp, Tcl_NewStringObj(varValue, -1)); #endif return TCL_OK; } @@ -3408,7 +3406,7 @@ ClockParseFmtScnArgs( if ((saw & (1 << CLC_ARGS_GMT)) && (saw & (1 << CLC_ARGS_TIMEZONE))) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot use -gmt and -timezone in same call", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "gmtWithTimezone", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "gmtWithTimezone", (char *)NULL); return TCL_ERROR; } if (gmtFlag) { @@ -3457,7 +3455,7 @@ ClockParseFmtScnArgs( Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected integer but got \"%s\"", Tcl_GetString(baseObj))); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", (char *)NULL); i = 1; goto badOption; } @@ -3519,7 +3517,7 @@ badOptionMsg: badOption: Tcl_SetErrorCode(interp, "CLOCK", "badOption", - i < objc ? Tcl_GetString(objv[i]) : NULL, NULL); + (i < objc) ? Tcl_GetString(objv[i]) : (char *)NULL, (char *)NULL); return TCL_ERROR; } @@ -3564,7 +3562,7 @@ ClockFormatObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -3641,7 +3639,7 @@ ClockScanObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -3669,7 +3667,7 @@ ClockScanObjCmd( if (opts.localeObj != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("legacy [clock scan] does not support -locale", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", (char *)NULL); ret = TCL_ERROR; goto done; } @@ -3758,7 +3756,7 @@ ClockScanCommit( if (curJDN > dataPtr->maxJDN) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( "requested date too large to represent", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", (char *)NULL); return TCL_ERROR; } } @@ -3943,7 +3941,7 @@ ClockValidDate( error: Tcl_SetObjResult(opts->interp, Tcl_ObjPrintf("unable to convert input string: %s", errMsg)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "invInpStr", errCode, NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "invInpStr", errCode, (char *)NULL); return TCL_ERROR; } @@ -4393,7 +4391,7 @@ ClockAddObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -4574,7 +4572,7 @@ ClockSafeCatchCmd( int objc, Tcl_Obj *const objv[]) { - typedef struct InterpState { + typedef struct { int status; /* return code status */ int flags; /* Each remaining field saves the */ int returnLevel; /* corresponding field of the Interp */ diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 29869d6..a25be83 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -59,7 +59,6 @@ static void ClockFrmScnFinalize(ClientData clientData); static inline int _str2int( int *out, - register const char *p, const char *e, int sign) @@ -89,7 +88,6 @@ _str2int( static inline int _str2wideInt( Tcl_WideInt *out, - register const char *p, const char *e, int sign) @@ -510,7 +508,7 @@ static Tcl_HashKeyType ClockFmtScnStorageHashKeyType; * Type definition of clock-format tcl object type. */ -Tcl_ObjType ClockFmtObjType = { +static const Tcl_ObjType ClockFmtObjType = { "clock-format", /* name */ ClockFmtObj_FreeInternalRep, /* freeIntRepProc */ ClockFmtObj_DupInternalRep, /* dupIntRepProc */ @@ -742,7 +740,7 @@ FindOrCreateFmtScnStorage( if (fss == NULL && interp != NULL) { Tcl_AppendResult(interp, "retrieve clock format failed \"", strFmt ? strFmt : "", "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "EINVAL", NULL); + Tcl_SetErrorCode(interp, "TCL", "EINVAL", (char *)NULL); } return fss; @@ -1460,7 +1458,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, } if (val > 7) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("day of week is greater than 7", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "badDayOfWeek", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badDayOfWeek", (char *)NULL); return TCL_ERROR; } info->date.dayOfWeek = val; @@ -2420,6 +2418,7 @@ ClockScan( case (CLF_DAYOFYEAR|CLF_DAYOFMONTH): /* miss month: ddd over dd (without month) */ flags &= ~CLF_DAYOFMONTH; + /* fallthrough */ case (CLF_DAYOFYEAR): /* ddd over naked weekday */ if (!(flags & CLF_ISO8601YEAR)) { @@ -2525,7 +2524,7 @@ overflow: Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("integer value too large to represent", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", (char *)NULL); goto done; not_match: @@ -2542,7 +2541,7 @@ not_match: Tcl_GetString(opts->localeObj), tok && tok->tokWord.start ? tok->tokWord.start : "NULL")); #endif - Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", (char *)NULL); done: diff --git a/generic/tclDate.c b/generic/tclDate.c index 0f9b3b9..fa4cf4f 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -2850,24 +2850,24 @@ TclClockFreeScan( } if (msg) { Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); } else { Tcl_SetObjResult(interp, info->messages ? info->messages : Tcl_NewObj()); info->messages = NULL; - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); } status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL); 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_SetErrorCode(interp, "TCL", "BUG", NULL); + Tcl_SetErrorCode(interp, "TCL", "BUG", (char *)NULL); status = TCL_ERROR; } if (info->messages) { diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 45eae1d..25802d8 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -1057,24 +1057,24 @@ TclClockFreeScan( } if (msg) { Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); } else { Tcl_SetObjResult(interp, info->messages ? info->messages : Tcl_NewObj()); info->messages = NULL; - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); } status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL); 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_SetErrorCode(interp, "TCL", "BUG", NULL); + Tcl_SetErrorCode(interp, "TCL", "BUG", (char *)NULL); status = TCL_ERROR; } if (info->messages) { -- cgit v0.12 From 64c5790b7194f8b3789343032fc2c1d8edb8388e Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 26 Feb 2024 13:20:40 +0000 Subject: (cherry-pick) More tweaks --- generic/tclClock.c | 38 +++++++++++++++++++------------------- generic/tclClockFmt.c | 8 ++++---- generic/tclDate.c | 8 ++++---- generic/tclGetDate.y | 8 ++++---- generic/tclStrIdxTree.c | 2 +- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index c16ae74..042b7e5 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -740,7 +740,7 @@ ClockMCDict(ClockFmtScnCmdArgs *opts) if (opts->localeObj == NULL) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("locale not specified and no default locale set", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", (char *)NULL); return NULL; } opts->flags |= CLF_LOCALE_USED; @@ -1007,7 +1007,7 @@ ClockConfigureObjCmd( if (Tcl_GetIndexFromObj(interp, objv[i++], options, "option", 0, &optionIndex) != TCL_OK) { Tcl_SetErrorCode(interp, "CLOCK", "badOption", - Tcl_GetString(objv[i-1]), NULL); + Tcl_GetString(objv[i-1]), (char *)NULL); return TCL_ERROR; } switch (optionIndex) { @@ -2141,7 +2141,7 @@ ConvertLocalToUTCUsingC( Tcl_MutexLock(&clockMutex); errno = 0; fields->seconds = (Tcl_WideInt) mktime(&timeVal); - localErrno = errno; + localErrno = (fields->seconds == -1) ? errno : 0; Tcl_MutexUnlock(&clockMutex); /* @@ -2370,7 +2370,7 @@ ConvertUTCToLocalUsingC( if ((Tcl_WideInt) tock != fields->seconds) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "number too large to represent as a Posix time", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", (char *)NULL); return TCL_ERROR; } TzsetIfNecessary(); @@ -2379,7 +2379,7 @@ ConvertUTCToLocalUsingC( Tcl_SetObjResult(interp, Tcl_NewStringObj( "localtime failed (clock value may be too " "large/small to represent)", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", (char *)NULL); return TCL_ERROR; } @@ -2413,12 +2413,12 @@ ConvertUTCToLocalUsingC( } else { *buffer = '+'; } - sprintf(buffer+1, "%02d", diff / 3600); + snprintf(buffer+1, sizeof(buffer) - 1, "%02d", diff / 3600); diff %= 3600; - sprintf(buffer+3, "%02d", diff / 60); + snprintf(buffer+3, sizeof(buffer) - 3, "%02d", diff / 60); diff %= 60; if (diff > 0) { - sprintf(buffer+5, "%02d", diff); + snprintf(buffer+5, sizeof(buffer) - 5, "%02d", diff); } Tcl_SetObjRef(fields->tzName, Tcl_NewStringObj(buffer, -1)); return TCL_OK; @@ -2859,9 +2859,9 @@ GetJulianDayFromEraYearMonthDay( * Have to make sure quotient is truncated towards 0 when negative. * See above bug for details. The casts are necessary. */ - if (ym1 >= 0) + if (ym1 >= 0) { ym1o4 = ym1 / 4; - else { + } else { ym1o4 = - (int) (((unsigned int) -ym1) / 4); } #endif @@ -3405,7 +3405,7 @@ ClockParseFmtScnArgs( if ((saw & (1 << CLC_ARGS_GMT)) && (saw & (1 << CLC_ARGS_TIMEZONE))) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot use -gmt and -timezone in same call", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "gmtWithTimezone", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "gmtWithTimezone", (char *)NULL); return TCL_ERROR; } if (gmtFlag) { @@ -3454,7 +3454,7 @@ ClockParseFmtScnArgs( Tcl_SetObjResult(interp, Tcl_ObjPrintf( "expected integer but got \"%s\"", Tcl_GetString(baseObj))); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", (char *)NULL); i = 1; goto badOption; } @@ -3516,7 +3516,7 @@ badOptionMsg: badOption: Tcl_SetErrorCode(interp, "CLOCK", "badOption", - i < objc ? Tcl_GetString(objv[i]) : NULL, NULL); + (i < objc) ? Tcl_GetString(objv[i]) : (char *)NULL, (char *)NULL); return TCL_ERROR; } @@ -3561,7 +3561,7 @@ ClockFormatObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -3638,7 +3638,7 @@ ClockScanObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -3666,7 +3666,7 @@ ClockScanObjCmd( if (opts.localeObj != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("legacy [clock scan] does not support -locale", -1)); - Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", (char *)NULL); ret = TCL_ERROR; goto done; } @@ -3755,7 +3755,7 @@ ClockScanCommit( if (curJDN > dataPtr->maxJDN) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj( "requested date too large to represent", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", (char *)NULL); return TCL_ERROR; } } @@ -3940,7 +3940,7 @@ ClockValidDate( error: Tcl_SetObjResult(opts->interp, Tcl_ObjPrintf("unable to convert input string: %s", errMsg)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "invInpStr", errCode, NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "invInpStr", errCode, (char *)NULL); return TCL_ERROR; } @@ -4390,7 +4390,7 @@ ClockAddObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { Tcl_WrongNumArgs(interp, 1, objv, syntax); - Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", NULL); + Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 35a7de2..3982c15 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -739,7 +739,7 @@ FindOrCreateFmtScnStorage( if (fss == NULL && interp != NULL) { Tcl_AppendResult(interp, "retrieve clock format failed \"", strFmt ? strFmt : "", "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "EINVAL", NULL); + Tcl_SetErrorCode(interp, "TCL", "EINVAL", (char *)NULL); } return fss; @@ -1457,7 +1457,7 @@ ClockScnToken_DayOfWeek_Proc(ClockFmtScnCmdArgs *opts, } if (val > 7) { Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("day of week is greater than 7", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "badDayOfWeek", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badDayOfWeek", (char *)NULL); return TCL_ERROR; } info->date.dayOfWeek = val; @@ -2521,7 +2521,7 @@ overflow: Tcl_SetObjResult(opts->interp, Tcl_NewStringObj("integer value too large to represent", -1)); - Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "dateTooLarge", (char *)NULL); goto done; not_match: @@ -2538,7 +2538,7 @@ not_match: Tcl_GetString(opts->localeObj), tok && tok->tokWord.start ? tok->tokWord.start : "NULL")); #endif - Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", NULL); + Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", (char *)NULL); done: diff --git a/generic/tclDate.c b/generic/tclDate.c index 1045e3a..28878e4 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -2849,24 +2849,24 @@ TclClockFreeScan( } if (msg) { Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); } else { Tcl_SetObjResult(interp, info->messages ? info->messages : Tcl_NewObj()); info->messages = NULL; - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); } status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", (void *)NULL); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL); 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_SetErrorCode(interp, "TCL", "BUG", NULL); + Tcl_SetErrorCode(interp, "TCL", "BUG", (char *)NULL); status = TCL_ERROR; } if (info->messages) { diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index c7631c8..270a3a8 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -1057,24 +1057,24 @@ TclClockFreeScan( } if (msg) { Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "MULTIPLE", (char *)NULL); } else { Tcl_SetObjResult(interp, info->messages ? info->messages : Tcl_NewObj()); info->messages = NULL; - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", (char *)NULL); } status = TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL); 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_SetErrorCode(interp, "TCL", "BUG", NULL); + Tcl_SetErrorCode(interp, "TCL", "BUG", (char *)NULL); status = TCL_ERROR; } if (info->messages) { diff --git a/generic/tclStrIdxTree.c b/generic/tclStrIdxTree.c index 21b5e71..d52f0ff 100644 --- a/generic/tclStrIdxTree.c +++ b/generic/tclStrIdxTree.c @@ -477,7 +477,7 @@ TclStrIdxTreeTestObjCmd( if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &optionIndex) != TCL_OK) { Tcl_SetErrorCode(interp, "CLOCK", "badOption", - Tcl_GetString(objv[1]), NULL); + Tcl_GetString(objv[1]), (char *)NULL); return TCL_ERROR; } switch (optionIndex) { -- cgit v0.12 From 619b123c9617d114a6cf0ced71f1013093289490 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 26 Feb 2024 13:25:20 +0000 Subject: One more little tweak missing --- generic/tclClock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 042b7e5..76f9af1 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -3116,7 +3116,7 @@ ThreadSafeLocalTime( Tcl_MutexUnlock(&clockMutex); return NULL; } - memcpy(tmPtr, localtime(timePtr), sizeof(struct tm)); + memcpy(tmPtr, sysTmPtr, sizeof(struct tm)); Tcl_MutexUnlock(&clockMutex); #endif return tmPtr; -- cgit v0.12 From 59837fad8458d5313d8847986385bf1170585302 Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 4 Mar 2024 11:09:49 +0000 Subject: Minimize diff to main branch by comment correction --- tests/http.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/http.test b/tests/http.test index cd61b7b..f7bb723 100644 --- a/tests/http.test +++ b/tests/http.test @@ -759,7 +759,7 @@ test http-idna-1.1.$ThreadLevel {IDNA package: basics} -returnCodes error -body } -result {wrong # args: should be "::tcl::idna subcommand ?arg ...?"} test http-idna-1.2.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna ? -} -result {unknown subcommand "?": must be decode, encode, puny, or version} +} -result {unknown or ambiguous subcommand "?": must be decode, encode, puny, or version} test http-idna-1.3.$ThreadLevel {IDNA package: basics} -body { ::tcl::idna version } -result 1.0.1 @@ -771,7 +771,7 @@ test http-idna-1.5.$ThreadLevel {IDNA package: basics} -returnCodes error -body } -result {wrong # args: should be "::tcl::idna puny subcommand ?arg ...?"} test http-idna-1.6.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna puny ? -} -result {unknown subcommand "?": must be decode, or encode} +} -result {unknown or ambiguous subcommand "?": must be decode, or encode} test http-idna-1.7.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna puny encode } -result {wrong # args: should be "::tcl::idna puny encode string ?case?"} -- cgit v0.12 From afd034f212422fe160f6fb2338742a45e5ad2780 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 11 Mar 2024 11:02:19 +0000 Subject: Fix [1acd172c424b57c9] (by just reverting the change causing this). Not crucial for TIP #688. Also, make it compile/run using -DTCL_NO_DEPRECATED=1 --- generic/tcl.h | 2 +- generic/tclClock.c | 2 +- generic/tclClockFmt.c | 21 ++++++++++----------- generic/tclDate.h | 6 +++--- generic/tclEnsemble.c | 8 -------- generic/tclStrIdxTree.c | 9 +++++---- generic/tclStrIdxTree.h | 7 +++---- tests/clock.test | 2 +- tests/http.test | 4 ++-- 9 files changed, 26 insertions(+), 35 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index a4480a7..0d3da74 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -230,7 +230,7 @@ extern "C" { * Miscellaneous declarations. */ -typedef void *ClientData; +// typedef void *ClientData; /* * Darwin specific configure overrides (to support fat compiles, where diff --git a/generic/tclClock.c b/generic/tclClock.c index c0be910..cf5b7d5 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -2164,7 +2164,7 @@ ConvertUTCToLocal( if (dataPtr->gmtTZName == NULL) { Tcl_Obj *tzName; tzdata = ClockGetTZData(clientData, interp, timezoneObj); - if ( TclListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK + if ( TclListObjGetElementsM(interp, tzdata, &rowc, &rowv) != TCL_OK || Tcl_ListObjIndex(interp, rowv[0], 3, &tzName) != TCL_OK) { return TCL_ERROR; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index bf566ff..9bf10ed 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -32,7 +32,7 @@ TCL_DECLARE_MUTEX(ClockFmtMutex); /* Serializes access to common format list. */ static void ClockFmtScnStorageDelete(ClockFmtScnStorage *fss); -static void ClockFrmScnFinalize(ClientData clientData); +static void ClockFrmScnFinalize(void *clientData); /* * Clock scan and format facilities. @@ -1103,7 +1103,7 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts, int minLen, int maxLen) { Tcl_Obj **lstv; - int lstc; + Tcl_Size lstc; Tcl_Obj *valObj; /* get msgcat value */ @@ -1113,7 +1113,7 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts, } /* is a list */ - if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { + if (TclListObjGetElementsM(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { return TCL_ERROR; } @@ -1159,7 +1159,7 @@ ClockMCGetListIdxTree( /* build new index */ Tcl_Obj **lstv; - int lstc; + Tcl_Size lstc; Tcl_Obj *valObj; objPtr = TclStrIdxTreeNewObj(); @@ -1172,7 +1172,7 @@ ClockMCGetListIdxTree( goto done; } - if (TclListObjGetElements(opts->interp, valObj, + if (TclListObjGetElementsM(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { goto done; }; @@ -1232,7 +1232,7 @@ ClockMCGetMultiListIdxTree( /* build new index */ Tcl_Obj **lstv; - int lstc; + Tcl_Size lstc; Tcl_Obj *valObj; objPtr = TclStrIdxTreeNewObj(); @@ -1247,7 +1247,7 @@ ClockMCGetMultiListIdxTree( goto done; } - if (TclListObjGetElements(opts->interp, valObj, + if (TclListObjGetElementsM(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { goto done; }; @@ -2809,7 +2809,7 @@ ClockFmtToken_LocaleERAYear_Proc( ClockFormatToken *tok, int *val) { - int rowc; + Tcl_Size rowc; Tcl_Obj **rowv; if (dateFmt->localeEra == NULL) { @@ -2817,7 +2817,7 @@ ClockFmtToken_LocaleERAYear_Proc( if (mcObj == NULL) { return TCL_ERROR; } - if (TclListObjGetElements(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) { + if (TclListObjGetElementsM(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) { return TCL_ERROR; } if (rowc != 0) { @@ -3349,9 +3349,8 @@ ClockFrmScnClearCaches(void) static void ClockFrmScnFinalize( - ClientData clientData) /* Not used. */ + TCL_UNUSED(void *)) { - (void)clientData; Tcl_MutexLock(&ClockFmtMutex); #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0 /* clear GC */ diff --git a/generic/tclDate.h b/generic/tclDate.h index 6369e14..911e285 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -270,7 +270,7 @@ ClockInitDateInfo(DateInfo *info) { #define CLF_LOCALE_USED (1 << 15) typedef struct ClockFmtScnCmdArgs { - ClientData clientData; /* Opaque pointer to literal pool, etc. */ + void *clientData; /* Opaque pointer to literal pool, etc. */ Tcl_Interp *interp; /* Tcl interpreter */ Tcl_Obj *formatObj; /* Format */ @@ -513,7 +513,7 @@ MODULE_SCOPE void MODULE_SCOPE void GetJulianDayFromEraYearDay( TclDateFields *fields, int changeover); -MODULE_SCOPE int ConvertUTCToLocal(ClientData clientData, Tcl_Interp *, +MODULE_SCOPE int ConvertUTCToLocal(void *clientData, Tcl_Interp *, TclDateFields *, Tcl_Obj *timezoneObj, int); MODULE_SCOPE Tcl_Obj * LookupLastTransition(Tcl_Interp *, Tcl_WideInt, @@ -524,7 +524,7 @@ MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info); /* tclClock.c module declarations */ MODULE_SCOPE Tcl_Obj * - ClockSetupTimeZone(ClientData clientData, + ClockSetupTimeZone(void *clientData, Tcl_Interp *interp, Tcl_Obj *timezoneObj); MODULE_SCOPE Tcl_Obj * diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 1bab757..8614171 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -369,14 +369,6 @@ TclNamespaceEnsembleCmd( Tcl_SetEnsembleMappingDict(interp, token, mapObj); Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); Tcl_SetEnsembleParameterList(interp, token, paramObj); - /* - * Ensemble should be compiled if it has map (performance purposes) - * Currently only for internal using namespace (like ::tcl::clock). - * (An enhancement for completelly compile-feature is in work.) - */ - if (mapObj != NULL && strncmp("::tcl::", nsPtr->fullName, 7) == 0) { - Tcl_SetEnsembleFlags(interp, token, ENSEMBLE_COMPILE); - } /* * Tricky! Must ensure that the result is not shared (command delete diff --git a/generic/tclStrIdxTree.c b/generic/tclStrIdxTree.c index d52f0ff..bdb16f2 100644 --- a/generic/tclStrIdxTree.c +++ b/generic/tclStrIdxTree.c @@ -226,13 +226,14 @@ TclStrIdxTreeAppend( int TclStrIdxTreeBuildFromList( TclStrIdxTree *idxTree, - int lstc, + Tcl_Size lstc, Tcl_Obj **lstv, - ClientData *values) + void **values) { Tcl_Obj **lwrv; - int i, ret = TCL_ERROR; - ClientData val; + Tcl_Size i; + int ret = TCL_ERROR; + void *val; const char *s, *e, *f; TclStrIdx *item; diff --git a/generic/tclStrIdxTree.h b/generic/tclStrIdxTree.h index 37931ed..19e7624 100644 --- a/generic/tclStrIdxTree.h +++ b/generic/tclStrIdxTree.h @@ -29,7 +29,7 @@ typedef struct TclStrIdx { struct TclStrIdx *prevPtr; Tcl_Obj *key; int length; - ClientData value; + void *value; } TclStrIdx; @@ -139,7 +139,7 @@ MODULE_SCOPE const char* const char *start, const char *end); MODULE_SCOPE int TclStrIdxTreeBuildFromList(TclStrIdxTree *idxTree, - int lstc, Tcl_Obj **lstv, ClientData *values); + Tcl_Size lstc, Tcl_Obj **lstv, void **values); MODULE_SCOPE Tcl_Obj* TclStrIdxTreeNewObj(); @@ -149,8 +149,7 @@ MODULE_SCOPE TclStrIdxTree* #if 1 -MODULE_SCOPE int TclStrIdxTreeTestObjCmd(ClientData, Tcl_Interp *, - int, Tcl_Obj *const objv[]); +MODULE_SCOPE Tcl_ObjCmdProc TclStrIdxTreeTestObjCmd; #endif #endif /* _TCLSTRIDXTREE_H */ diff --git a/tests/clock.test b/tests/clock.test index 8a2218c..8f82b00 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -315,7 +315,7 @@ test clock-1.0 "clock format - wrong # args" { test clock-1.0.1 "clock format - wrong # args (compiled ensemble with invalid syntax)" { list [catch {clock format 0 -too-few-options-4-test} msg] $msg $::errorCode -} [subst {1 {wrong # args: should be "::tcl::clock::format $syntax"} {CLOCK wrongNumArgs}}] +} [subst {1 {wrong # args: should be "clock format $syntax"} {CLOCK wrongNumArgs}}] test clock-1.1 "clock format - bad time" { list [catch {clock format foo} msg] $msg diff --git a/tests/http.test b/tests/http.test index cd61b7b..f7bb723 100644 --- a/tests/http.test +++ b/tests/http.test @@ -759,7 +759,7 @@ test http-idna-1.1.$ThreadLevel {IDNA package: basics} -returnCodes error -body } -result {wrong # args: should be "::tcl::idna subcommand ?arg ...?"} test http-idna-1.2.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna ? -} -result {unknown subcommand "?": must be decode, encode, puny, or version} +} -result {unknown or ambiguous subcommand "?": must be decode, encode, puny, or version} test http-idna-1.3.$ThreadLevel {IDNA package: basics} -body { ::tcl::idna version } -result 1.0.1 @@ -771,7 +771,7 @@ test http-idna-1.5.$ThreadLevel {IDNA package: basics} -returnCodes error -body } -result {wrong # args: should be "::tcl::idna puny subcommand ?arg ...?"} test http-idna-1.6.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna puny ? -} -result {unknown subcommand "?": must be decode, or encode} +} -result {unknown or ambiguous subcommand "?": must be decode, or encode} test http-idna-1.7.$ThreadLevel {IDNA package: basics} -returnCodes error -body { ::tcl::idna puny encode } -result {wrong # args: should be "::tcl::idna puny encode string ?case?"} -- cgit v0.12 From 1bccb39a50fac43dbba87150412310a38001ad4b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 11 Mar 2024 11:55:58 +0000 Subject: Use {} in expr. Enable no_tclclockmod testcase --- tests/clock.test | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/clock.test b/tests/clock.test index 8f82b00..f74b58b 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -31,8 +31,6 @@ testConstraint detroit \ [expr {![catch {clock format 0 -timezone :America/Detroit -format %z}]}] testConstraint y2038 \ [expr {[clock format 2158894800 -format %z -timezone :America/Detroit] eq {-0400}}] -testConstraint no_tclclockmod \ - [expr {[namespace which -command ::tcl::clock::configure] eq {}}] # Test with both validity modes - validate on / off: @@ -276,7 +274,7 @@ proc ::testClock::registry { cmd path key } { # Base test cases: -test clock-0.1 "initial: auto-loading of ensemble and stubs on demand" no_tclclockmod { +test clock-0.1 "initial: auto-loading of ensemble and stubs on demand" { set i [interp create]; # because clock can be used somewhere, test it in new interp: set ret [$i eval { @@ -15396,7 +15394,7 @@ test clock-4.97.8 { format JDN/JD (calendar and astronomical) } { -1 0 1 21600 43199 43200 86399 86400 86401 108000 129600 172800 } { - lappend res $i [clock format [expr -210866803200 - $i] \ + lappend res $i [clock format [expr {-210866803200 - $i}] \ -format {%EE %Y-%m-%d %T -- %J %EJ %Ej} -gmt true] } set res @@ -15425,7 +15423,7 @@ test clock-4.97.9 { format JDN/JD (calendar and astronomical) } { -1 0 1 43199 43200 43201 86400 } { - lappend res $i [clock format [expr 653133196800 + $i] \ + lappend res $i [clock format [expr {653133196800 + $i}] \ -format {%Y-%m-%d %T -- %J %EJ %Ej} -gmt true] } set res @@ -36013,7 +36011,7 @@ test clock-33.5 {clock clicks tests, millisecond timing test} { expr { ($end > $start) && (($end - $start) <= 60) ? "ok" : - "test should have taken 0-60 ms, actually took [expr $end - $start]"} + "test should have taken 0-60 ms, actually took [expr {$end - $start}]"} } {ok} test clock-33.5a {clock tests, millisecond timing test} { # This test can fail on a system that is so heavily loaded that @@ -36029,7 +36027,7 @@ test clock-33.5a {clock tests, millisecond timing test} { expr { ($end > $start) && (($end - $start) <= 60) ? "ok" : - "test should have taken 0-60 ms, actually took [expr $end - $start]"} + "test should have taken 0-60 ms, actually took [expr {$end - $start}]"} } {ok} test clock-33.6 {clock clicks, milli with too much abbreviation} { list [catch { clock clicks ? } msg] $msg -- cgit v0.12 From 74a458b601e64698a1099bf06bed6917c4ff3f3d Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 11 Mar 2024 13:31:46 +0000 Subject: more int -> Tcl_Size --- generic/tclClock.c | 15 ++++++++------- generic/tclClockFmt.c | 43 +++++++++++++++++++++---------------------- generic/tclDate.h | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index cf5b7d5..1c91578 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -2412,12 +2412,11 @@ Tcl_Obj * LookupLastTransition( Tcl_Interp *interp, /* Interpreter for error messages */ Tcl_WideInt tick, /* Time from the epoch */ - int rowc, /* Number of rows of tzdata */ + Tcl_Size rowc, /* Number of rows of tzdata */ Tcl_Obj *const *rowv, /* Rows in tzdata */ Tcl_WideInt *rangesVal) /* Return bounds for time period */ { - int l = 0; - int u; + Tcl_Size l, u; Tcl_Obj *compObj; Tcl_WideInt compVal, fromVal = LLONG_MIN, toVal = LLONG_MAX; @@ -2447,9 +2446,10 @@ LookupLastTransition( * Binary-search to find the transition. */ + l = 0; u = rowc-1; while (l < u) { - int m = (l + u + 1) / 2; + Tcl_Size m = (l + u + 1) / 2; if (Tcl_ListObjIndex(interp, rowv[m], 0, &compObj) != TCL_OK || TclGetWideIntFromObj(interp, compObj, &compVal) != TCL_OK) { @@ -3955,7 +3955,8 @@ ClockFreeScan( yyInput = Tcl_GetString(strObj); if (TclClockFreeScan(interp, info) != TCL_OK) { - Tcl_Obj *msg = Tcl_NewObj(); + Tcl_Obj *msg; + TclNewObj(msg); Tcl_AppendPrintfToObj(msg, "unable to convert date-time string \"%s\": %s", Tcl_GetString(strObj), TclGetString(Tcl_GetObjResult(interp))); Tcl_SetObjResult(interp, msg); @@ -4628,7 +4629,7 @@ TzsetIfNecessary(void) { static WCHAR* tzWas = (WCHAR *)INT2PTR(-1); /* Previous value of TZ, protected by * clockMutex. */ - static long tzLastRefresh = 0; /* Used for latency before next refresh */ + static long long tzLastRefresh = 0; /* Used for latency before next refresh */ static size_t tzWasEpoch = 0; /* Epoch, signals that TZ changed */ static size_t tzEnvEpoch = 0; /* Last env epoch, for faster signaling, that TZ changed via TCL */ @@ -4637,7 +4638,7 @@ TzsetIfNecessary(void) /* * Prevent performance regression on some platforms by resolving of system time zone: * small latency for check whether environment was changed (once per second) - * no latency if environment was chaned with tcl-env (compare both epoch values) + * no latency if environment was changed with tcl-env (compare both epoch values) */ Tcl_Time now; Tcl_GetTime(&now); diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 9bf10ed..f79a863 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -606,7 +606,7 @@ ClockFmtObj_UpdateString( Tcl_Obj *objPtr) { const char *name = "UNKNOWN"; - int len; + size_t len; ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr); if (fss != NULL) { @@ -614,10 +614,11 @@ ClockFmtObj_UpdateString( name = hPtr->key.string; } len = strlen(name); - objPtr->length = len, - objPtr->bytes = (char *)Tcl_Alloc((size_t)++len); - if (objPtr->bytes) + objPtr->length = len++, + objPtr->bytes = (char *)Tcl_Alloc(len); + if (objPtr->bytes) { memcpy(objPtr->bytes, name, len); + } } /* @@ -1053,15 +1054,14 @@ DetermineGreedySearchLen( static inline int ObjListSearch( DateInfo *info, int *val, - Tcl_Obj **lstv, int lstc, + Tcl_Obj **lstv, Tcl_Size lstc, int minLen, int maxLen) { - int i, l, lf = -1; + Tcl_Size i, l, lf = -1; const char *s, *f, *sf; /* search in list */ for (i = 0; i < lstc; i++) { - s = TclGetString(lstv[i]); - l = lstv[i]->length; + s = Tcl_GetStringFromObj(lstv[i], &l); if ( l >= minLen && (f = TclUtfFindEqualNC(yyInput, yyInput + maxLen, s, s + l, &sf)) > yyInput @@ -1323,7 +1323,7 @@ static int StaticListSearch(ClockFmtScnCmdArgs *opts, DateInfo *info, const char **lst, int *val) { - int len; + size_t len; const char **s = lst; while (*s != NULL) { len = strlen(*s); @@ -2598,7 +2598,7 @@ ClockFmtToken_AMPM_Proc( { Tcl_Obj *mcObj; const char *s; - int len; + Tcl_Size len; if (*val < (SECONDS_PER_DAY / 2)) { mcObj = ClockMCGet(opts, MCLIT_AM); @@ -2608,7 +2608,7 @@ ClockFmtToken_AMPM_Proc( if (mcObj == NULL) { return TCL_ERROR; } - s = TclGetString(mcObj); len = mcObj->length; + s = Tcl_GetStringFromObj(mcObj, &len); if (FrmResultAllocate(dateFmt, len) != TCL_OK) { return TCL_ERROR; }; memcpy(dateFmt->output, s, len + 1); if (*tok->tokWord.start == 'p') { @@ -2758,7 +2758,7 @@ ClockFmtToken_TimeZone_Proc( } } else { Tcl_Obj * objPtr; - const char *s; int len; + const char *s; Tcl_Size len; /* convert seconds to local seconds to obtain tzName object */ if (ConvertUTCToLocal(opts->clientData, opts->interp, &dateFmt->date, opts->timezoneObj, @@ -2766,8 +2766,7 @@ ClockFmtToken_TimeZone_Proc( return TCL_ERROR; }; objPtr = dateFmt->date.tzName; - s = TclGetString(objPtr); - len = objPtr->length; + s = Tcl_GetStringFromObj(objPtr, &len); if (FrmResultAllocate(dateFmt, len) != TCL_OK) { return TCL_ERROR; }; memcpy(dateFmt->output, s, len + 1); dateFmt->output += len; @@ -2784,7 +2783,7 @@ ClockFmtToken_LocaleERA_Proc( { Tcl_Obj *mcObj; const char *s; - int len; + Tcl_Size len; if (dateFmt->date.isBce) { mcObj = ClockMCGet(opts, MCLIT_BCE); @@ -2794,7 +2793,7 @@ ClockFmtToken_LocaleERA_Proc( if (mcObj == NULL) { return TCL_ERROR; } - s = TclGetString(mcObj); len = mcObj->length; + s = Tcl_GetStringFromObj(mcObj, &len); if (FrmResultAllocate(dateFmt, len) != TCL_OK) { return TCL_ERROR; }; memcpy(dateFmt->output, s, len + 1); dateFmt->output += len; @@ -2844,7 +2843,7 @@ ClockFmtToken_LocaleERAYear_Proc( } else { Tcl_Obj *objPtr; const char *s; - int len; + Tcl_Size len; if (*tok->tokWord.start == 'C') { /* %EC */ if (Tcl_ListObjIndex(opts->interp, dateFmt->localeEra, 1, &objPtr) != TCL_OK ) { @@ -2877,8 +2876,7 @@ ClockFmtToken_LocaleERAYear_Proc( return TCL_OK; } } - s = TclGetString(objPtr); - len = objPtr->length; + s = Tcl_GetStringFromObj(objPtr, &len); if (FrmResultAllocate(dateFmt, len) != TCL_OK) { return TCL_ERROR; }; memcpy(dateFmt->output, s, len + 1); dateFmt->output += len; @@ -3281,7 +3279,7 @@ ClockFormat( break; case CTOKT_WORD: if (1) { - int len = tok->tokWord.end - tok->tokWord.start; + Tcl_Size len = tok->tokWord.end - tok->tokWord.start; if (FrmResultAllocate(dateFmt, len) != TCL_OK) { goto error; }; if (len == 1) { *dateFmt->output++ = *tok->tokWord.start; @@ -3306,8 +3304,9 @@ error: done: if (dateFmt->resMem) { - size_t size; - Tcl_Obj * result = Tcl_NewObj(); + size_t size; + Tcl_Obj *result; + TclNewObj(result); result->length = dateFmt->output - dateFmt->resMem; size = result->length+1; if (dateFmt->resMem == resMem) { diff --git a/generic/tclDate.h b/generic/tclDate.h index 911e285..5033018 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -517,7 +517,7 @@ MODULE_SCOPE int ConvertUTCToLocal(void *clientData, Tcl_Interp *, TclDateFields *, Tcl_Obj *timezoneObj, int); MODULE_SCOPE Tcl_Obj * LookupLastTransition(Tcl_Interp *, Tcl_WideInt, - int, Tcl_Obj *const *, Tcl_WideInt *rangesVal); + Tcl_Size, Tcl_Obj *const *, Tcl_WideInt *rangesVal); MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info); -- cgit v0.12 From a4daa7523ff2b9edb4292841a14a2a691183d0b0 Mon Sep 17 00:00:00 2001 From: sebres Date: Mon, 11 Mar 2024 15:14:51 +0000 Subject: load clock-stubs dynamically with namespace unknown (no auto-index needed) --- library/init.tcl | 11 +++++++++++ library/tclIndex | 24 ------------------------ win/Makefile.in | 6 +++--- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/library/init.tcl b/library/init.tcl index 2a2391d..5eb5dfc 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -120,6 +120,17 @@ if {[interp issafe]} { uplevel 1 [info level 0] } + + # Auto-loading stubs for 'clock.tcl' + + namespace eval ::tcl::clock { + proc _load_stubs args { + namespace unknown {} + ::source -encoding utf-8 [::file join [info library] clock.tcl] + tailcall {*}$args + } + namespace unknown ::tcl::clock::_load_stubs + } } # Conditionalize for presence of exec. diff --git a/library/tclIndex b/library/tclIndex index 438aaa7..04f6d41 100644 --- a/library/tclIndex +++ b/library/tclIndex @@ -19,30 +19,6 @@ set auto_index(::auto_mkindex_parser::command) [list ::tcl::Pkg::source [file jo set auto_index(::auto_mkindex_parser::commandInit) [list ::tcl::Pkg::source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::fullname) [list ::tcl::Pkg::source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::indexEntry) [list ::tcl::Pkg::source [file join $dir auto.tcl]] -set auto_index(::tcl::clock::mc) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::Initialize) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::mcget) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::mcMerge) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::GetSystemLocale) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::EnterLocale) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::_hasRegistry) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::LoadWindowsDateTimeFormats) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::LocalizeFormat) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::GetSystemTimeZone) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::SetupTimeZone) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::GuessWindowsTimeZone) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::LoadTimeZoneFile) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::LoadZoneinfoFile) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::ReadZoneinfoFile) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::ParsePosixTimeZone) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::ProcessPosixTimeZone) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::DeterminePosixDSTTime) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::GetJulianDayFromEraYearDay) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::GetJulianDayFromEraYearMonthWeekDay) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::IsGregorianLeapYear) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::WeekdayOnOrBefore) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::ChangeCurrentLocale) [list ::tcl::Pkg::source [file join $dir clock.tcl]] -set auto_index(::tcl::clock::ClearCaches) [list ::tcl::Pkg::source [file join $dir clock.tcl]] set auto_index(foreachLine) [list ::tcl::Pkg::source [file join $dir foreachline.tcl]] set auto_index(::tcl::history) [list ::tcl::Pkg::source [file join $dir history.tcl]] set auto_index(history) [list ::tcl::Pkg::source [file join $dir history.tcl]] diff --git a/win/Makefile.in b/win/Makefile.in index e4f6b8b..960f02f 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -155,9 +155,9 @@ TEST_DLL_FILE = tcltest$(VER)${DLLSUFFIX} TEST_EXE_FILE = tcltest${EXESUFFIX} TEST_LIB_FILE = @LIBPREFIX@tcltest$(VER)${DLLSUFFIX}${LIBSUFFIX} TEST_LOAD_PRMS = lappend ::auto_path {$(ROOT_DIR_WIN_NATIVE)/tests};\ - package ifneeded dde 1.4.5 [list load [file normalize ${DDE_DLL_FILE}]];\ - package ifneeded registry 1.3.7 [list load [file normalize ${REG_DLL_FILE}]] -TEST_LOAD_FACILITIES = package ifneeded tcl::test ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest];\ + package ifneeded dde 1.4.5 [list load ${DDE_DLL_FILE}];\ + package ifneeded registry 1.3.7 [list load ${REG_DLL_FILE}] +TEST_LOAD_FACILITIES = package ifneeded tcl::test ${VERSION}@TCL_PATCH_LEVEL@ [list load ${TEST_DLL_FILE} Tcltest];\ $(TEST_LOAD_PRMS) ZLIB_DLL_FILE = zlib1.dll TOMMATH_DLL_FILE = libtommath.dll -- cgit v0.12 From 5c2ac2ff4878a8ca2dc233d15c52efcb03fff5b4 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:21:47 +0000 Subject: tests to ensure cache of base is correct for :localtime if TZ-env changing --- tests/clock.test | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index 9b9bc52..f4492b6 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -36828,6 +36828,52 @@ test clock-38.2 {make sure TZ is not cached after unset} \ } \ -result 1 +test clock-38.3sc {ensure cache of base is correct for :localtime if TZ-env changing / scan} \ + -setup { + if { [info exists env(TZ)] } { + set oldTZ $env(TZ) + } + } \ + -body { + set res {} + foreach env(TZ) {GMT-11:30 GMT-07:30 GMT-03:30 GMT} \ + i {{07:30:00} {03:30:00} {23:30:00} {20:00:00}} \ + { + lappend res [clock scan $i -format "%H:%M:%S" -base [expr {20*60*60}] -timezone :localtime] + } + set res + } \ + -cleanup { + if { [info exists oldTZ] } { + set env(TZ) $oldTZ + unset oldTZ + } else { + unset env(TZ) + } + } \ + -result [lrepeat 4 [expr {20*60*60}]] +test clock-38.3fm {ensure cache of base is correct for :localtime if TZ-env changing / format} \ + -setup { + if { [info exists env(TZ)] } { + set oldTZ $env(TZ) + } + } \ + -body { + set res {} + foreach env(TZ) {GMT-11:30 GMT-07:30 GMT-03:30 GMT} { + lappend res [clock format [expr {20*60*60}] -format "%Y-%m-%dT%H:%M:%S %Z" -timezone :localtime] + } + set res + } \ + -cleanup { + if { [info exists oldTZ] } { + set env(TZ) $oldTZ + unset oldTZ + } else { + unset env(TZ) + } + } \ + -result {{1970-01-02T07:30:00 +1130} {1970-01-02T03:30:00 +0730} {1970-01-01T23:30:00 +0330} {1970-01-01T20:00:00 +0000}} test clock-39.1 {regression - synonym timezones} { clock format 0 -format {%H:%M:%S} -timezone :US/Eastern -- cgit v0.12 From e1c52c67653d71271cf79b17fc4a30670bc0a1b3 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:33:38 +0000 Subject: consider TZ-epoch in base-cache (ensure cache of base is correct for :localtime if TZ changing) --- generic/tclClock.c | 11 ++++++++++- generic/tclDate.h | 4 ++++ library/clock.tcl | 5 +---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index e156cf3..1c9f77e 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -2249,6 +2249,9 @@ ConvertUTCToLocal( return TCL_ERROR; } + /* signal we need to revalidate TZ epoch next time fields gets used. */ + fields->flags |= CLF_CTZ; + /* we cannot cache (ranges unknown yet) */ } else { Tcl_WideInt rangesVal[2]; @@ -2258,6 +2261,9 @@ ConvertUTCToLocal( return TCL_ERROR; } + /* converted using table (TZ isn't :localtime) */ + fields->flags &= ~CLF_CTZ; + /* Cache the last conversion */ if (ltzoc != NULL) { /* slot was found above */ /* timezoneObj and changeover are the same */ @@ -3491,7 +3497,10 @@ baseNow: /* check base fields already cached (by TZ, last-second cache) */ if ( dataPtr->lastBase.timezoneObj == opts->timezoneObj - && dataPtr->lastBase.date.seconds == baseVal) { + && dataPtr->lastBase.date.seconds == baseVal + && (!(dataPtr->lastBase.date.flags & CLF_CTZ) + || dataPtr->lastTZEpoch == TzsetIfNecessary()) + ) { memcpy(date, &dataPtr->lastBase.date, ClockCacheableDateFieldsSize); } else { /* extact fields from base */ diff --git a/generic/tclDate.h b/generic/tclDate.h index 6e82a3f..0fd0fef 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -150,6 +150,8 @@ typedef enum ClockMsgCtLiteral { typedef enum {BCE=1, CE=0} ERA_ENUM; +#define CLF_CTZ (1 << 4) + typedef struct TclDateFields { /* Cacheable fields: */ @@ -175,6 +177,8 @@ typedef struct TclDateFields { int secondOfMin; /* Seconds of minute (in-between time only calculation) */ int secondOfDay; /* Seconds of day (in-between time only calculation) */ + int flags; /* 0 or CLF_CTZ */ + /* Non cacheable fields: */ Tcl_Obj *tzName; /* Name (or corresponding DST-abbreviation) of the diff --git a/library/clock.tcl b/library/clock.tcl index 529a4f9..504ba0b 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -968,10 +968,7 @@ proc ::tcl::clock::SetupTimeZone { timezone {alias {}} } { "time zone \"$timezone\" not found" } variable MINWIDE - if { $timezone eq {:localtime} } { - # Nothing to do, we'll convert using the localtime function - - } elseif { + if { [regexp {^([-+])(\d\d)(?::?(\d\d)(?::?(\d\d))?)?} $timezone \ -> s hh mm ss] } then { -- cgit v0.12 From 65008fd907b0b91833d29c0c3242355ac7ab272c Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:36:28 +0000 Subject: optimize simplest case if numeric timezone is 0000 (so GMT/UTC) --- generic/tclClock.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 1c9f77e..5872ad1 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -4023,16 +4023,23 @@ ClockFreeScan( */ if (info->flags & CLF_ZONE) { - Tcl_Obj *tzObjStor = NULL; - int minEast = -yyTimezone; - int dstFlag = 1 - yyDSTmode; - tzObjStor = ClockFormatNumericTimeZone( - 60 * minEast + 3600 * dstFlag); - Tcl_IncrRefCount(tzObjStor); - - opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, tzObjStor); - - Tcl_DecrRefCount(tzObjStor); + if (yyTimezone || !yyDSTmode) { + /* Real time zone from numeric zone */ + Tcl_Obj *tzObjStor = NULL; + int minEast = -yyTimezone; + int dstFlag = 1 - yyDSTmode; + tzObjStor = ClockFormatNumericTimeZone( + 60 * minEast + 3600 * dstFlag); + Tcl_IncrRefCount(tzObjStor); + + opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, tzObjStor); + + Tcl_DecrRefCount(tzObjStor); + } else { + /* simplest case - GMT / UTC */ + opts->timezoneObj = ClockSetupTimeZone(dataPtr, interp, + dataPtr->literals[LIT_GMT]); + } if (opts->timezoneObj == NULL) { goto done; } -- cgit v0.12 From ec60f6221811c965c1abeeac81455ced5537ac1e Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:37:39 +0000 Subject: more optimizations of numeric to regular TZ conversion (for non GMT offsets) --- generic/tclClock.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 5872ad1..052184c 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -1375,20 +1375,24 @@ ClockSetupTimeZone( Tcl_Obj * ClockFormatNumericTimeZone(int z) { - char sign = '+'; + char buf[12+1]; int h, m; + + *buf = '+'; if ( z < 0 ) { z = -z; - sign = '-'; + *buf = '-'; } h = z / 3600; z %= 3600; m = z / 60; z %= 60; if (z != 0) { - return Tcl_ObjPrintf("%c%02d%02d%02d", sign, h, m, z); + sprintf(&buf[1], "%02d%02d%02d", h, m, z); + } else { + sprintf(&buf[1], "%02d%02d", h, m); } - return Tcl_ObjPrintf("%c%02d%02d", sign, h, m); + return Tcl_NewStringObj(buf, -1); } /* -- cgit v0.12 From c196cd75cc4308e95b7e629c31970eac858757a9 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:43:03 +0000 Subject: replace sprintf with itoaw --- generic/tclClock.c | 32 +++++++++++++------------------- generic/tclClockFmt.c | 9 +++++++++ generic/tclDate.h | 4 ++++ 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 052184c..571052f 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -1375,24 +1375,20 @@ ClockSetupTimeZone( Tcl_Obj * ClockFormatNumericTimeZone(int z) { - char buf[12+1]; - int h, m; + char buf[12+1], *p; - *buf = '+'; if ( z < 0 ) { z = -z; *buf = '-'; + } else { + *buf = '+'; } - h = z / 3600; - z %= 3600; - m = z / 60; - z %= 60; + TclItoAw(buf+1, z / 3600, '0', 2); z %= 3600; + p = TclItoAw(buf+3, z / 60, '0', 2); z %= 60; if (z != 0) { - sprintf(&buf[1], "%02d%02d%02d", h, m, z); - } else { - sprintf(&buf[1], "%02d%02d", h, m); + p = TclItoAw(buf+5, z, '0', 2); } - return Tcl_NewStringObj(buf, -1); + return Tcl_NewStringObj(buf, p - buf); } /* @@ -2370,7 +2366,7 @@ ConvertUTCToLocalUsingC( time_t tock; struct tm *timeVal; /* Time after conversion */ int diff; /* Time zone diff local-Greenwich */ - char buffer[16]; /* Buffer for time zone name */ + char buffer[16], *p; /* Buffer for time zone name */ /* * Use 'localtime' to determine local year, month, day, time of day. @@ -2423,14 +2419,12 @@ ConvertUTCToLocalUsingC( } else { *buffer = '+'; } - snprintf(buffer+1, sizeof(buffer) - 1, "%02d", diff / 3600); - diff %= 3600; - snprintf(buffer+3, sizeof(buffer) - 3, "%02d", diff / 60); - diff %= 60; - if (diff > 0) { - snprintf(buffer+5, sizeof(buffer) - 5, "%02d", diff); + TclItoAw(buffer+1, diff / 3600, '0', 2); diff %= 3600; + p = TclItoAw(buffer+3, diff / 60, '0', 2); diff %= 60; + if (diff != 0) { + p = TclItoAw(buffer+5, diff, '0', 2); } - Tcl_SetObjRef(fields->tzName, Tcl_NewStringObj(buffer, -1)); + Tcl_SetObjRef(fields->tzName, Tcl_NewStringObj(buffer, p - buffer)); return TCL_OK; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index a25be83..811996f 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -197,6 +197,15 @@ _itoaw( return buf + width; } +char * +TclItoAw( + char *buf, + int val, + char padchar, + unsigned short int width) +{ + return _itoaw(buf, val, padchar, width); +} static inline char * _witoaw( diff --git a/generic/tclDate.h b/generic/tclDate.h index 0fd0fef..465473f 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -544,6 +544,10 @@ MODULE_SCOPE int ClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey, /* tclClockFmt.c module declarations */ + +MODULE_SCOPE char * + TclItoAw(char *buf, int val, char padchar, unsigned short int width); + MODULE_SCOPE Tcl_Obj* ClockFrmObjGetLocFmtKey(Tcl_Interp *interp, Tcl_Obj *objPtr); -- cgit v0.12 From 8934efeefe580d76ce4016bf996e1512a009c136 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:43:30 +0000 Subject: test cases covering #23: `clock add` regression (due to integer overflow) --- tests/clock.test | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index f4492b6..7c1f756 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -35753,6 +35753,26 @@ test clock-30.30 {clock add weekdays and back} -body { } return "OK" } -result {OK} +test clock-30.31 {regression test - add with int overflow} { + list \ + [list \ + [clock add 0 1600000000 seconds 24856 days -gmt 1] \ + [clock add 0 1600000000 seconds 815 months -gmt 1] \ + [clock add 0 1600000000 seconds 69 years -gmt 1] \ + [clock add 0 1600000000 seconds 596524 hours -gmt 1] \ + [clock add 0 1600000000 seconds 35791395 minutes -gmt 1] \ + [clock add 0 1600000000 seconds 0x7fffffff seconds -gmt 1] + ] \ + [list \ + [clock add 1600000000 24856 days -gmt 1] \ + [clock add 1600000000 815 months -gmt 1] \ + [clock add 1600000000 69 years -gmt 1] \ + [clock add 1600000000 596524 hours -gmt 1] \ + [clock add 1600000000 35791395 minutes -gmt 1] \ + [clock add 1600000000 0x7fffffff seconds -gmt 1] + ] +} [lrepeat 2 {3747558400 3743238400 3777452800 3747486400 3747483700 3747483647}] + # END testcases30 -- cgit v0.12 From c177806ce6f30bb0668d018076625d8acdfb105c Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:48:02 +0000 Subject: fixes #23: `clock add` regression (integer overflow in time part) --- generic/tclClock.c | 15 +++++++++------ generic/tclDate.h | 12 ++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 571052f..76f14da 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -4189,7 +4189,7 @@ repeat_rel: /* relative time (seconds), if exceeds current date, do the day conversion and * leave rest of the increment in yyRelSeconds to add it hereafter in UTC seconds */ if (yyRelSeconds) { - int newSecs = yySecondOfDay + yyRelSeconds; + Tcl_WideInt newSecs = yySecondOfDay + yyRelSeconds; /* if seconds increment outside of current date, increment day */ if (newSecs / SECONDS_PER_DAY != yySecondOfDay / SECONDS_PER_DAY) { @@ -4434,19 +4434,22 @@ ClockAddObjCmd( */ for (i = 2; i < objc; i+=2) { - /* bypass not integers (options, allready processed above) */ + /* bypass not integers (options, allready processed above in ClockParseFmtScnArgs) */ if (TclGetWideIntFromObj(NULL, objv[i], &offs) != TCL_OK) { continue; } - if (objv[i]->typePtr == &tclBignumType) { - Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]); - goto done; - } /* get unit */ if (Tcl_GetIndexFromObj(interp, objv[i+1], units, "unit", 0, &unitIndex) != TCL_OK) { goto done; } + if (objv[i]->typePtr == &tclBignumType + || offs > (unitIndex < CLC_ADD_HOURS ? 0x7fffffff : TCL_MAX_SECONDS) + || offs < (unitIndex < CLC_ADD_HOURS ? -0x7fffffff : TCL_MIN_SECONDS) + ) { + Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]); + goto done; + } /* nothing to do if zero quantity */ if (!offs) { diff --git a/generic/tclDate.h b/generic/tclDate.h index 465473f..10e6473 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -174,8 +174,8 @@ typedef struct TclDateFields { int dayOfWeek; /* Day of the week */ int hour; /* Hours of day (in-between time only calculation) */ int minutes; /* Minutes of hour (in-between time only calculation) */ - int secondOfMin; /* Seconds of minute (in-between time only calculation) */ - int secondOfDay; /* Seconds of day (in-between time only calculation) */ + Tcl_WideInt secondOfMin; /* Seconds of minute (in-between time only calculation) */ + Tcl_WideInt secondOfDay; /* Seconds of day (in-between time only calculation) */ int flags; /* 0 or CLF_CTZ */ @@ -215,16 +215,16 @@ typedef struct DateInfo { int dateTimezone; int dateDSTmode; - int dateRelMonth; - int dateRelDay; - int dateRelSeconds; + Tcl_WideInt dateRelMonth; + Tcl_WideInt dateRelDay; + Tcl_WideInt dateRelSeconds; int dateMonthOrdinalIncr; int dateMonthOrdinal; int dateDayOrdinal; - int *dateRelPointer; + Tcl_WideInt *dateRelPointer; int dateSpaceCount; int dateDigitCount; -- cgit v0.12 From 12d0aca68174c5033bd3ed6292b18534addf5848 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 01:50:32 +0000 Subject: fixes similar issue by free scan + more tests --- generic/tclDate.c | 4 ++-- generic/tclGetDate.y | 4 ++-- tests/clock.test | 44 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index fa4cf4f..7d6ddac 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -138,7 +138,7 @@ typedef struct _TABLE { const char *name; int type; - long value; + Tcl_WideInt value; } TABLE; /* @@ -223,7 +223,7 @@ extern int TclDatedebug; union YYSTYPE { - long Number; + Tcl_WideInt Number; enum _MERIDIAN Meridian; diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 25802d8..b5f2efb 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -89,7 +89,7 @@ typedef struct _TABLE { const char *name; int type; - long value; + Tcl_WideInt value; } TABLE; /* @@ -103,7 +103,7 @@ typedef enum _DSTMODE { %} %union { - long Number; + Tcl_WideInt Number; enum _MERIDIAN Meridian; } diff --git a/tests/clock.test b/tests/clock.test index 7c1f756..65d3ce9 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -35753,7 +35753,7 @@ test clock-30.30 {clock add weekdays and back} -body { } return "OK" } -result {OK} -test clock-30.31 {regression test - add with int overflow} { +test clock-30.31 {regression test - add no int overflow} { list \ [list \ [clock add 0 1600000000 seconds 24856 days -gmt 1] \ @@ -35772,7 +35772,25 @@ test clock-30.31 {regression test - add with int overflow} { [clock add 1600000000 0x7fffffff seconds -gmt 1] ] } [lrepeat 2 {3747558400 3743238400 3777452800 3747486400 3747483700 3747483647}] - +test clock-30.32 {regression test - add no int overflow} { + list \ + [list \ + [clock add 3777452800 -1600000000 seconds -24856 days -gmt 1] \ + [clock add 3777452800 -1600000000 seconds -815 months -gmt 1] \ + [clock add 3777452800 -1600000000 seconds -69 years -gmt 1] \ + [clock add 3777452800 -1600000000 seconds -596524 hours -gmt 1] \ + [clock add 3777452800 -1600000000 seconds -35791395 minutes -gmt 1] \ + [clock add 3777452800 -1600000000 seconds -0x7fffffff seconds -gmt 1] + ] \ + [list \ + [clock add 2177452800 -24856 days -gmt 1] \ + [clock add 2177452800 -815 months -gmt 1] \ + [clock add 2177452800 -69 years -gmt 1] \ + [clock add 2177452800 -596524 hours -gmt 1] \ + [clock add 2177452800 -35791395 minutes -gmt 1] \ + [clock add 2177452800 -0x7fffffff seconds -gmt 1] + ] +} [lrepeat 2 {29894400 34214400 0 29966400 29969100 29969153}] # END testcases30 @@ -37012,6 +37030,28 @@ test clock-45.4 {compat: scan regression on spaces (mandatory leading/trailing s [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-45.5 {regression test - freescan no int overflow} { + # note that the relative date changes currently reset the time to 00:00, + # this can be changed later (simply achievable by adding 00:00 if expected): + list \ + [clock scan "+24856 days" -base 1600000000 -gmt 1] \ + [clock scan "+815 months" -base 1600000000 -gmt 1] \ + [clock scan "+69 years" -base 1600000000 -gmt 1] \ + [clock scan "+596524 hours" -base 1600000000 -gmt 1] \ + [clock scan "+35791395 minutes" -base 1600000000 -gmt 1] \ + [clock scan "+2147483647 seconds" -base 1600000000 -gmt 1] +} {3747513600 3743193600 3777408000 3747486400 3747483700 3747483647} +test clock-45.6 {regression test - freescan no int overflow} { + # note that the relative date changes currently reset the time to 00:00, + # this can be changed later (simply achievable by adding 00:00 if expected): + list \ + [clock scan "-24856 days" -base 2177452800 -gmt 1] \ + [clock scan "-815 months" -base 2177452800 -gmt 1] \ + [clock scan "-69 years" -base 2177452800 -gmt 1] \ + [clock scan "-596524 hours" -base 2177452800 -gmt 1] \ + [clock scan "-35791395 minutes" -base 2177452800 -gmt 1] \ + [clock scan "-2147483647 seconds" -base 2177452800 -gmt 1] +} {29894400 34214400 0 29966400 29969100 29969153} test clock-46.1 {regression test - month zero} -constraints valid_off \ -body { -- cgit v0.12 From 1ffa0ed63b45b8a081ef7454588c69025379bcac Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 21:39:39 +0000 Subject: small amend (forgotten TclListObjGetElementsM -> TclListObjGetElements) --- generic/tclClock.c | 2 +- generic/tclClockFmt.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 9b3e60e..1ba93b5 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -2164,7 +2164,7 @@ ConvertUTCToLocal( if (dataPtr->gmtTZName == NULL) { Tcl_Obj *tzName; tzdata = ClockGetTZData(clientData, interp, timezoneObj); - if ( TclListObjGetElementsM(interp, tzdata, &rowc, &rowv) != TCL_OK + if ( TclListObjGetElements(interp, tzdata, &rowc, &rowv) != TCL_OK || Tcl_ListObjIndex(interp, rowv[0], 3, &tzName) != TCL_OK) { return TCL_ERROR; } diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index e46043a..c216d34 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -1122,7 +1122,7 @@ LocaleListSearch(ClockFmtScnCmdArgs *opts, } /* is a list */ - if (TclListObjGetElementsM(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { + if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { return TCL_ERROR; } @@ -1181,7 +1181,7 @@ ClockMCGetListIdxTree( goto done; } - if (TclListObjGetElementsM(opts->interp, valObj, + if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { goto done; }; @@ -1256,7 +1256,7 @@ ClockMCGetMultiListIdxTree( goto done; } - if (TclListObjGetElementsM(opts->interp, valObj, + if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) { goto done; }; @@ -2825,7 +2825,7 @@ ClockFmtToken_LocaleERAYear_Proc( if (mcObj == NULL) { return TCL_ERROR; } - if (TclListObjGetElementsM(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) { + if (TclListObjGetElements(opts->interp, mcObj, &rowc, &rowv) != TCL_OK) { return TCL_ERROR; } if (rowc != 0) { -- cgit v0.12 From f0f32689200939a6ce2d36e0a389687c959eac15 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 12 Mar 2024 21:44:21 +0000 Subject: fixes [1acd172c424b57c9]: restored ensemble compilation, fixed TCL_ENSEMBLE_PREFIX (restores default), fixed compiled INST_INVOKE_REPLACE for ensembles by CMD_COMPILE_TO_INVOKED flag --- generic/tclClock.c | 48 ++++++++++++++++++++++++++++++++---------------- generic/tclEnsemble.c | 48 ++++++++++++++++++++++++++++++++---------------- generic/tclInt.h | 3 +++ 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 1ba93b5..b7ca81c 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -133,28 +133,43 @@ struct ClockCommand { * will always have the ClockClientData sent * to it, but may well ignore this data. */ CompileProc *compileProc; /* The compiler for the command. */ - void *clientData; /* Any clientData to give the command (if NULL + void *clientData; /* Any clientData to give the command (if NULL * a reference to ClockClientData will be sent) */ + int compFlags; /* Command compile flags */ }; 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}, - {"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3)}, - {"configure", ClockConfigureObjCmd, NULL, NULL}, - {"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL}, - {"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL}, + {"add", ClockAddObjCmd, TclCompileBasicMin1ArgCmd, NULL, + CMD_COMPILE_TO_INVOKED}, + {"clicks", ClockClicksObjCmd, TclCompileClockClicksCmd, NULL, + 0}, + {"format", ClockFormatObjCmd, TclCompileBasicMin1ArgCmd, NULL, + CMD_COMPILE_TO_INVOKED}, + {"getenv", ClockGetenvObjCmd, TclCompileBasicMin1ArgCmd, NULL, + 0}, + {"microseconds", ClockMicrosecondsObjCmd,TclCompileClockReadingCmd,INT2PTR(1), + 0}, + {"milliseconds", ClockMillisecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(2), + 0}, + {"scan", ClockScanObjCmd, TclCompileBasicMin1ArgCmd, NULL, + CMD_COMPILE_TO_INVOKED}, + {"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3), + 0}, + {"configure", ClockConfigureObjCmd, NULL, NULL, + CMD_COMPILE_TO_INVOKED}, + {"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL, + 0}, + {"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL, + 0}, {"GetJulianDayFromEraYearMonthDay", - ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL}, + ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL, + 0}, {"GetJulianDayFromEraYearWeekDay", - ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL}, - {"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL}, - {NULL, NULL, NULL, NULL} + ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL, + 0}, + {"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL, + 0}, + {NULL, NULL, NULL, NULL, 0} }; /* @@ -266,6 +281,7 @@ TclClockInit( clockCmdPtr->clientData ? NULL : ClockDeleteCmdProc); cmdPtr->compileProc = clockCmdPtr->compileProc ? clockCmdPtr->compileProc : TclCompileBasicMin0ArgCmd; + cmdPtr->flags |= clockCmdPtr->compFlags; } } diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index ad6ced3..2ae966f 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -196,7 +196,7 @@ TclNamespaceEnsembleCmd( */ Tcl_Obj *subcmdObj = NULL; Tcl_Obj *mapObj = NULL; - int permitPrefix = 1; + int ensFlags = TCL_ENSEMBLE_PREFIX; Tcl_Obj *unknownObj = NULL; Tcl_Obj *paramObj = NULL; @@ -330,7 +330,8 @@ TclNamespaceEnsembleCmd( } continue; } - case CRT_PREFIX: + case CRT_PREFIX: { + int permitPrefix; if (Tcl_GetBooleanFromObj(interp, objv[1], &permitPrefix) != TCL_OK) { if (allocatedMapFlag) { @@ -338,7 +339,10 @@ TclNamespaceEnsembleCmd( } return TCL_ERROR; } + ensFlags &= ~TCL_ENSEMBLE_PREFIX; + ensFlags |= permitPrefix ? TCL_ENSEMBLE_PREFIX : 0; continue; + } case CRT_UNKNOWN: if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { if (allocatedMapFlag) { @@ -356,6 +360,15 @@ TclNamespaceEnsembleCmd( &actualCxtPtr, &simpleName); /* + * Ensemble should be compiled if it has map (performance purposes) + * Currently only for internal using namespace (like ::tcl::clock). + * (An enhancement for completelly compile-feature is in work.) + */ + if (mapObj != NULL && strncmp("::tcl::", nsPtr->fullName, 7) == 0) { + ensFlags |= ENSEMBLE_COMPILE; + } + + /* * Create the ensemble. Note that this might delete another ensemble * linked to the same namespace, so we must be careful. However, we * should be OK because we only link the namespace into the list once @@ -364,7 +377,7 @@ TclNamespaceEnsembleCmd( token = TclCreateEnsembleInNs(interp, simpleName, (Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, - (permitPrefix ? TCL_ENSEMBLE_PREFIX : 0)); + ensFlags); Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj); Tcl_SetEnsembleMappingDict(interp, token, mapObj); Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); @@ -2934,14 +2947,14 @@ TclCompileEnsemble( TclNewObj(replaced); Tcl_IncrRefCount(replaced); if (parsePtr->numWords <= depth) { - goto failed; + goto tryCompileToInv; } if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { /* * Too hard. */ - goto failed; + goto tryCompileToInv; } /* @@ -2966,7 +2979,7 @@ TclCompileEnsemble( * to proceed. */ - goto failed; + goto tryCompileToInv; } /* @@ -2980,7 +2993,7 @@ TclCompileEnsemble( * Figuring out how to compile this has become too much. Bail out. */ - goto failed; + goto tryCompileToInv; } /* @@ -3003,7 +3016,7 @@ TclCompileEnsemble( Tcl_Obj *matchObj = NULL; if (TclListObjGetElements(NULL, listObj, &len, &elems) != TCL_OK) { - goto failed; + goto tryCompileToInv; } for (i=0 ; iflags & CMD_COMPILE_TO_INVOKED) { + goto tryCompileToInv; + } /* * See whether we have a nested ensemble. If we do, we can go round the * mulberry bush again, consuming the next word. @@ -3211,7 +3227,7 @@ TclCompileEnsemble( * instead of going through the ensemble lookup process again. */ - failed: + tryCompileToInv: if (depth < 250) { if (depth > 1) { if (!invokeAnyway) { diff --git a/generic/tclInt.h b/generic/tclInt.h index d3e8989..d218a20 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1850,6 +1850,8 @@ typedef struct Command { * CMD_COMPILES_EXPANDED - If 1 this command has a compiler that * can handle expansion (provided it is not the * first word). + * CMD_COMPILE_TO_INVOKED - If 1 this command prefers a compilation with + * INST_INVOKE_REPLACE (in ensemble only). * TCL_TRACE_RENAME - A rename trace is in progress. Further * recursive renames will not be traced. * TCL_TRACE_DELETE - A delete trace is in progress. Further @@ -1864,6 +1866,7 @@ typedef struct Command { #define CMD_REDEF_IN_PROGRESS 0x10 #define CMD_VIA_RESOLVER 0x20 #define CMD_DEAD 0x40 +#define CMD_COMPILE_TO_INVOKED 0x80 /* -- cgit v0.12 From 4651b01f6aa0e2baea54fd0a3b7a59afac7aaf0a Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2024 00:01:26 +0000 Subject: partially revert f665afd65ee7a5f9 (INST_INVOKE_REPLACE/CMD_COMPILE_TO_INVOKED), ensemble compiled in configure -init-complete (only for clock) --- generic/tclClock.c | 95 +++++++++++++++++++++++++++------------------------ generic/tclEnsemble.c | 48 +++++++++----------------- generic/tclInt.h | 3 -- library/init.tcl | 21 ++++++------ 4 files changed, 78 insertions(+), 89 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index b7ca81c..cc990a6 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -133,43 +133,28 @@ struct ClockCommand { * will always have the ClockClientData sent * to it, but may well ignore this data. */ CompileProc *compileProc; /* The compiler for the command. */ - void *clientData; /* Any clientData to give the command (if NULL + void *clientData; /* Any clientData to give the command (if NULL * a reference to ClockClientData will be sent) */ - int compFlags; /* Command compile flags */ }; static const struct ClockCommand clockCommands[] = { - {"add", ClockAddObjCmd, TclCompileBasicMin1ArgCmd, NULL, - CMD_COMPILE_TO_INVOKED}, - {"clicks", ClockClicksObjCmd, TclCompileClockClicksCmd, NULL, - 0}, - {"format", ClockFormatObjCmd, TclCompileBasicMin1ArgCmd, NULL, - CMD_COMPILE_TO_INVOKED}, - {"getenv", ClockGetenvObjCmd, TclCompileBasicMin1ArgCmd, NULL, - 0}, - {"microseconds", ClockMicrosecondsObjCmd,TclCompileClockReadingCmd,INT2PTR(1), - 0}, - {"milliseconds", ClockMillisecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(2), - 0}, - {"scan", ClockScanObjCmd, TclCompileBasicMin1ArgCmd, NULL, - CMD_COMPILE_TO_INVOKED}, - {"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3), - 0}, - {"configure", ClockConfigureObjCmd, NULL, NULL, - CMD_COMPILE_TO_INVOKED}, - {"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL, - 0}, - {"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL, - 0}, + {"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}, + {"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3)}, + {"configure", ClockConfigureObjCmd, NULL, NULL}, + {"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL}, + {"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL}, {"GetJulianDayFromEraYearMonthDay", - ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL, - 0}, + ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL}, {"GetJulianDayFromEraYearWeekDay", - ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL, - 0}, - {"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL, - 0}, - {NULL, NULL, NULL, NULL, 0} + ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL}, + {"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL}, + {NULL, NULL, NULL, NULL} }; /* @@ -281,7 +266,6 @@ TclClockInit( clockCmdPtr->clientData ? NULL : ClockDeleteCmdProc); cmdPtr->compileProc = clockCmdPtr->compileProc ? clockCmdPtr->compileProc : TclCompileBasicMin0ArgCmd; - cmdPtr->flags |= clockCmdPtr->compFlags; } } @@ -983,13 +967,15 @@ ClockConfigureObjCmd( "-clear", "-year-century", "-century-switch", "-min-year", "-max-year", "-max-jdn", "-validate", + "-init-complete", 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_MAX_JDN, CLOCK_VALIDATE + CLOCK_MIN_YEAR, CLOCK_MAX_YEAR, CLOCK_MAX_JDN, CLOCK_VALIDATE, + CLOCK_INIT_COMPLETE }; int optionIndex; /* Index of an option. */ int i; @@ -1153,6 +1139,27 @@ ClockConfigureObjCmd( case CLOCK_CLEAR_CACHE: ClockConfigureClear(dataPtr); break; + case CLOCK_INIT_COMPLETE: + { + /* + * Init completed. + * Compile clock ensemble (performance purposes). + */ + Tcl_Command token = Tcl_FindCommand(interp, "::clock", + NULL, TCL_GLOBAL_ONLY); + if (!token) { + return TCL_ERROR; + } + int ensFlags = 0; + if (Tcl_GetEnsembleFlags(interp, token, &ensFlags) != TCL_OK) { + return TCL_ERROR; + } + ensFlags |= ENSEMBLE_COMPILE; + if (Tcl_SetEnsembleFlags(interp, token, ensFlags) != TCL_OK) { + return TCL_ERROR; + } + } + break; } } @@ -3157,7 +3164,7 @@ ClockClicksObjCmd( } break; default: - Tcl_WrongNumArgs(interp, 1, objv, "?-switch?"); + Tcl_WrongNumArgs(interp, 0, objv, "clock clicks ?-switch?"); return TCL_ERROR; } @@ -3211,7 +3218,7 @@ ClockMillisecondsObjCmd( Tcl_Obj *timeObj; if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, objv, "clock milliseconds"); return TCL_ERROR; } Tcl_GetTime(&now); @@ -3247,7 +3254,7 @@ ClockMicrosecondsObjCmd( Tcl_Obj *const *objv) /* Parameter values */ { if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, objv, "clock microseconds"); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetMicroseconds())); @@ -3545,7 +3552,7 @@ ClockFormatObjCmd( { ClockClientData *dataPtr = (ClockClientData *)clientData; - static const char *syntax = "clockval|-now " + static const char *syntax = "clock format clockval|-now " "?-format string? " "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"; @@ -3555,7 +3562,7 @@ ClockFormatObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, syntax); + Tcl_WrongNumArgs(interp, 0, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -3620,7 +3627,7 @@ ClockScanObjCmd( int objc, /* Parameter count */ Tcl_Obj *const objv[]) /* Parameter values */ { - static const char *syntax = "string " + static const char *syntax = "clock scan string " "?-base seconds? " "?-format string? " "?-gmt boolean? " @@ -3632,7 +3639,7 @@ ClockScanObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, syntax); + Tcl_WrongNumArgs(interp, 0, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -4365,7 +4372,7 @@ ClockAddObjCmd( int objc, /* Parameter count */ Tcl_Obj *const objv[]) /* Parameter values */ { - static const char *syntax = "clockval|-now ?number units?..." + static const char *syntax = "clock add clockval|-now ?number units?..." "?-gmt boolean? " "?-locale LOCALE? ?-timezone ZONE?"; ClockClientData *dataPtr = (ClockClientData *)clientData; @@ -4392,7 +4399,7 @@ ClockAddObjCmd( /* even number of arguments */ if ((objc & 1) == 1) { - Tcl_WrongNumArgs(interp, 1, objv, syntax); + Tcl_WrongNumArgs(interp, 0, objv, syntax); Tcl_SetErrorCode(interp, "CLOCK", "wrongNumArgs", (char *)NULL); return TCL_ERROR; } @@ -4405,7 +4412,7 @@ ClockAddObjCmd( ClockInitFmtScnArgs(clientData, interp, &opts); ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv, - CLC_ADD_ARGS, syntax); + CLC_ADD_ARGS, "-gmt, -locale, or -timezone"); if (ret != TCL_OK) { goto done; } @@ -4551,7 +4558,7 @@ ClockSecondsObjCmd( Tcl_Obj *timeObj; if (objc != 1) { - Tcl_WrongNumArgs(interp, 1, objv, NULL); + Tcl_WrongNumArgs(interp, 0, objv, "clock seconds"); return TCL_ERROR; } Tcl_GetTime(&now); diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 2ae966f..ad6ced3 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -196,7 +196,7 @@ TclNamespaceEnsembleCmd( */ Tcl_Obj *subcmdObj = NULL; Tcl_Obj *mapObj = NULL; - int ensFlags = TCL_ENSEMBLE_PREFIX; + int permitPrefix = 1; Tcl_Obj *unknownObj = NULL; Tcl_Obj *paramObj = NULL; @@ -330,8 +330,7 @@ TclNamespaceEnsembleCmd( } continue; } - case CRT_PREFIX: { - int permitPrefix; + case CRT_PREFIX: if (Tcl_GetBooleanFromObj(interp, objv[1], &permitPrefix) != TCL_OK) { if (allocatedMapFlag) { @@ -339,10 +338,7 @@ TclNamespaceEnsembleCmd( } return TCL_ERROR; } - ensFlags &= ~TCL_ENSEMBLE_PREFIX; - ensFlags |= permitPrefix ? TCL_ENSEMBLE_PREFIX : 0; continue; - } case CRT_UNKNOWN: if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { if (allocatedMapFlag) { @@ -360,15 +356,6 @@ TclNamespaceEnsembleCmd( &actualCxtPtr, &simpleName); /* - * Ensemble should be compiled if it has map (performance purposes) - * Currently only for internal using namespace (like ::tcl::clock). - * (An enhancement for completelly compile-feature is in work.) - */ - if (mapObj != NULL && strncmp("::tcl::", nsPtr->fullName, 7) == 0) { - ensFlags |= ENSEMBLE_COMPILE; - } - - /* * Create the ensemble. Note that this might delete another ensemble * linked to the same namespace, so we must be careful. However, we * should be OK because we only link the namespace into the list once @@ -377,7 +364,7 @@ TclNamespaceEnsembleCmd( token = TclCreateEnsembleInNs(interp, simpleName, (Tcl_Namespace *) foundNsPtr, (Tcl_Namespace *) nsPtr, - ensFlags); + (permitPrefix ? TCL_ENSEMBLE_PREFIX : 0)); Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj); Tcl_SetEnsembleMappingDict(interp, token, mapObj); Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); @@ -2947,14 +2934,14 @@ TclCompileEnsemble( TclNewObj(replaced); Tcl_IncrRefCount(replaced); if (parsePtr->numWords <= depth) { - goto tryCompileToInv; + goto failed; } if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { /* * Too hard. */ - goto tryCompileToInv; + goto failed; } /* @@ -2979,7 +2966,7 @@ TclCompileEnsemble( * to proceed. */ - goto tryCompileToInv; + goto failed; } /* @@ -2993,7 +2980,7 @@ TclCompileEnsemble( * Figuring out how to compile this has become too much. Bail out. */ - goto tryCompileToInv; + goto failed; } /* @@ -3016,7 +3003,7 @@ TclCompileEnsemble( Tcl_Obj *matchObj = NULL; if (TclListObjGetElements(NULL, listObj, &len, &elems) != TCL_OK) { - goto tryCompileToInv; + goto failed; } for (i=0 ; iflags & CMD_COMPILE_TO_INVOKED) { - goto tryCompileToInv; - } /* * See whether we have a nested ensemble. If we do, we can go round the * mulberry bush again, consuming the next word. @@ -3227,7 +3211,7 @@ TclCompileEnsemble( * instead of going through the ensemble lookup process again. */ - tryCompileToInv: + failed: if (depth < 250) { if (depth > 1) { if (!invokeAnyway) { diff --git a/generic/tclInt.h b/generic/tclInt.h index d218a20..d3e8989 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -1850,8 +1850,6 @@ typedef struct Command { * CMD_COMPILES_EXPANDED - If 1 this command has a compiler that * can handle expansion (provided it is not the * first word). - * CMD_COMPILE_TO_INVOKED - If 1 this command prefers a compilation with - * INST_INVOKE_REPLACE (in ensemble only). * TCL_TRACE_RENAME - A rename trace is in progress. Further * recursive renames will not be traced. * TCL_TRACE_DELETE - A delete trace is in progress. Further @@ -1866,7 +1864,6 @@ typedef struct Command { #define CMD_REDEF_IN_PROGRESS 0x10 #define CMD_VIA_RESOLVER 0x20 #define CMD_DEAD 0x40 -#define CMD_COMPILE_TO_INVOKED 0x80 /* diff --git a/library/init.tcl b/library/init.tcl index 5eb5dfc..9306986 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -117,19 +117,20 @@ if {[interp issafe]} { namespace inscope ::tcl::clock [list namespace ensemble create -command \ [uplevel 1 [list ::namespace origin [::lindex [info level 0] 0]]] \ -map $cmdmap] + ::tcl::clock::configure -init-complete - uplevel 1 [info level 0] - } - - # Auto-loading stubs for 'clock.tcl' + # Auto-loading stubs for 'clock.tcl' - namespace eval ::tcl::clock { - proc _load_stubs args { - namespace unknown {} - ::source -encoding utf-8 [::file join [info library] clock.tcl] - tailcall {*}$args + namespace inscope ::tcl::clock { + proc _load_stubs args { + namespace unknown {} + ::source -encoding utf-8 [::file join [info library] clock.tcl] + tailcall {*}$args + } + namespace unknown ::tcl::clock::_load_stubs } - namespace unknown ::tcl::clock::_load_stubs + + uplevel 1 [info level 0] } } -- cgit v0.12 From 325b6e8027f0844453bb33576eb003cb3c9a313f Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 13 Mar 2024 01:03:10 +0000 Subject: compat regression test: original clock ensemble supports prefixes --- tests/clock.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/clock.test b/tests/clock.test index 3cfba06..d283e16 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -348,6 +348,10 @@ test clock-1.7 "clock format - option abbreviations" { clock format 0 -g true -f "%Y-%m-%d" } 1970-01-01 +test clock-1.7.1 "clock format - command abbreviations (compat regression test)" { + clock f 0 -g 1 -f "%Y-%m-%d" +} 1970-01-01 + test clock-1.8 "clock format -now" { # give one second more for test (if on boundary of the current second): set n [clock format [clock seconds] -g 1 -f "%s"] -- cgit v0.12