From 58f947e48be58a2371a0d24f957244796306d2ba Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 10 Jan 2017 21:58:33 +0000 Subject: [temp-commit]: clock scan with several optimization porting, still not-ready --- generic/tclClock.c | 520 +++++++++++++++++++++++++++++++++++++++++++++++---- generic/tclDate.c | 497 +++++++++++++++++++++++------------------------- generic/tclDate.h | 77 ++++++++ generic/tclGetDate.y | 134 ++++++------- library/clock.tcl | 19 +- library/init.tcl | 2 +- win/makefile.vc | 4 +- 7 files changed, 870 insertions(+), 383 deletions(-) create mode 100644 generic/tclDate.h diff --git a/generic/tclClock.c b/generic/tclClock.c index e9a59f3..24ed095 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -14,6 +14,7 @@ */ #include "tclInt.h" +#include "tclDate.h" /* * Windows has mktime. The configurators do not check. @@ -28,6 +29,7 @@ */ #define JULIAN_DAY_POSIX_EPOCH 2440588 +#define GREGORIAN_CHANGE_DATE 2361222 #define SECONDS_PER_DAY 86400 #define JULIAN_SEC_POSIX_EPOCH (((Tcl_WideInt) JULIAN_DAY_POSIX_EPOCH) \ * SECONDS_PER_DAY) @@ -69,7 +71,14 @@ typedef enum ClockLiteral { LIT_MONTH, LIT_SECONDS, LIT_TZNAME, LIT_TZOFFSET, LIT_YEAR, + LIT_CURRENTYEARCENTURY, + LIT_YEAROFCENTURYSWITCH, + LIT_TZDATA, + LIT_GETSYSTEMTIMEZONE, + LIT_SETUPTIMEZONE, +#if 0 LIT_FREESCAN, +#endif LIT__END } ClockLiteral; static const char *const literals[] = { @@ -86,9 +95,18 @@ static const char *const literals[] = { "month", "seconds", "tzName", "tzOffset", "year", + "::tcl::clock::CurrentYearCentury", + "::tcl::clock::YearOfCenturySwitch", + "::tcl::clock::TZData", + "::tcl::clock::GetSystemTimeZone", + "::tcl::clock::SetupTimeZone", +#if 0 "::tcl::clock::FreeScan" +#endif }; +#define CurrentYearCentury 2000 + /* * Structure containing the client data for [clock] */ @@ -168,6 +186,10 @@ static int ClockClicksObjCmd( static int ClockConvertlocaltoutcObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); + +static int ClockGetDateFields(Tcl_Interp *interp, + TclDateFields *fields, Tcl_Obj *tzdata, + int changeover); static int ClockGetdatefieldsObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -195,6 +217,10 @@ static int ClockSecondsObjCmd( static int ClockScanObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +static int ClockFreeScan( + ClientData clientData, Tcl_Interp *interp, + Tcl_Obj *strObj, Tcl_WideInt baseVal, + Tcl_Obj *timezoneObj, Tcl_Obj *locale); static struct tm * ThreadSafeLocalTime(const time_t *); static void TzsetIfNecessary(void); static void ClockDeleteCmdProc(ClientData); @@ -296,6 +322,123 @@ TclClockInit( /* *---------------------------------------------------------------------- + */ +inline Tcl_Obj* +ClockGetTZData( + ClientData clientData, /* Opaque pointer to literal pool, etc. */ + Tcl_Interp *interp, /* Tcl interpreter */ + Tcl_Obj *timezoneObj) /* Name of the timezone */ +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + + return Tcl_ObjGetVar2(interp, literals[LIT_TZDATA], + timezoneObj, TCL_LEAVE_ERR_MSG); +} +/* + *---------------------------------------------------------------------- + */ +static Tcl_Obj * +ClockGetSystemTimeZone( + ClientData clientData, /* Opaque pointer to literal pool, etc. */ + Tcl_Interp *interp) /* Tcl interpreter */ +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + + if (Tcl_EvalObjv(interp, 1, &literals[LIT_GETSYSTEMTIMEZONE], 0) != TCL_OK) { + return NULL; + } + return Tcl_GetObjResult(interp); +} +/* + *---------------------------------------------------------------------- + */ +static int +ClockSetupTimeZone( + ClientData clientData, /* Opaque pointer to literal pool, etc. */ + Tcl_Interp *interp, /* Tcl interpreter */ + Tcl_Obj *timezoneObj) +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + Tcl_Obj *callargs[2]; + + callargs[0] = literals[LIT_SETUPTIMEZONE]; + callargs[1] = timezoneObj; + return Tcl_EvalObjv(interp, 2, callargs, 0); +} +/* + *---------------------------------------------------------------------- + * ClockFormatNumericTimeZone - + * + * Formats a time zone as +hhmmss + * + * Parameters: + * z - Time zone in seconds east of Greenwich + * + * Results: + * Returns the time zone object (formatted in a numeric form) + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +ClockFormatNumericTimeZone(int z) { + char sign = '+'; + int h, m; + if ( z < 0 ) { + z = -z; + sign = '-'; + } + h = z / 3600; + z %= 3600; + m = z / 60; + z %= 60; + if (z != 0) { + return Tcl_ObjPrintf("%c%02d%02d%02d", sign, h, m, z); + } + return Tcl_ObjPrintf("%c%02d%02d", sign, h, m); +} + +/* + *---------------------------------------------------------------------- + * [SB] TODO: make constans cacheable (once per second, etc.) ... + */ +inline int +ClockCurrentYearCentury( + ClientData clientData, /* Opaque pointer to literal pool, etc. */ + Tcl_Interp *interp) /* Tcl interpreter */ +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + int year = 2000; + + Tcl_Obj * yearObj = Tcl_ObjGetVar2(interp, + literals[LIT_CURRENTYEARCENTURY], NULL, TCL_LEAVE_ERR_MSG); + Tcl_GetIntFromObj(NULL, yearObj, &year); + return year; +} +inline int +ClockGetYearOfCenturySwitch( + ClientData clientData, /* Opaque pointer to literal pool, etc. */ + Tcl_Interp *interp) /* Tcl interpreter */ +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + int year = 37; + + Tcl_Obj * yearObj = Tcl_ObjGetVar2(interp, + literals[LIT_YEAROFCENTURYSWITCH], NULL, TCL_LEAVE_ERR_MSG); + Tcl_GetIntFromObj(NULL, yearObj, &year); + return year; +} + +/* + *---------------------------------------------------------------------- * * ClockConvertlocaltoutcObjCmd -- * @@ -426,6 +569,8 @@ ClockGetdatefieldsObjCmd( Tcl_Obj *const *literals = data->literals; int changeover; + fields.tzName = NULL; + /* * Check params. */ @@ -449,31 +594,14 @@ ClockGetdatefieldsObjCmd( return TCL_ERROR; } - /* - * Convert UTC time to local. - */ + /* Extract fields */ - if (ConvertUTCToLocal(interp, &fields, objv[2], changeover) != TCL_OK) { + if (ClockGetDateFields(interp, &fields, objv[2], changeover) + != TCL_OK) { return TCL_ERROR; } - /* - * Extract Julian day. - */ - - fields.julianDay = (int) ((fields.localSeconds + JULIAN_SEC_POSIX_EPOCH) - / SECONDS_PER_DAY); - - /* - * Convert to Julian or Gregorian calendar. - */ - - GetGregorianEraYearDay(&fields, changeover); - GetMonthDay(&fields); - GetYearWeekDay(&fields, changeover); - - -/************* split to use structured version from here ************/ + /* Make dict of fields */ dict = Tcl_NewDictObj(); Tcl_DictObjPut(NULL, dict, literals[LIT_LOCALSECONDS], @@ -511,6 +639,59 @@ ClockGetdatefieldsObjCmd( /* *---------------------------------------------------------------------- + */ +int +ClockGetDateFields( + Tcl_Interp *interp, /* Tcl interpreter */ + TclDateFields *fields, /* Pointer to result fields, where + * fields->seconds contains date to extract */ + Tcl_Obj *tzdata, /* Time zone data object or NULL for gmt */ + int changeover) /* Julian Day Number */ +{ + /* + * Convert UTC time to local. + */ + + if (ConvertUTCToLocal(interp, fields, tzdata, changeover) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Extract Julian day. + */ + + fields->julianDay = (int) ((fields->localSeconds + JULIAN_SEC_POSIX_EPOCH) + / SECONDS_PER_DAY); + + /* + * Convert to Julian or Gregorian calendar. + */ + + GetGregorianEraYearDay(fields, changeover); + GetMonthDay(fields); + GetYearWeekDay(fields, changeover); + + return TCL_OK; +} + +inline +SetDateFieldsTimeZone( + TclDateFields *fields, + Tcl_Obj *timezoneObj) +{ + if (fields->tzName != timezoneObj) { + if (timezoneObj) { + Tcl_IncrRefCount(timezoneObj); + } + if (fields->tzName != NULL) { + Tcl_DecrRefCount(fields->tzName); + } + fields->tzName = timezoneObj; + } +} + +/* + *---------------------------------------------------------------------- * * ClockGetjuliandayfromerayearmonthdayObjCmd -- * @@ -1013,8 +1194,7 @@ ConvertUTCToLocalUsingTable( * Convert the time. */ - fields->tzName = cellv[3]; - Tcl_IncrRefCount(fields->tzName); + SetDateFieldsTimeZone(fields, cellv[3]); fields->localSeconds = fields->seconds + fields->tzOffset; return TCL_OK; } @@ -1107,8 +1287,7 @@ ConvertUTCToLocalUsingC( if (diff > 0) { sprintf(buffer+5, "%02d", diff); } - fields->tzName = Tcl_NewStringObj(buffer, -1); - Tcl_IncrRefCount(fields->tzName); + SetDateFieldsTimeZone(fields, Tcl_NewStringObj(buffer, -1)); return TCL_OK; } @@ -1968,7 +2147,7 @@ ClockParseformatargsObjCmd( Tcl_Obj *const objv[]) /* Parameter vector */ { ClockClientData *dataPtr = clientData; - Tcl_Obj **litPtr = dataPtr->literals; + Tcl_Obj **literals = dataPtr->literals; _ClockFmtScnArgs resOpts; /* Format, locale and timezone */ Tcl_WideInt clockVal; /* Clock value - just used to parse. */ int ret; @@ -2003,11 +2182,11 @@ ClockParseformatargsObjCmd( return TCL_ERROR; } if (resOpts.formatObj == NULL) - resOpts.formatObj = litPtr[LIT__DEFAULT_FORMAT]; + resOpts.formatObj = literals[LIT__DEFAULT_FORMAT]; if (resOpts.localeObj == NULL) - resOpts.localeObj = litPtr[LIT_C]; + resOpts.localeObj = literals[LIT_C]; if (resOpts.timezoneObj == NULL) - resOpts.timezoneObj = litPtr[LIT__NIL]; + resOpts.timezoneObj = literals[LIT__NIL]; /* * Return options as a list. @@ -2032,7 +2211,7 @@ ClockScanObjCmd( Tcl_Obj *const objv[]) /* Parameter values */ { ClockClientData *dataPtr = clientData; - Tcl_Obj **litPtr = dataPtr->literals; + Tcl_Obj **literals = dataPtr->literals; Tcl_Time retClock; char *string, *format = NULL; @@ -2071,8 +2250,10 @@ ClockScanObjCmd( baseVal = (Tcl_WideInt) now.sec; } - /* if free scan */ + /* If free scan */ if (opts.formatObj == NULL) { +#if 0 + /* Tcled FreeScan proc - */ Tcl_Obj *callargs[5]; /* [SB] TODO: Perhaps someday we'll localize the legacy code. Right now, it's not localized. */ if (opts.localeObj != NULL) { @@ -2081,18 +2262,287 @@ ClockScanObjCmd( Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", NULL); return TCL_ERROR; } - callargs[0] = litPtr[LIT_FREESCAN]; + callargs[0] = literals[LIT_FREESCAN]; callargs[1] = objv[1]; callargs[2] = opts.baseObj != NULL ? opts.baseObj : Tcl_NewWideIntObj(baseVal); - callargs[3] = opts.timezoneObj != NULL ? opts.timezoneObj : litPtr[LIT__NIL]; - callargs[4] = opts.localeObj != NULL ? opts.localeObj : litPtr[LIT_C]; + callargs[3] = opts.timezoneObj != NULL ? opts.timezoneObj : literals[LIT__NIL]; + callargs[4] = opts.localeObj != NULL ? opts.localeObj : literals[LIT_C]; return Tcl_EvalObjv(interp, 5, callargs, 0); +#else + /* Use compiled version of FreeScan - */ + + + /* [SB] TODO: Perhaps someday we'll localize the legacy code. Right now, it's not localized. */ + if (opts.localeObj != NULL) { + Tcl_SetResult(interp, + "legacy [clock scan] does not support -locale", TCL_STATIC); + Tcl_SetErrorCode(interp, "CLOCK", "flagWithLegacyFormat", NULL); + return TCL_ERROR; + } + return ClockFreeScan(clientData, interp, objv[1], baseVal, + opts.timezoneObj, opts.localeObj); +#endif } + // **** string = TclGetString(objv[1]); - // **** timezone = GetSystemTimeZone() + // **** timezone = ClockGetSystemTimeZone(clientData, interp) + /* + if (timezoneObj == NULL) { + goto done; + } + */ + + return TCL_OK; +} + +/*---------------------------------------------------------------------- + */ +int +ClockFreeScan( + ClientData clientData, /* Client data containing literal pool */ + Tcl_Interp *interp, /* Tcl interpreter */ + Tcl_Obj *strObj, /* String containing the time to scan */ + Tcl_WideInt baseVal, /* Base time, expressed in seconds from the Epoch */ + Tcl_Obj *timezoneObj, /* Default time zone in which the time will be expressed */ + Tcl_Obj *locale) /* (Unused) Name of the locale where the time will be scanned. */ +{ + ClockClientData *dataPtr = clientData; + Tcl_Obj **literals = dataPtr->literals; + + DateInfo yy; /* parse structure of TclClockFreeScan */ + TclDateFields date; /* date fields used for converting from seconds */ + Tcl_Obj *tzdata; + int secondOfDay; /* Seconds of day (time only calculation) */ + Tcl_WideInt seconds; + int ret = TCL_ERROR; + Tcl_Obj *cleanUpList = Tcl_NewObj(); + + date.tzName = NULL; + + /* If time zone not specified use system time zone */ + if (timezoneObj == NULL || + TclGetString(timezoneObj) == NULL || timezoneObj->length == 0) { + timezoneObj = ClockGetSystemTimeZone(clientData, interp); + if (timezoneObj == NULL) { + goto done; + } + Tcl_ListObjAppendElement(NULL, cleanUpList, timezoneObj); + } + + /* Get the data for time changes in the given zone */ + + if (ClockSetupTimeZone(clientData, interp, timezoneObj) != TCL_OK) { + goto done; + } + + /* + * Extract year, month and day from the base time for the parser to use as + * defaults + */ + + tzdata = ClockGetTZData(clientData, interp, timezoneObj); + if (tzdata == NULL) { + goto done; + } + date.seconds = baseVal; + if (ClockGetDateFields(interp, &date, tzdata, GREGORIAN_CHANGE_DATE) + != TCL_OK) { + goto done; + } + + secondOfDay = date.localSeconds % 86400; + + /* + * Parse the date. The parser will fill a structure "yy" with date, time, + * time zone, relative month/day/seconds, relative weekday, ordinal month. + */ + yy.dateInput = Tcl_GetString(strObj); + + yy.dateYear = date.year; + yy.dateMonth = date.month; + yy.dateDay = date.dayOfMonth; + + if (TclClockFreeScan(interp, &yy) != TCL_OK) { + Tcl_Obj *msg = Tcl_NewObj(); + Tcl_AppendPrintfToObj(msg, "unable to convert date-time string \"", + yy.dateInput, "\":", + TclGetString(Tcl_GetObjResult(interp))); + Tcl_SetObjResult(interp, msg); + goto done; + } + + /* + * If the caller supplied a date in the string, update the date with + * the value. If the caller didn't specify a time with the date, default to + * midnight. + */ + + if (yy.dateHaveDate) { + if (yy.dateYear < 100) { + yy.dateYear += ClockCurrentYearCentury(clientData, interp); + if (yy.dateYear > ClockGetYearOfCenturySwitch(clientData, interp)) { + yy.dateYear -= 100; + } + } + date.era = CE; + date.year = yy.dateYear; + date.month = yy.dateMonth; + date.dayOfMonth = yy.dateDay; + if (yy.dateHaveTime == 0) { + yy.dateHaveTime = -1; + } + } + + /* + * If the caller supplied a time zone in the string, make it into a time + * zone indicator of +-hhmm and setup this time zone. + */ + + if (yy.dateHaveZone) { + int minEast = -yy.dateTimezone; + int dstFlag = 1 - yy.dateDSTmode; + timezoneObj = ClockFormatNumericTimeZone( + 60 * minEast + 3600 * dstFlag); + Tcl_ListObjAppendElement(NULL, cleanUpList, timezoneObj); + if (ClockSetupTimeZone(clientData, interp, timezoneObj) != TCL_OK) { + goto done; + } + tzdata = ClockGetTZData(clientData, interp, timezoneObj); + if (tzdata == NULL) { + goto done; + } + } + + SetDateFieldsTimeZone(&date, timezoneObj); + + /* Assemble date, time, zone into seconds-from-epoch */ + + GetJulianDayFromEraYearMonthDay(&date, GREGORIAN_CHANGE_DATE); + + if (yy.dateHaveTime == -1) { + secondOfDay = 0; + } + else + if (yy.dateHaveTime) { + secondOfDay = ToSeconds(yy.dateHour, yy.dateMinutes, + yy.dateSeconds, yy.dateMeridian); + } + else + if ( (yy.dateHaveDay && !yy.dateHaveDate) + || yy.dateHaveOrdinalMonth + || ( yy.dateHaveRel + && ( yy.dateRelMonth != 0 + || yy.dateRelDay != 0 ) ) + ) { + secondOfDay = 0; + } + + date.localSeconds = + -210866803200L + + ( 86400 * (Tcl_WideInt)date.julianDay ) + + secondOfDay; + + SetDateFieldsTimeZone(&date, timezoneObj); + if (ConvertLocalToUTC(interp, &date, tzdata, GREGORIAN_CHANGE_DATE) + != TCL_OK) { + goto done; + } + + seconds = date.seconds; + + /* + * Do relative times + */ + + if (yy.dateHaveRel) { + + /* [SB] TODO: rewrite it in C: * / + seconds = [add $seconds \ + yy.dateRelMonth months yy.dateRelDay days yy.dateRelMonthSecond seconds \ + -timezone $timezone -locale $locale] + */ + } + + /* + * Do relative weekday + */ + + if (yy.dateHaveDay && !yy.dateHaveDate) { + TclDateFields date2; + date2.tzName = NULL; + + SetDateFieldsTimeZone(&date2, timezoneObj); + + date2.seconds = date.seconds; + if (ClockGetDateFields(interp, &date2, tzdata, GREGORIAN_CHANGE_DATE) + != TCL_OK) { + SetDateFieldsTimeZone(&date2, NULL); + goto done; + } + date2.era = CE; + date2.julianDay = WeekdayOnOrBefore(yy.dateDayNumber, date2.julianDay + 6) + + 7 * yy.dateDayOrdinal; + if (yy.dateDayOrdinal > 0) { + date2.julianDay -= 7; + } + secondOfDay = date2.localSeconds % 86400; + date2.localSeconds = + -210866803200 + + ( 86400 * (Tcl_WideInt)date2.julianDay ) + + secondOfDay; + + SetDateFieldsTimeZone(&date2, timezoneObj); + if (ConvertLocalToUTC(interp, &date2, tzdata, GREGORIAN_CHANGE_DATE) + != TCL_OK) { + SetDateFieldsTimeZone(&date2, NULL); + goto done; + } + SetDateFieldsTimeZone(&date2, NULL); + + seconds = date2.seconds; + } + + /* + * Do relative month + */ + + if (yy.dateHaveOrdinalMonth) { + int monthDiff; + if (yy.dateMonthOrdinal > 0) { + monthDiff = yy.dateMonth - date.month; + if (monthDiff <= 0) { + monthDiff += 12; + } + yy.dateMonthOrdinal--; + } else { + monthDiff = date.month - yy.dateMonth; + if (monthDiff >= 0) { + monthDiff -= 12; + } + yy.dateMonthOrdinal++; + } + /* [SB] TODO: rewrite it in C: * / + seconds = [add $seconds $yy.dateMonthOrdinal years $monthDiff months \ + -timezone $timezone -locale $locale] + */ + } + + ret = TCL_OK; + +done: + + if (date.tzName != NULL) { + Tcl_DecrRefCount(date.tzName); + } + Tcl_DecrRefCount(cleanUpList); + + if (ret != TCL_OK) { + return ret; + } + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(seconds)); return TCL_OK; } diff --git a/generic/tclDate.c b/generic/tclDate.c index e4dd000..a31e0fc 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -1,24 +1,22 @@ -/* A Bison parser, made by GNU Bison 2.3. */ +/* A Bison parser, made by GNU Bison 2.4.2. */ /* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + 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 2, or (at your option) - any later version. - + 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,7 +27,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. */ @@ -47,7 +45,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.3" +#define YYBISON_VERSION "2.4.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -55,65 +53,24 @@ /* Pure parsers. */ #define YYPURE 1 +/* Push parsers. */ +#define YYPUSH 0 + +/* 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 - -/* Tokens. */ -#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, - tSNUMBER = 267, - tUNUMBER = 268, - tZONE = 269, - tEPOCH = 270, - tDST = 271, - tISOBASE = 272, - tDAY_UNIT = 273, - tNEXT = 274 - }; -#endif -/* Tokens. */ -#define tAGO 258 -#define tDAY 259 -#define tDAYZONE 260 -#define tID 261 -#define tMERIDIAN 262 -#define tMONTH 263 -#define tMONTH_UNIT 264 -#define tSTARDATE 265 -#define tSEC_UNIT 266 -#define tSNUMBER 267 -#define tUNUMBER 268 -#define tZONE 269 -#define tEPOCH 270 -#define tDST 271 -#define tISOBASE 272 -#define tDAY_UNIT 273 -#define tNEXT 274 - - - +#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. */ @@ -129,6 +86,7 @@ * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. + * */ #include "tclInt.h" @@ -146,44 +104,7 @@ * parsed fields will be returned. */ -typedef struct DateInfo { - - Tcl_Obj* messages; /* Error messages */ - const char* separatrix; /* String separating messages */ - - time_t dateYear; - time_t dateMonth; - time_t dateDay; - int dateHaveDate; - - time_t dateHour; - time_t dateMinutes; - time_t dateSeconds; - int dateMeridian; - int dateHaveTime; - - time_t dateTimezone; - int dateDSTmode; - int dateHaveZone; - - time_t dateRelMonth; - time_t dateRelDay; - time_t dateRelSeconds; - int dateHaveRel; - - time_t dateMonthOrdinal; - int dateHaveOrdinalMonth; - - time_t dateDayOrdinal; - time_t dateDayNumber; - int dateHaveDay; - - const char *dateStart; - const char *dateInput; - time_t *dateRelPointer; - - int dateDigitCount; -} DateInfo; +#include "tclDate.h" #define YYMALLOC ckalloc #define YYFREE(x) (ckfree((void*) (x))) @@ -246,13 +167,6 @@ typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe } DSTMODE; -/* - * Meridian: am, pm, or 24-hour style. - */ - -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; @@ -274,19 +188,49 @@ typedef enum _MERIDIAN { # define YYTOKEN_TABLE 0 #endif + +/* Tokens. */ +#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, + tSNUMBER = 267, + tUNUMBER = 268, + tZONE = 269, + tEPOCH = 270, + tDST = 271, + tISOBASE = 272, + tDAY_UNIT = 273, + tNEXT = 274 + }; +#endif + + + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE - { + + time_t Number; enum _MERIDIAN Meridian; -} -/* Line 187 of yacc.c. */ - YYSTYPE; + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 #endif #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED @@ -316,14 +260,10 @@ static int LookupWord(YYSTYPE* yylvalPtr, char *buff); DateInfo* info, const char *s); static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, DateInfo* info); -static time_t ToSeconds(time_t Hours, time_t Minutes, - time_t Seconds, MERIDIAN Meridian); MODULE_SCOPE int yyparse(DateInfo*); -/* Line 216 of yacc.c. */ - #ifdef short # undef short @@ -359,15 +299,21 @@ typedef short int yytype_int16; #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ -# else +# elif defined size_t # define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ -# if YYENABLE_NLS +# if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) @@ -392,14 +338,14 @@ typedef short int yytype_int16; #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int i) +YYID (int yyi) #else static int -YYID (i) - int i; +YYID (yyi) + int yyi; #endif { - return i; + return yyi; } #endif @@ -481,9 +427,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss; - YYSTYPE yyvs; - YYLTYPE yyls; + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ @@ -518,12 +464,12 @@ union yyalloc 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) \ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ @@ -624,12 +570,12 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 225, 225, 226, 229, 232, 235, 238, 241, 244, - 247, 251, 256, 259, 265, 271, 279, 285, 296, 300, - 304, 310, 314, 318, 322, 326, 332, 336, 341, 346, - 351, 356, 360, 365, 369, 374, 381, 385, 391, 400, - 409, 419, 433, 438, 441, 444, 447, 450, 453, 458, - 461, 466, 470, 474, 480, 498, 501 + 0, 176, 176, 177, 180, 183, 186, 189, 192, 195, + 198, 202, 207, 210, 216, 222, 230, 236, 247, 251, + 255, 261, 265, 269, 273, 277, 283, 287, 292, 297, + 302, 307, 311, 316, 320, 325, 332, 336, 342, 351, + 360, 370, 384, 389, 392, 395, 398, 401, 404, 409, + 412, 417, 421, 425, 431, 449, 452 }; #endif @@ -783,9 +729,18 @@ static const yytype_uint8 yystos[] = /* 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. */ + 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 #define YYRECOVERING() (!!yyerrstatus) @@ -842,7 +797,7 @@ while (YYID (0)) we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT -# if YYLTYPE_IS_TRIVIAL +# 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, \ @@ -961,17 +916,20 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, info) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } YYFPRINTF (stderr, "\n"); } @@ -1007,11 +965,11 @@ yy_reduce_print (yyvsp, yylsp, yyrule, info) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - fprintf (stderr, " $%d = ", yyi + 1); + YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) , info); - fprintf (stderr, "\n"); + YYFPRINTF (stderr, "\n"); } } @@ -1295,10 +1253,8 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, info) break; } } - /* Prevent warnings from -Wmissing-prototypes. */ - #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); @@ -1317,10 +1273,9 @@ int yyparse (); - -/*----------. -| yyparse. | -`----------*/ +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ @@ -1344,88 +1299,97 @@ yyparse (info) #endif #endif { - /* The look-ahead symbol. */ +/* The lookahead symbol. */ int yychar; -/* The semantic value of the look-ahead symbol. */ +/* The semantic value of the lookahead symbol. */ YYSTYPE yylval; -/* Number of syntax errors so far. */ -int yynerrs; -/* Location data for the look-ahead symbol. */ +/* Location data for the lookahead symbol. */ YYLTYPE yylloc; - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[2]; + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; - YYSIZE_T yystacksize = YYINITDEPTH; + YYSIZE_T yystacksize; + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + 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 YYLTYPE_IS_TRIVIAL + +#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 = 0; + yylloc.first_column = yylloc.last_column = 1; #endif goto yysetstate; @@ -1464,6 +1428,7 @@ YYLTYPE yylloc; &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); + yyls = yyls1; yyss = yyss1; yyvs = yyvs1; @@ -1485,9 +1450,9 @@ YYLTYPE yylloc; (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - YYSTACK_RELOCATE (yyls); + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1508,6 +1473,9 @@ YYLTYPE yylloc; YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + if (yystate == YYFINAL) + YYACCEPT; + goto yybackup; /*-----------. @@ -1516,16 +1484,16 @@ YYLTYPE yylloc; yybackup: /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ + lookahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to look-ahead token. */ + /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a look-ahead token if don't already have one. */ + /* Not known => get a lookahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -1557,20 +1525,16 @@ yybackup: goto yyreduce; } - if (yyn == YYFINAL) - YYACCEPT; - /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the look-ahead token. */ + /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; + /* Discard the shifted token. */ + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; @@ -2062,7 +2026,6 @@ yyreduce: break; -/* Line 1267 of yacc.c. */ default: break; } @@ -2139,7 +2102,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse look-ahead token after an + /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -2156,7 +2119,7 @@ yyerrlab: } } - /* Else will try to reuse look-ahead token after shifting the error + /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; @@ -2214,14 +2177,11 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } - if (yyn == YYFINAL) - YYACCEPT; - *++yyvsp = yylval; yyerror_range[1] = yylloc; /* Using YYLLOC is tempting, but would change the location of - the look-ahead. YYLOC is available though. */ + the lookahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); *++yylsp = yyloc; @@ -2246,7 +2206,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#ifndef yyoverflow +#if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -2257,7 +2217,7 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) + if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc, info); /* Do not reclaim the symbols of the rule which action triggered @@ -2513,7 +2473,7 @@ TclDateerror( infoPtr->separatrix = "\n"; } -static time_t +time_t ToSeconds( time_t Hours, time_t Minutes, @@ -2680,7 +2640,7 @@ TclDatelex( location->first_column = yyInput - info->dateStart; for ( ; ; ) { - while (TclIsSpaceProc(*yyInput)) { + while (isspace(UCHAR(*yyInput))) { yyInput++; } @@ -2740,36 +2700,20 @@ TclDatelex( } while (Count > 0); } } - + int -TclClockOldscanObjCmd( - ClientData clientData, /* Unused */ +TclClockFreeScan( Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Count of paraneters */ - Tcl_Obj *const *objv) /* Parameters */ + DateInfo *info) /* Input and result parameters */ { - Tcl_Obj *result, *resultElement; - int yr, mo, da; - DateInfo dateInfo; - DateInfo* info = &dateInfo; int status; - if (objc != 5) { - Tcl_WrongNumArgs(interp, 1, objv, - "stringToParse baseYear baseMonth baseDay" ); - return TCL_ERROR; - } - - yyInput = Tcl_GetString( objv[1] ); - dateInfo.dateStart = yyInput; + /* + * yyInput = stringToParse; + * yyYear = baseYear; yyMonth = baseMonth; yyDay = baseDay; + */ yyHaveDate = 0; - if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK - || Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK - || Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) { - return TCL_ERROR; - } - yyYear = yr; yyMonth = mo; yyDay = da; yyHaveTime = 0; yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; @@ -2786,19 +2730,20 @@ TclClockOldscanObjCmd( yyHaveRel = 0; yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; - dateInfo.messages = Tcl_NewObj(); - dateInfo.separatrix = ""; - Tcl_IncrRefCount(dateInfo.messages); + info->messages = Tcl_NewObj(); + info->separatrix = ""; + Tcl_IncrRefCount(info->messages); - status = yyparse(&dateInfo); + info->dateStart = yyInput; + status = yyparse(info); if (status == 1) { - Tcl_SetObjResult(interp, dateInfo.messages); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_SetObjResult(interp, info->messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); return TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); return TCL_ERROR; } else if (status != 0) { @@ -2806,11 +2751,11 @@ TclClockOldscanObjCmd( "from date parser. Please " "report this error as a " "bug in Tcl.", -1)); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "BUG", NULL); return TCL_ERROR; } - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); if (yyHaveDate > 1) { Tcl_SetObjResult(interp, @@ -2843,6 +2788,40 @@ TclClockOldscanObjCmd( return TCL_ERROR; } + return TCL_OK; +} + +int +TclClockOldscanObjCmd( + ClientData clientData, /* Unused */ + Tcl_Interp *interp, /* Tcl interpreter */ + int objc, /* Count of paraneters */ + Tcl_Obj *const *objv) /* Parameters */ +{ + Tcl_Obj *result, *resultElement; + int yr, mo, da; + DateInfo dateInfo; + DateInfo* info = &dateInfo; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 1, objv, + "stringToParse baseYear baseMonth baseDay" ); + return TCL_ERROR; + } + + yyInput = Tcl_GetString( objv[1] ); + + if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) { + return TCL_ERROR; + } + yyYear = yr; yyMonth = mo; yyDay = da; + + if (TclClockFreeScan(interp, info) != TCL_OK) { + return TCL_ERROR; + } + result = Tcl_NewObj(); resultElement = Tcl_NewObj(); if (yyHaveDate) { diff --git a/generic/tclDate.h b/generic/tclDate.h new file mode 100644 index 0000000..91e677f --- /dev/null +++ b/generic/tclDate.h @@ -0,0 +1,77 @@ +/* + * tclDate.h -- + * + * This header file handles common usage of clock primitives + * between tclDate.c (yacc) and tclClock.c. + * + * Copyright (c) 2014 Serg G. Brester (aka sebres) + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#ifndef _TCLCLOCK_H +#define _TCLCLOCK_H + +/* + * Structure contains return parsed fields. + */ + +typedef struct DateInfo { + + Tcl_Obj* messages; /* Error messages */ + const char* separatrix; /* String separating messages */ + + time_t dateYear; + time_t dateMonth; + time_t dateDay; + int dateHaveDate; + + time_t dateHour; + time_t dateMinutes; + time_t dateSeconds; + int dateMeridian; + int dateHaveTime; + + time_t dateTimezone; + int dateDSTmode; + int dateHaveZone; + + time_t dateRelMonth; + time_t dateRelDay; + time_t dateRelSeconds; + int dateHaveRel; + + time_t dateMonthOrdinal; + int dateHaveOrdinalMonth; + + time_t dateDayOrdinal; + time_t dateDayNumber; + int dateHaveDay; + + const char *dateStart; + const char *dateInput; + time_t *dateRelPointer; + + int dateDigitCount; +} DateInfo; + + +/* + * Meridian: am, pm, or 24-hour style. + */ + +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + +/* + * Prototypes of module functions. + */ + +MODULE_SCOPE time_t ToSeconds(time_t Hours, time_t Minutes, + time_t Seconds, MERIDIAN Meridian); + +MODULE_SCOPE int TclClockFreeScan(Tcl_Interp *interp, DateInfo *info); + +#endif /* _TCLCLOCK_H */ diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index da4c3fd..ac781ad 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -50,44 +50,7 @@ * parsed fields will be returned. */ -typedef struct DateInfo { - - Tcl_Obj* messages; /* Error messages */ - const char* separatrix; /* String separating messages */ - - time_t dateYear; - time_t dateMonth; - time_t dateDay; - int dateHaveDate; - - time_t dateHour; - time_t dateMinutes; - time_t dateSeconds; - int dateMeridian; - int dateHaveTime; - - time_t dateTimezone; - int dateDSTmode; - int dateHaveZone; - - time_t dateRelMonth; - time_t dateRelDay; - time_t dateRelSeconds; - int dateHaveRel; - - time_t dateMonthOrdinal; - int dateHaveOrdinalMonth; - - time_t dateDayOrdinal; - time_t dateDayNumber; - int dateHaveDay; - - const char *dateStart; - const char *dateInput; - time_t *dateRelPointer; - - int dateDigitCount; -} DateInfo; +#include "tclDate.h" #define YYMALLOC ckalloc #define YYFREE(x) (ckfree((void*) (x))) @@ -150,14 +113,6 @@ typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe } DSTMODE; -/* - * Meridian: am, pm, or 24-hour style. - */ - -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; - %} %union { @@ -176,8 +131,6 @@ static int LookupWord(YYSTYPE* yylvalPtr, char *buff); DateInfo* info, const char *s); static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, DateInfo* info); -static time_t ToSeconds(time_t Hours, time_t Minutes, - time_t Seconds, MERIDIAN Meridian); MODULE_SCOPE int yyparse(DateInfo*); %} @@ -730,7 +683,7 @@ TclDateerror( infoPtr->separatrix = "\n"; } -static time_t +time_t ToSeconds( time_t Hours, time_t Minutes, @@ -957,36 +910,20 @@ TclDatelex( } while (Count > 0); } } - + int -TclClockOldscanObjCmd( - ClientData clientData, /* Unused */ +TclClockFreeScan( Tcl_Interp *interp, /* Tcl interpreter */ - int objc, /* Count of paraneters */ - Tcl_Obj *const *objv) /* Parameters */ + DateInfo *info) /* Input and result parameters */ { - Tcl_Obj *result, *resultElement; - int yr, mo, da; - DateInfo dateInfo; - DateInfo* info = &dateInfo; int status; - if (objc != 5) { - Tcl_WrongNumArgs(interp, 1, objv, - "stringToParse baseYear baseMonth baseDay" ); - return TCL_ERROR; - } - - yyInput = Tcl_GetString( objv[1] ); - dateInfo.dateStart = yyInput; + /* + * yyInput = stringToParse; + * yyYear = baseYear; yyMonth = baseMonth; yyDay = baseDay; + */ yyHaveDate = 0; - if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK - || Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK - || Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) { - return TCL_ERROR; - } - yyYear = yr; yyMonth = mo; yyDay = da; yyHaveTime = 0; yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; @@ -1003,19 +940,20 @@ TclClockOldscanObjCmd( yyHaveRel = 0; yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; - dateInfo.messages = Tcl_NewObj(); - dateInfo.separatrix = ""; - Tcl_IncrRefCount(dateInfo.messages); + info->messages = Tcl_NewObj(); + info->separatrix = ""; + Tcl_IncrRefCount(info->messages); - status = yyparse(&dateInfo); + info->dateStart = yyInput; + status = yyparse(info); if (status == 1) { - Tcl_SetObjResult(interp, dateInfo.messages); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_SetObjResult(interp, info->messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DATE", "PARSE", NULL); return TCL_ERROR; } else if (status == 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); return TCL_ERROR; } else if (status != 0) { @@ -1023,11 +961,11 @@ TclClockOldscanObjCmd( "from date parser. Please " "report this error as a " "bug in Tcl.", -1)); - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); Tcl_SetErrorCode(interp, "TCL", "BUG", NULL); return TCL_ERROR; } - Tcl_DecrRefCount(dateInfo.messages); + Tcl_DecrRefCount(info->messages); if (yyHaveDate > 1) { Tcl_SetObjResult(interp, @@ -1060,6 +998,40 @@ TclClockOldscanObjCmd( return TCL_ERROR; } + return TCL_OK; +} + +int +TclClockOldscanObjCmd( + ClientData clientData, /* Unused */ + Tcl_Interp *interp, /* Tcl interpreter */ + int objc, /* Count of paraneters */ + Tcl_Obj *const *objv) /* Parameters */ +{ + Tcl_Obj *result, *resultElement; + int yr, mo, da; + DateInfo dateInfo; + DateInfo* info = &dateInfo; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 1, objv, + "stringToParse baseYear baseMonth baseDay" ); + return TCL_ERROR; + } + + yyInput = Tcl_GetString( objv[1] ); + + if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[3], &mo) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[4], &da) != TCL_OK) { + return TCL_ERROR; + } + yyYear = yr; yyMonth = mo; yyDay = da; + + if (TclClockFreeScan(interp, info) != TCL_OK) { + return TCL_ERROR; + } + result = Tcl_NewObj(); resultElement = Tcl_NewObj(); if (yyHaveDate) { diff --git a/library/clock.tcl b/library/clock.tcl index 5b48eb3..9c3f95c 100755 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -287,6 +287,10 @@ proc ::tcl::clock::Initialize {} { variable FEB_28 58 + # Current year century and year of century switch + variable CurrentYearCentury 2000 + variable YearOfCenturySwitch 37 + # Translation table to map Windows TZI onto cities, so that the Olson # rules can apply. In some cases the mapping is ambiguous, so it's wise # to specify $::env(TCL_TZ) rather than simply depending on the system @@ -1295,7 +1299,7 @@ proc ::tcl::clock::__org_scan { args } { # #---------------------------------------------------------------------- -proc ::tcl::clock::FreeScan { string base timezone locale } { +proc ::tcl::clock::__org_FreeScan { string base timezone locale } { variable TZData @@ -1341,7 +1345,8 @@ proc ::tcl::clock::FreeScan { string base timezone locale } { if { [llength $parseDate] > 0 } { lassign $parseDate y m d if { $y < 100 } { - if { $y >= 39 } { + variable YearOfCenturySwitch + if { $y > $YearOfCenturySwitch } { incr y 1900 } else { incr y 2000 @@ -2719,12 +2724,14 @@ proc ::tcl::clock::ScanWide { str } { proc ::tcl::clock::InterpretTwoDigitYear { date baseTime { twoDigitField yearOfCentury } { fourDigitField year } } { + variable CurrentYearCentury + variable YearOfCenturySwitch set yr [dict get $date $twoDigitField] - if { $yr <= 37 } { - dict set date $fourDigitField [expr { $yr + 2000 }] - } else { - dict set date $fourDigitField [expr { $yr + 1900 }] + incr yr $CurrentYearCentury + if { $yr <= $YearOfCenturySwitch } { + incr yr -100 } + dict set date $fourDigitField $yr return $date } diff --git a/library/init.tcl b/library/init.tcl index e6df12b..4bbce51 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -178,7 +178,7 @@ if {[interp issafe]} { # Auto-loading stubs for 'clock.tcl' - foreach cmd {add format FreeScan} { + foreach cmd {add format} { proc ::tcl::clock::$cmd args { variable TclLibDir source -encoding utf-8 [file join $TclLibDir clock.tcl] diff --git a/win/makefile.vc b/win/makefile.vc index d6de5e1..26ee669 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -482,7 +482,9 @@ cdebug = $(cdebug) -Zi ### Warnings are too many, can't support warnings into errors. cdebug = -Zi -Od $(DEBUGFLAGS) !else -cdebug = -Zi -WX $(DEBUGFLAGS) +# no -WX option here (error C2220: warning treated as error): +#cdebug = -Zi -WX $(DEBUGFLAGS) +cdebug = -Zi $(DEBUGFLAGS) !endif ### Declarations common to all compiler options -- cgit v0.12