From b2ddd5afb45d64091bc8d01b2b113523ffd74d45 Mon Sep 17 00:00:00 2001 From: Kevin B Kenny Date: Mon, 27 Sep 2004 14:31:14 +0000 Subject: many more TIP 173 changes --- ChangeLog | 32 +++ compat/strftime.c | 538 ----------------------------------- generic/tclClock.c | 105 +------ generic/tclDate.c | 767 +++++++++++++++++++------------------------------- generic/tclGetDate.y | 573 +++++++++++++------------------------ generic/tclInt.decls | 20 +- generic/tclInt.h | 37 +-- generic/tclIntDecls.h | 31 +- generic/tclStubInit.c | 6 +- library/clock.tcl | 433 ++++++++++++++++++++-------- unix/tclUnixTime.c | 57 +--- win/Makefile.in | 15 +- win/makefile.bc | 1 - win/makefile.vc | 14 +- win/tcl.dsp | 4 - 15 files changed, 868 insertions(+), 1765 deletions(-) delete mode 100644 compat/strftime.c diff --git a/ChangeLog b/ChangeLog index 4e696b9..4debeae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2004-09-27 Kevin Kenny + + * compat/strftime.c (Removed): + * generic/tclClock.c (removed TclClockOldscanObjCmd): + * generic/tclDate.c (Regenerated): + * generic/tclGetDate.y: + * generic/tclInt.decls (removed TclGetDate and TclpStrftime): + * generic/tclInt.h (removed TclGetDateInfo): + * generic/tclIntDecls.h (Regenerated): + * generic/tclStubInit.c (Regenerated): + * library/clock.tcl: + * unix/tclUnixTime.c (removed TclpStrftime): + * win/Makefile.in: + * win/makefile.bc: + * win/makefile.bc: + * win/tcl.dsp: + Continued refactoring of [clock] for TIP 173 changes. + Broke the free-form parser apart so that the Bison parser + is responsible for only parsing, while clock.tcl handles + relative times like "next Thursday", "next January". This + change is needed to make timezones other than :localtime + and :Etc/UTC work with free-form scanning. This change closes + out the issue identified as being "for another day" in + my log message of 2004-09-08. The refactored code also + eliminates the last known references to TclpStrftime and + TclGetDate, so those routines (including compat/strftime.c) + have been removed. The refactoring also has the benefit + that all storage in the Bison parser is now on the C stack, + eliminating any need for mutex protection around [clock scan]. + Also, changed the Makefiles so that 'make gendate' is + available on Windows as well as Unix. + 2004-09-27 Vince Darley * doc/FileSystem.3: fix to small typo. diff --git a/compat/strftime.c b/compat/strftime.c deleted file mode 100644 index 91e7057..0000000 --- a/compat/strftime.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * strftime.c -- - * - * This file contains a modified version of the BSD 4.4 strftime - * function. - * - * This file is a modified version of the strftime.c file from the BSD 4.4 - * source. See the copyright notice below for details on redistribution - * restrictions. The "license.terms" file does not apply to this file. - * - * Changes 2002 Copyright (c) 2002 ActiveState Corporation. - * - * RCS: @(#) $Id: strftime.c,v 1.17 2004/09/08 18:46:18 kennykb Exp $ - */ - -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) -static char *rcsid = "$Id: strftime.c,v 1.17 2004/09/08 18:46:18 kennykb Exp $"; -#endif /* LIBC_SCCS */ - -#include -#include -#include -#include "tclInt.h" - -#define TM_YEAR_BASE 1900 -#define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) - -/* - * Structure type holding the locale-dependent strings for formatting - * times. The strings are all expected to be encoded in UTF-8. - */ - -typedef struct { - const char *abday[7]; /* Abbreviated weekday names */ - const char *day[7]; /* Full weekday names */ - const char *abmon[12]; /* Abbreviated month names */ - const char *mon[12]; /* Full month name */ - const char *am_pm[2]; /* The strings to use for meridian time - * (am, pm) */ - const char *d_t_fmt; /* The locale-dependent date-time format */ - const char *d_fmt; /* The locale-dependent date format */ - const char *t_fmt; /* The locale-dependent 24hr time format */ - const char *t_fmt_ampm; /* The locale-dependent 12hr time format */ -} _TimeLocale; - -/* - * This is the C locale default. On Windows, if we wanted to make this - * localized, we would use GetLocaleInfo to get the correct values. - * It may be acceptable to do localization of month/day names, as the - * numerical values would be considered the locale-independent versions. - */ -static const _TimeLocale _DefaultTimeLocale = -{ - { - "Sun","Mon","Tue","Wed","Thu","Fri","Sat", - }, - { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", - "Friday", "Saturday" - }, - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }, - { - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" - }, - { - "AM", "PM" - }, - "%a %b %d %H:%M:%S %Y", - "%m/%d/%y", - "%H:%M:%S", - "%I:%M:%S %p" -}; - -static CONST _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale; - -static int isGMT; -static size_t gsize; -static char *pt; -static int _add _ANSI_ARGS_((CONST char* str)); -static int _conv _ANSI_ARGS_((int n, int digits, int pad)); -static int _secs _ANSI_ARGS_((CONST struct tm *t)); -static size_t _fmt _ANSI_ARGS_((CONST char *format, - const struct tm *t)); -static int ISO8601Week _ANSI_ARGS_((CONST struct tm* t, int *year )); - -/* - *---------------------------------------------------------------------- - * - * TclpStrftime -- - * - * Formats a time (in 'struct tm' representation) for use by - * [clock format]. - * - * Results: - * Returns the length of the formatted string. - * - * Side effects: - * Stores the formatted string in the 's' parameter. The - * formatted string is returned in UTF-8 encoding, *not* the - * system encoding. - * - *---------------------------------------------------------------------- - */ - -size_t -TclpStrftime(s, maxsize, format, t, useGMT) - char *s; /* Buffer to hold the formatted string */ - size_t maxsize; /* Size of the passed buffer */ - CONST char *format; /* Format to use (see the user documentation - * for [clock] for details) */ - CONST struct tm *t; /* Time to format */ - int useGMT; /* Flag == 1 if time is to be returned - * in UTC */ -{ - if (format[0] == '%' && format[1] == 'Q') { - /* Format as a stardate */ - sprintf(s, "Stardate %2d%03d.%01d", - (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), - (((t->tm_yday + 1) * 1000) / - (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), - (((t->tm_hour * 60) + t->tm_min)/144)); - return(strlen(s)); - } - - isGMT = useGMT; - /* - * We may be able to skip this for useGMT, but it should be harmless. - * -- hobbs - */ - tzset(); - - pt = s; - if ((gsize = maxsize) < 1) - return(0); - if (_fmt(format, t)) { - *pt = '\0'; - return(maxsize - gsize); - } - return(0); -} - -#define SUN_WEEK(t) (((t)->tm_yday + 7 - \ - ((t)->tm_wday)) / 7) -#define MON_WEEK(t) (((t)->tm_yday + 7 - \ - ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7) - -static size_t -_fmt(format, t) - CONST char *format; - CONST struct tm *t; -{ -#ifdef __WIN32__ -#define BUF_SIZ 256 - TCHAR buf[BUF_SIZ]; - SYSTEMTIME syst; - syst.wYear = t->tm_year + 1900; - syst.wMonth = t->tm_mon + 1; - syst.wDayOfWeek = t->tm_wday; - syst.wDay = t->tm_mday; - syst.wHour = t->tm_hour; - syst.wMinute = t->tm_min; - syst.wSecond = t->tm_sec; - syst.wMilliseconds = 0; -#endif - for (; *format; ++format) { - if (*format == '%') { - ++format; - if (*format == 'E') { - /* Alternate Era */ - ++format; - } else if (*format == 'O') { - /* Alternate numeric symbols */ - ++format; - } - switch(*format) { - case '\0': - --format; - break; - case 'A': - if (t->tm_wday < 0 || t->tm_wday > 6) - return(0); - if (!_add(_CurrentTimeLocale->day[t->tm_wday])) - return(0); - continue; - case 'a': - if (t->tm_wday < 0 || t->tm_wday > 6) - return(0); - if (!_add(_CurrentTimeLocale->abday[t->tm_wday])) - return(0); - continue; - case 'B': - if (t->tm_mon < 0 || t->tm_mon > 11) - return(0); - if (!_add(_CurrentTimeLocale->mon[t->tm_mon])) - return(0); - continue; - case 'b': - case 'h': - if (t->tm_mon < 0 || t->tm_mon > 11) - return(0); - if (!_add(_CurrentTimeLocale->abmon[t->tm_mon])) - return(0); - continue; - case 'C': - if (!_conv((t->tm_year + TM_YEAR_BASE) / 100, - 2, '0')) - return(0); - continue; - case 'D': - if (!_fmt("%m/%d/%y", t)) - return(0); - continue; - case 'd': - if (!_conv(t->tm_mday, 2, '0')) - return(0); - continue; - case 'e': - if (!_conv(t->tm_mday, 2, ' ')) - return(0); - continue; - case 'g': - { - int year; - ISO8601Week( t, &year ); - if ( !_conv( year%100, 2, '0' ) ) { - return( 0 ); - } - continue; - } - case 'G': - { - int year; - ISO8601Week( t, &year ); - if ( !_conv( year, 4, '0' ) ) { - return( 0 ); - } - continue; - } - case 'H': - if (!_conv(t->tm_hour, 2, '0')) - return(0); - continue; - case 'I': - if (!_conv(t->tm_hour % 12 ? - t->tm_hour % 12 : 12, 2, '0')) - return(0); - continue; - case 'j': - if (!_conv(t->tm_yday + 1, 3, '0')) - return(0); - continue; - case 'k': - if (!_conv(t->tm_hour, 2, ' ')) - return(0); - continue; - case 'l': - if (!_conv(t->tm_hour % 12 ? - t->tm_hour % 12: 12, 2, ' ')) - return(0); - continue; - case 'M': - if (!_conv(t->tm_min, 2, '0')) - return(0); - continue; - case 'm': - if (!_conv(t->tm_mon + 1, 2, '0')) - return(0); - continue; - case 'n': - if (!_add("\n")) - return(0); - continue; - case 'p': - if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12])) - return(0); - continue; - case 'R': - if (!_fmt("%H:%M", t)) - return(0); - continue; - case 'r': - if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t)) - return(0); - continue; - case 'S': - if (!_conv(t->tm_sec, 2, '0')) - return(0); - continue; - case 's': - if (!_secs(t)) - return(0); - continue; - case 'T': - if (!_fmt("%H:%M:%S", t)) - return(0); - continue; - case 't': - if (!_add("\t")) - return(0); - continue; - case 'U': - if (!_conv(SUN_WEEK(t), 2, '0')) - return(0); - continue; - case 'u': - if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0')) - return(0); - continue; - case 'V': - { - int week = ISO8601Week( t, NULL ); - if (!_conv(week, 2, '0')) - return(0); - continue; - } - case 'W': - if (!_conv(MON_WEEK(t), 2, '0')) - return(0); - continue; - case 'w': - if (!_conv(t->tm_wday, 1, '0')) - return(0); - continue; -#ifdef __WIN32__ - /* - * To properly handle the localized time routines on Windows, - * we must make use of the special localized calls. - */ - case 'c': - if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, - &syst, NULL, buf, BUF_SIZ) || !_add(buf) - || !_add(" ")) { - return(0); - } - /* - * %c is created with LONGDATE + " " + TIME on Windows, - * so continue to %X case here. - */ - case 'X': - if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, - &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { - return(0); - } - continue; - case 'x': - if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, - &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { - return(0); - } - continue; -#else - case 'c': - if (!_fmt(_CurrentTimeLocale->d_t_fmt, t)) - return(0); - continue; - case 'x': - if (!_fmt(_CurrentTimeLocale->d_fmt, t)) - return(0); - continue; - case 'X': - if (!_fmt(_CurrentTimeLocale->t_fmt, t)) - return(0); - continue; -#endif - case 'y': - if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, - 2, '0')) - return(0); - continue; - case 'Y': - if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0')) - return(0); - continue; - case 'Z': { - char *name = (isGMT ? "GMT" : TclpGetTZName(t->tm_isdst)); - if (name && !_add(name)) { - return 0; - } - continue; - } - case '%': - /* - * X311J/88-090 (4.12.3.5): if conversion char is - * undefined, behavior is undefined. Print out the - * character itself as printf(3) does. - */ - default: - break; - } - } - if (!gsize--) - return(0); - *pt++ = *format; - } - return(gsize); -} - -static int -_secs(t) - CONST struct tm *t; -{ - static char buf[15]; - register time_t s; - register char *p; - struct tm tmp; - - /* Make a copy, mktime(3) modifies the tm struct. */ - tmp = *t; - s = mktime(&tmp); - for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) - *p-- = (char)(s % 10 + '0'); - return(_add(++p)); -} - -static int -_conv(n, digits, pad) - int n, digits; - int pad; -{ - static char buf[10]; - register char *p; - - p = buf + sizeof( buf ) - 1; - *p-- = '\0'; - if ( n == 0 ) { - *p-- = '0'; - } else { - for (; n > 0 && p > buf; n /= 10, --digits) - *p-- = (char)(n % 10 + '0'); - } - while (p > buf && digits-- > 0) - *p-- = (char) pad; - return(_add(++p)); -} - -static int -_add(str) - const char *str; -{ - for (;; ++pt, --gsize) { - if (!gsize) - return(0); - if (!(*pt = *str++)) - return(1); - } -} - -static int -ISO8601Week( t, year ) - CONST struct tm* t; - int* year; -{ - /* Find the day-of-year of the Thursday in - * the week in question. */ - - int ydayThursday; - int week; - if ( t->tm_wday == 0 ) { - ydayThursday = t->tm_yday - 3; - } else { - ydayThursday = t->tm_yday - t->tm_wday + 4; - } - - if ( ydayThursday < 0 ) { - - /* This is the last week of the previous year. */ - if ( IsLeapYear(( t->tm_year + TM_YEAR_BASE - 1 )) ) { - ydayThursday += 366; - } else { - ydayThursday += 365; - } - week = ydayThursday / 7 + 1; - if ( year != NULL ) { - *year = t->tm_year + 1899; - } - - } else if ( ( IsLeapYear(( t -> tm_year + TM_YEAR_BASE )) - && ydayThursday >= 366 ) - || ( !IsLeapYear(( t -> tm_year - + TM_YEAR_BASE )) - && ydayThursday >= 365 ) ) { - - /* This is week 1 of the following year */ - - week = 1; - if ( year != NULL ) { - *year = t->tm_year + 1901; - } - - } else { - - week = ydayThursday / 7 + 1; - if ( year != NULL ) { - *year = t->tm_year + 1900; - } - - } - - return week; - -} diff --git a/generic/tclClock.c b/generic/tclClock.c index f6edf43..e30760b 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclClock.c,v 1.33 2004/09/14 21:42:55 kennykb Exp $ + * RCS: @(#) $Id: tclClock.c,v 1.34 2004/09/27 14:31:17 kennykb Exp $ */ #include "tclInt.h" @@ -519,107 +519,4 @@ TzsetIfNecessary() } Tcl_MutexUnlock( &clockMutex ); } - -/* - *------------------------------------------------------------------------- - * - * TclClockOldscanObjCmd -- - * - * Implements the legacy 'clock scan' Tcl command when no '-format' - * option is supplied. - * - * Results: - * Returns a standard Tcl result. - * - * This function implements the 'clock scan' Tcl command when no - * -format group is present. Refer to the user documentation to see - * what it does. - * - *------------------------------------------------------------------------- - */ - -int -TclClockOldscanObjCmd( ClientData clientData, /* unused */ - Tcl_Interp* interp, /* Tcl interpreter */ - int objc, /* Parameter count */ - Tcl_Obj *CONST * objv /* Parameter vector */ - ) -{ - int index; - Tcl_Obj *CONST *objPtr; - char *scanStr; - Tcl_Obj *baseObjPtr = NULL; - int useGMT = 0; - unsigned long baseClock; - unsigned long clockVal; - long zone; - Tcl_Obj *resultPtr; - int dummy; - - static CONST char *scanSwitches[] = { - "-base", "-gmt", (char *) NULL - }; - - if ((objc < 2) || (objc > 6)) { - wrongScanArgs: - Tcl_WrongNumArgs(interp, 2, objv, - "dateString ?-base clockValue? ?-gmt boolean?"); - return TCL_ERROR; - } - objPtr = objv+2; - objc -= 2; - while (objc > 1) { - if (Tcl_GetIndexFromObj(interp, objPtr[0], scanSwitches, - "switch", 0, &index) != TCL_OK) { - return TCL_ERROR; - } - switch (index) { - case 0: /* -base */ - baseObjPtr = objPtr[1]; - break; - case 1: /* -gmt */ - if (Tcl_GetBooleanFromObj(interp, objPtr[1], - &useGMT) != TCL_OK) { - return TCL_ERROR; - } - break; - } - objPtr += 2; - objc -= 2; - } - if (objc != 0) { - goto wrongScanArgs; - } - - if (baseObjPtr != NULL) { - if (Tcl_GetLongFromObj(interp, baseObjPtr, - (long*) &baseClock) != TCL_OK) { - return TCL_ERROR; - } - } else { - baseClock = TclpGetSeconds(); - } - - if (useGMT) { - zone = -50000; /* Force GMT */ - } else { - zone = TclpGetTimeZone((unsigned long) baseClock); - } - - scanStr = Tcl_GetStringFromObj(objv[1], &dummy); - Tcl_MutexLock(&clockMutex); - if (TclGetDate(scanStr, (unsigned long) baseClock, zone, - &clockVal) < 0) { - Tcl_MutexUnlock(&clockMutex); - resultPtr = Tcl_NewObj(); - Tcl_AppendStringsToObj(resultPtr, - "unable to convert date-time string \"", - scanStr, "\"", (char *) NULL); - Tcl_SetObjResult( interp, resultPtr ); - return TCL_ERROR; - } - Tcl_MutexUnlock(&clockMutex); - Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt) clockVal ) ); - return TCL_OK; -} diff --git a/generic/tclDate.c b/generic/tclDate.c index 8369a85..566c848 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -1,7 +1,7 @@ -/* A Bison parser, made by GNU Bison 1.875. */ +/* A Bison parser, made by GNU Bison 1.875b. */ /* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 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 @@ -105,7 +105,7 @@ /* Copy the first part of user declarations. */ -#line 17 "../unix/../generic/tclGetDate.y" +#line 17 "..\\generic/tclGetDate.y" /* * tclDate.c -- @@ -119,9 +119,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCSID */ +#include "tclInt.h" + /* * Bison generates several labels that happen to be unused. MS Visual * C++ doesn't like that, and complains. Tell it to shut up. @@ -132,35 +133,70 @@ #endif /* _MSC_VER */ /* - * yyparse will accept a 'struct TclGetDateInfo' as its parameter; + * yyparse will accept a 'struct DateInfo' as its parameter; * that's where the parsed fields will be returned. */ -#define YYPARSE_PARAM info +typedef struct DateInfo { -#define yyDSTmode (((TclGetDateInfo*)info)->dateDSTmode) -#define yyDayOrdinal (((TclGetDateInfo*)info)->dateDayOrdinal) -#define yyDayNumber (((TclGetDateInfo*)info)->dateDayNumber) -#define yyMonthOrdinal (((TclGetDateInfo*)info)->dateMonthOrdinal) -#define yyHaveDate (((TclGetDateInfo*)info)->dateHaveDate) -#define yyHaveDay (((TclGetDateInfo*)info)->dateHaveDay) -#define yyHaveOrdinalMonth (((TclGetDateInfo*)info)->dateHaveOrdinalMonth) -#define yyHaveRel (((TclGetDateInfo*)info)->dateHaveRel) -#define yyHaveTime (((TclGetDateInfo*)info)->dateHaveTime) -#define yyHaveZone (((TclGetDateInfo*)info)->dateHaveZone) -#define yyTimezone (((TclGetDateInfo*)info)->dateTimezone) -#define yyDay (((TclGetDateInfo*)info)->dateDay) -#define yyMonth (((TclGetDateInfo*)info)->dateMonth) -#define yyYear (((TclGetDateInfo*)info)->dateYear) -#define yyHour (((TclGetDateInfo*)info)->dateHour) -#define yyMinutes (((TclGetDateInfo*)info)->dateMinutes) -#define yySeconds (((TclGetDateInfo*)info)->dateSeconds) -#define yyMeridian (((TclGetDateInfo*)info)->dateMeridian) -#define yyRelMonth (((TclGetDateInfo*)info)->dateRelMonth) -#define yyRelDay (((TclGetDateInfo*)info)->dateRelDay) -#define yyRelSeconds (((TclGetDateInfo*)info)->dateRelSeconds) + time_t dateYear; + time_t dateMonth; + time_t dateDay; + int dateHaveDate; -#include "tclInt.h" + 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; + + char *dateInput; + time_t *dateRelPointer; + +} DateInfo; + +#define YYPARSE_PARAM info +#define YYLEX_PARAM info + +#define yyDSTmode (((DateInfo*)info)->dateDSTmode) +#define yyDayOrdinal (((DateInfo*)info)->dateDayOrdinal) +#define yyDayNumber (((DateInfo*)info)->dateDayNumber) +#define yyMonthOrdinal (((DateInfo*)info)->dateMonthOrdinal) +#define yyHaveDate (((DateInfo*)info)->dateHaveDate) +#define yyHaveDay (((DateInfo*)info)->dateHaveDay) +#define yyHaveOrdinalMonth (((DateInfo*)info)->dateHaveOrdinalMonth) +#define yyHaveRel (((DateInfo*)info)->dateHaveRel) +#define yyHaveTime (((DateInfo*)info)->dateHaveTime) +#define yyHaveZone (((DateInfo*)info)->dateHaveZone) +#define yyTimezone (((DateInfo*)info)->dateTimezone) +#define yyDay (((DateInfo*)info)->dateDay) +#define yyMonth (((DateInfo*)info)->dateMonth) +#define yyYear (((DateInfo*)info)->dateYear) +#define yyHour (((DateInfo*)info)->dateHour) +#define yyMinutes (((DateInfo*)info)->dateMinutes) +#define yySeconds (((DateInfo*)info)->dateSeconds) +#define yyMeridian (((DateInfo*)info)->dateMeridian) +#define yyRelMonth (((DateInfo*)info)->dateRelMonth) +#define yyRelDay (((DateInfo*)info)->dateRelDay) +#define yyRelSeconds (((DateInfo*)info)->dateRelSeconds) +#define yyRelPointer (((DateInfo*)info)->dateRelPointer) +#define yyInput (((DateInfo*)info)->dateInput) #define EPOCH 1970 #define START_OF_TIME 1902 @@ -168,10 +204,7 @@ /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. - * I don't know how universal this is; K&R II, the NetBSD manpages, and - * ../compat/strftime.c all agree that tm_year is the year-1900. However, - * some systems may have a different value. This #define should be the - * same as in ../compat/strftime.c. + * Posix requires 1900. */ #define TM_YEAR_BASE 1900 @@ -205,36 +238,13 @@ typedef enum _MERIDIAN { /* - * Global variables. We could get rid of most of these by using a good - * union as the yacc stack. (This routine was originally written before - * yacc had the %union construct.) Maybe someday; right now we only use - * the %union very rarely. - */ - -static char *yyInput; -static time_t *yyRelPointer; - -/* * Prototypes of internal functions. */ static void TclDateerror _ANSI_ARGS_((char *s)); static time_t ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)); -static int Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year, - time_t Hours, time_t Minutes, time_t Seconds, - MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr, - VOID* info)); -static time_t DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future)); -static time_t NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal, - time_t DayNumber)); -static time_t NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal, - time_t MonthNumber, VOID* info)); -static int RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth, - time_t *TimePtr, VOID* info)); -static int RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay, - time_t *TimePtr)); static int LookupWord _ANSI_ARGS_((char *buff)); -static int TclDatelex _ANSI_ARGS_((void)); +static int TclDatelex _ANSI_ARGS_((void* info)); @@ -253,13 +263,13 @@ static int TclDatelex _ANSI_ARGS_((void)); #endif #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 150 "../unix/../generic/tclGetDate.y" +#line 160 "..\\generic/tclGetDate.y" typedef union YYSTYPE { time_t Number; enum _MERIDIAN Meridian; } YYSTYPE; /* Line 191 of yacc.c. */ -#line 262 "../unix/../generic/tclDate.c" +#line 273 "..\\generic/tclDate.c" # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 @@ -271,7 +281,7 @@ typedef union YYSTYPE { /* Line 214 of yacc.c. */ -#line 274 "../unix/../generic/tclDate.c" +#line 285 "..\\generic/tclDate.c" #if ! defined (yyoverflow) || YYERROR_VERBOSE @@ -460,12 +470,12 @@ static const yysigned_char yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short yyrline[] = { - 0, 166, 166, 167, 170, 173, 176, 179, 182, 185, - 188, 192, 197, 200, 206, 212, 219, 225, 235, 239, - 243, 249, 253, 257, 261, 265, 271, 275, 280, 285, - 290, 295, 299, 304, 308, 313, 320, 324, 330, 339, - 348, 358, 371, 376, 378, 379, 380, 381, 382, 384, - 385, 387, 388, 389, 392, 411, 414 + 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, 383, 388, 390, 391, 392, 393, 394, 396, + 397, 399, 400, 401, 404, 423, 426 }; #endif @@ -632,6 +642,7 @@ static const unsigned char yystos[] = #define YYABORT goto yyabortlab #define YYERROR goto yyerrlab1 + /* 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. */ @@ -752,9 +763,9 @@ yy_reduce_print (yyrule) #endif { int yyi; - unsigned int yylineno = yyrline[yyrule]; + unsigned int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylineno); + yyrule - 1, yylno); /* Print the symbols being reduced, and their result. */ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); @@ -1214,49 +1225,49 @@ yyreduce: switch (yyn) { case 4: -#line 170 "../unix/../generic/tclGetDate.y" +#line 180 "..\\generic/tclGetDate.y" { yyHaveTime++; ;} break; case 5: -#line 173 "../unix/../generic/tclGetDate.y" +#line 183 "..\\generic/tclGetDate.y" { yyHaveZone++; ;} break; case 6: -#line 176 "../unix/../generic/tclGetDate.y" +#line 186 "..\\generic/tclGetDate.y" { yyHaveDate++; ;} break; case 7: -#line 179 "../unix/../generic/tclGetDate.y" +#line 189 "..\\generic/tclGetDate.y" { yyHaveOrdinalMonth++; ;} break; case 8: -#line 182 "../unix/../generic/tclGetDate.y" +#line 192 "..\\generic/tclGetDate.y" { yyHaveDay++; ;} break; case 9: -#line 185 "../unix/../generic/tclGetDate.y" +#line 195 "..\\generic/tclGetDate.y" { yyHaveRel++; ;} break; case 10: -#line 188 "../unix/../generic/tclGetDate.y" +#line 198 "..\\generic/tclGetDate.y" { yyHaveTime++; yyHaveDate++; @@ -1264,7 +1275,7 @@ yyreduce: break; case 11: -#line 192 "../unix/../generic/tclGetDate.y" +#line 202 "..\\generic/tclGetDate.y" { yyHaveTime++; yyHaveDate++; @@ -1273,7 +1284,7 @@ yyreduce: break; case 13: -#line 200 "../unix/../generic/tclGetDate.y" +#line 210 "..\\generic/tclGetDate.y" { yyHour = yyvsp[-1].Number; yyMinutes = 0; @@ -1283,7 +1294,7 @@ yyreduce: break; case 14: -#line 206 "../unix/../generic/tclGetDate.y" +#line 216 "..\\generic/tclGetDate.y" { yyHour = yyvsp[-3].Number; yyMinutes = yyvsp[-1].Number; @@ -1293,18 +1304,19 @@ yyreduce: break; case 15: -#line 212 "../unix/../generic/tclGetDate.y" +#line 222 "..\\generic/tclGetDate.y" { yyHour = yyvsp[-4].Number; yyMinutes = yyvsp[-2].Number; yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + ++yyHaveZone; ;} break; case 16: -#line 219 "../unix/../generic/tclGetDate.y" +#line 230 "..\\generic/tclGetDate.y" { yyHour = yyvsp[-5].Number; yyMinutes = yyvsp[-3].Number; @@ -1314,7 +1326,7 @@ yyreduce: break; case 17: -#line 225 "../unix/../generic/tclGetDate.y" +#line 236 "..\\generic/tclGetDate.y" { yyHour = yyvsp[-6].Number; yyMinutes = yyvsp[-4].Number; @@ -1322,11 +1334,12 @@ yyreduce: yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + ++yyHaveZone; ;} break; case 18: -#line 235 "../unix/../generic/tclGetDate.y" +#line 247 "..\\generic/tclGetDate.y" { yyTimezone = yyvsp[-1].Number; yyDSTmode = DSTon; @@ -1334,7 +1347,7 @@ yyreduce: break; case 19: -#line 239 "../unix/../generic/tclGetDate.y" +#line 251 "..\\generic/tclGetDate.y" { yyTimezone = yyvsp[0].Number; yyDSTmode = DSToff; @@ -1342,7 +1355,7 @@ yyreduce: break; case 20: -#line 243 "../unix/../generic/tclGetDate.y" +#line 255 "..\\generic/tclGetDate.y" { yyTimezone = yyvsp[0].Number; yyDSTmode = DSTon; @@ -1350,7 +1363,7 @@ yyreduce: break; case 21: -#line 249 "../unix/../generic/tclGetDate.y" +#line 261 "..\\generic/tclGetDate.y" { yyDayOrdinal = 1; yyDayNumber = yyvsp[0].Number; @@ -1358,7 +1371,7 @@ yyreduce: break; case 22: -#line 253 "../unix/../generic/tclGetDate.y" +#line 265 "..\\generic/tclGetDate.y" { yyDayOrdinal = 1; yyDayNumber = yyvsp[-1].Number; @@ -1366,7 +1379,7 @@ yyreduce: break; case 23: -#line 257 "../unix/../generic/tclGetDate.y" +#line 269 "..\\generic/tclGetDate.y" { yyDayOrdinal = yyvsp[-1].Number; yyDayNumber = yyvsp[0].Number; @@ -1374,7 +1387,7 @@ yyreduce: break; case 24: -#line 261 "../unix/../generic/tclGetDate.y" +#line 273 "..\\generic/tclGetDate.y" { yyDayOrdinal = yyvsp[-2].Number * yyvsp[-1].Number; yyDayNumber = yyvsp[0].Number; @@ -1382,7 +1395,7 @@ yyreduce: break; case 25: -#line 265 "../unix/../generic/tclGetDate.y" +#line 277 "..\\generic/tclGetDate.y" { yyDayOrdinal = 2; yyDayNumber = yyvsp[0].Number; @@ -1390,7 +1403,7 @@ yyreduce: break; case 26: -#line 271 "../unix/../generic/tclGetDate.y" +#line 283 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-2].Number; yyDay = yyvsp[0].Number; @@ -1398,7 +1411,7 @@ yyreduce: break; case 27: -#line 275 "../unix/../generic/tclGetDate.y" +#line 287 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-4].Number; yyDay = yyvsp[-2].Number; @@ -1407,7 +1420,7 @@ yyreduce: break; case 28: -#line 280 "../unix/../generic/tclGetDate.y" +#line 292 "..\\generic/tclGetDate.y" { yyYear = yyvsp[0].Number / 10000; yyMonth = (yyvsp[0].Number % 10000)/100; @@ -1416,7 +1429,7 @@ yyreduce: break; case 29: -#line 285 "../unix/../generic/tclGetDate.y" +#line 297 "..\\generic/tclGetDate.y" { yyDay = yyvsp[-4].Number; yyMonth = yyvsp[-2].Number; @@ -1425,7 +1438,7 @@ yyreduce: break; case 30: -#line 290 "../unix/../generic/tclGetDate.y" +#line 302 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-2].Number; yyDay = yyvsp[0].Number; @@ -1434,7 +1447,7 @@ yyreduce: break; case 31: -#line 295 "../unix/../generic/tclGetDate.y" +#line 307 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-1].Number; yyDay = yyvsp[0].Number; @@ -1442,7 +1455,7 @@ yyreduce: break; case 32: -#line 299 "../unix/../generic/tclGetDate.y" +#line 311 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-3].Number; yyDay = yyvsp[-2].Number; @@ -1451,7 +1464,7 @@ yyreduce: break; case 33: -#line 304 "../unix/../generic/tclGetDate.y" +#line 316 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[0].Number; yyDay = yyvsp[-1].Number; @@ -1459,7 +1472,7 @@ yyreduce: break; case 34: -#line 308 "../unix/../generic/tclGetDate.y" +#line 320 "..\\generic/tclGetDate.y" { yyMonth = 1; yyDay = 1; @@ -1468,7 +1481,7 @@ yyreduce: break; case 35: -#line 313 "../unix/../generic/tclGetDate.y" +#line 325 "..\\generic/tclGetDate.y" { yyMonth = yyvsp[-1].Number; yyDay = yyvsp[-2].Number; @@ -1477,7 +1490,7 @@ yyreduce: break; case 36: -#line 320 "../unix/../generic/tclGetDate.y" +#line 332 "..\\generic/tclGetDate.y" { yyMonthOrdinal = 1; yyMonth = yyvsp[0].Number; @@ -1485,7 +1498,7 @@ yyreduce: break; case 37: -#line 324 "../unix/../generic/tclGetDate.y" +#line 336 "..\\generic/tclGetDate.y" { yyMonthOrdinal = yyvsp[-1].Number; yyMonth = yyvsp[0].Number; @@ -1493,7 +1506,7 @@ yyreduce: break; case 38: -#line 330 "../unix/../generic/tclGetDate.y" +#line 342 "..\\generic/tclGetDate.y" { if (yyvsp[-1].Number != HOUR(- 7)) YYABORT; yyYear = yyvsp[-2].Number / 10000; @@ -1506,7 +1519,7 @@ yyreduce: break; case 39: -#line 339 "../unix/../generic/tclGetDate.y" +#line 351 "..\\generic/tclGetDate.y" { if (yyvsp[-5].Number != HOUR(- 7)) YYABORT; yyYear = yyvsp[-6].Number / 10000; @@ -1519,7 +1532,7 @@ yyreduce: break; case 40: -#line 348 "../unix/../generic/tclGetDate.y" +#line 360 "..\\generic/tclGetDate.y" { yyYear = yyvsp[-1].Number / 10000; yyMonth = (yyvsp[-1].Number % 10000)/100; @@ -1531,7 +1544,7 @@ yyreduce: break; case 41: -#line 358 "../unix/../generic/tclGetDate.y" +#line 370 "..\\generic/tclGetDate.y" { /* * Offset computed year by -377 so that the returned years will @@ -1546,7 +1559,7 @@ yyreduce: break; case 42: -#line 371 "../unix/../generic/tclGetDate.y" +#line 383 "..\\generic/tclGetDate.y" { yyRelSeconds *= -1; yyRelMonth *= -1; @@ -1555,57 +1568,57 @@ yyreduce: break; case 44: -#line 378 "../unix/../generic/tclGetDate.y" +#line 390 "..\\generic/tclGetDate.y" { *yyRelPointer += yyvsp[-2].Number * yyvsp[-1].Number * yyvsp[0].Number; ;} break; case 45: -#line 379 "../unix/../generic/tclGetDate.y" +#line 391 "..\\generic/tclGetDate.y" { *yyRelPointer += yyvsp[-1].Number * yyvsp[0].Number; ;} break; case 46: -#line 380 "../unix/../generic/tclGetDate.y" +#line 392 "..\\generic/tclGetDate.y" { *yyRelPointer += yyvsp[0].Number; ;} break; case 47: -#line 381 "../unix/../generic/tclGetDate.y" +#line 393 "..\\generic/tclGetDate.y" { *yyRelPointer += yyvsp[-1].Number * yyvsp[0].Number; ;} break; case 48: -#line 382 "../unix/../generic/tclGetDate.y" +#line 394 "..\\generic/tclGetDate.y" { *yyRelPointer += yyvsp[0].Number; ;} break; case 49: -#line 384 "../unix/../generic/tclGetDate.y" +#line 396 "..\\generic/tclGetDate.y" { yyval.Number = -1; ;} break; case 50: -#line 385 "../unix/../generic/tclGetDate.y" +#line 397 "..\\generic/tclGetDate.y" { yyval.Number = 1; ;} break; case 51: -#line 387 "../unix/../generic/tclGetDate.y" +#line 399 "..\\generic/tclGetDate.y" { yyval.Number = yyvsp[0].Number; yyRelPointer = &yyRelSeconds; ;} break; case 52: -#line 388 "../unix/../generic/tclGetDate.y" +#line 400 "..\\generic/tclGetDate.y" { yyval.Number = yyvsp[0].Number; yyRelPointer = &yyRelDay; ;} break; case 53: -#line 389 "../unix/../generic/tclGetDate.y" +#line 401 "..\\generic/tclGetDate.y" { yyval.Number = yyvsp[0].Number; yyRelPointer = &yyRelMonth; ;} break; case 54: -#line 393 "../unix/../generic/tclGetDate.y" +#line 405 "..\\generic/tclGetDate.y" { if (yyHaveTime && yyHaveDate && !yyHaveRel) { yyYear = yyvsp[0].Number; @@ -1625,14 +1638,14 @@ yyreduce: break; case 55: -#line 411 "../unix/../generic/tclGetDate.y" +#line 423 "..\\generic/tclGetDate.y" { yyval.Meridian = MER24; ;} break; case 56: -#line 414 "../unix/../generic/tclGetDate.y" +#line 426 "..\\generic/tclGetDate.y" { yyval.Meridian = yyvsp[0].Meridian; ;} @@ -1641,8 +1654,8 @@ yyreduce: } -/* Line 991 of yacc.c. */ -#line 1645 "../unix/../generic/tclDate.c" +/* Line 999 of yacc.c. */ +#line 1659 "..\\generic/tclDate.c" yyvsp -= yylen; yyssp -= yylen; @@ -1683,18 +1696,33 @@ yyerrlab: { YYSIZE_T yysize = 0; int yytype = YYTRANSLATE (yychar); + const char* yyprefix; char *yymsg; - int yyx, yycount; + int yyx; - yycount = 0; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 0; + + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("syntax error, unexpected ") + 1; - yysize += yystrlen (yytname[yytype]); + { + yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); + yycount += 1; + if (yycount == 5) + { + yysize = 0; + break; + } + } + yysize += (sizeof ("syntax error, unexpected ") + + yystrlen (yytname[yytype])); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { @@ -1703,16 +1731,13 @@ yyerrlab: if (yycount < 5) { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yyprefix); yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; + yyprefix = " or "; } } yyerror (yymsg); @@ -1756,30 +1781,13 @@ yyerrlab: /* Else will try to reuse lookahead token after shifting the error token. */ - goto yyerrlab2; + goto yyerrlab1; /*----------------------------------------------------. | yyerrlab1 -- error raised explicitly by an action. | `----------------------------------------------------*/ yyerrlab1: - - /* Suppress GCC warning that yyerrlab1 is unused when no action - invokes YYERROR. Doesn't work in C++ */ -#ifndef __cplusplus -#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) - __attribute__ ((__unused__)) -#endif -#endif - - - goto yyerrlab2; - - -/*---------------------------------------------------------------. -| yyerrlab2 -- pop states until the error token can be shifted. | -`---------------------------------------------------------------*/ -yyerrlab2: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) @@ -1853,7 +1861,7 @@ yyreturn: } -#line 419 "../unix/../generic/tclGetDate.y" +#line 431 "..\\generic/tclGetDate.y" /* @@ -2059,7 +2067,6 @@ TclDateerror(s) { } - static time_t ToSeconds(Hours, Minutes, Seconds, Meridian) time_t Hours; @@ -2086,238 +2093,6 @@ ToSeconds(Hours, Minutes, Seconds, Meridian) return -1; /* Should never be reached */ } -/* - *----------------------------------------------------------------------------- - * - * Convert -- - * - * Convert a {month, day, year, hours, minutes, seconds, meridian, dst} - * tuple into a clock seconds value. - * - * Results: - * 0 or -1 indicating success or failure. - * - * Side effects: - * Fills TimePtr with the computed value. - * - *----------------------------------------------------------------------------- - */ -static int -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr, info) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE DSTmode; - time_t *TimePtr; - VOID* info; -{ - static int DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t tod; - time_t Julian; - int i; - - /* Figure out how many days are in February for the given year. - * Every year divisible by 4 is a leap year. - * But, every year divisible by 100 is not a leap year. - * But, every year divisible by 400 is a leap year after all. - */ - DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28; - - /* Check the inputs for validity */ - if (Month < 1 || Month > 12 - || Year < START_OF_TIME || Year > END_OF_TIME - || Day < 1 || Day > DaysInMonth[(int)--Month]) - return -1; - - /* Start computing the value. First determine the number of days - * represented by the date, then multiply by the number of seconds/day. - */ - for (Julian = Day - 1, i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - if (Year >= EPOCH) { - for (i = EPOCH; i < Year; i++) - Julian += 365 + IsLeapYear(i); - } else { - for (i = Year; i < EPOCH; i++) - Julian -= 365 + IsLeapYear(i); - } - Julian *= SECSPERDAY; - - /* Add the timezone offset ?? */ - Julian += yyTimezone * 60L; - - /* Add the number of seconds represented by the time component */ - if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) - return -1; - Julian += tod; - - /* Perform a preliminary DST compensation ?? */ - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && TclpGetDate(&Julian, 0)->tm_isdst)) - Julian -= 60 * 60; - *TimePtr = Julian; - return 0; -} - - -static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; -{ - time_t StartDay; - time_t FutureDay; - StartDay = (TclpGetDate(&Start, 0)->tm_hour + 1) % 24; - FutureDay = (TclpGetDate(&Future, 0)->tm_hour + 1) % 24; - return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; -} - - -static time_t -NamedDay(Start, DayOrdinal, DayNumber) - time_t Start; - time_t DayOrdinal; - time_t DayNumber; -{ - struct tm *tm; - time_t now; - - now = Start; - tm = TclpGetDate(&now, 0); - now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - return DSTcorrect(Start, now); -} - -static time_t -NamedMonth(Start, MonthOrdinal, MonthNumber, info) - time_t Start; - time_t MonthOrdinal; - time_t MonthNumber; - VOID* info; -{ - struct tm *tm; - time_t now; - int result; - - now = Start; - tm = TclpGetDate(&now, 0); - /* To compute the next n'th month, we use this alg: - * add n to year value - * if currentMonth < requestedMonth decrement year value by 1 (so that - * doing next february from january gives us february of the current year) - * set day to 1, time to 0 - */ - tm->tm_year += MonthOrdinal; - if (tm->tm_mon < MonthNumber - 1) { - tm->tm_year--; - } - result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE, - (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now, info); - if (result < 0) { - return 0; - } - return DSTcorrect(Start, now); -} - -static int -RelativeMonth(Start, RelMonth, TimePtr, info) - time_t Start; - time_t RelMonth; - time_t *TimePtr; - VOID* info; -{ - struct tm *tm; - time_t Month; - time_t Year; - time_t Julian; - int result; - - if (RelMonth == 0) { - *TimePtr = 0; - return 0; - } - tm = TclpGetDate(&Start, 0); - Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth; - Year = Month / 12; - Month = Month % 12 + 1; - result = Convert(Month, (time_t) tm->tm_mday, Year, - (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, - MER24, DSTmaybe, &Julian, info); - - /* - * The Julian time returned above is behind by one day, if "month" - * or "year" is used to specify relative time and the GMT flag is true. - * This problem occurs only when the current time is closer to - * midnight, the difference being not more than its time difference - * with GMT. For example, in US/Pacific time zone, the problem occurs - * whenever the current time is between midnight to 8:00am or 7:00amDST. - * See Bug# 413397 for more details and sample script. - * To resolve this bug, we simply add the number of seconds corresponding - * to timezone difference with GMT to Julian time, if GMT flag is true. - */ - - if (yyTimezone == 0) { - Julian += TclpGetTimeZone((unsigned long) Start) * 60L; - } - - /* - * The following iteration takes into account the case were we jump - * into a "short month". Far example, "one month from Jan 31" will - * fail because there is no Feb 31. The code below will reduce the - * day and try converting the date until we succed or the date equals - * 28 (which always works unless the date is bad in another way). - */ - - while ((result != 0) && (tm->tm_mday > 28)) { - tm->tm_mday--; - result = Convert(Month, (time_t) tm->tm_mday, Year, - (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, - MER24, DSTmaybe, &Julian, info); - } - if (result != 0) { - return -1; - } - *TimePtr = DSTcorrect(Start, Julian); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * RelativeDay -- - * - * Given a starting time and a number of days before or after, compute the - * DST corrected difference between those dates. - * - * Results: - * 1 or -1 indicating success or failure. - * - * Side effects: - * Fills TimePtr with the computed value. - * - *----------------------------------------------------------------------------- - */ - -static int -RelativeDay(Start, RelDay, TimePtr) - time_t Start; - time_t RelDay; - time_t *TimePtr; -{ - time_t new; - - new = Start + (RelDay * 60 * 60 * 24); - *TimePtr = DSTcorrect(Start, new); - return 1; -} static int LookupWord(buff) @@ -2438,9 +2213,8 @@ LookupWord(buff) return tID; } - static int -TclDatelex() +TclDatelex( void* info ) { register char c; register char *p; @@ -2496,118 +2270,149 @@ TclDatelex() } } -/* - * Specify zone is of -50000 to force GMT. (This allows BST to work). - */ - int -TclGetDate(p, now, zone, timePtr) - char *p; - unsigned long now; - long zone; - unsigned long *timePtr; +TclClockOldscanObjCmd( clientData, interp, objc, objv ) + ClientData clientData; /* Unused */ + Tcl_Interp* interp; /* Tcl interpreter */ + int objc; /* Count of paraneters */ + Tcl_Obj *CONST *objv; /* Parameters */ { - struct tm *tm; - time_t Start; - time_t Time; - time_t tod; - int thisyear; - TclGetDateInfo dateInfo; + Tcl_Obj* result; + Tcl_Obj* resultElement; + int yr, mo, da; + DateInfo dateInfo; void* info = (void*) &dateInfo; - yyInput = p; - /* now has to be cast to a time_t for 64bit compliance */ - Start = now; - tm = TclpGetDate(&Start, (zone == -50000)); - thisyear = tm->tm_year + TM_YEAR_BASE; - yyYear = thisyear; - yyMonth = tm->tm_mon + 1; - yyDay = tm->tm_mday; - yyTimezone = zone; - if (zone == -50000) { - yyDSTmode = DSToff; /* assume GMT */ - yyTimezone = 0; - } else { - yyDSTmode = DSTmaybe; + if ( objc != 5 ) { + Tcl_WrongNumArgs( interp, 1, objv, + "stringToParse baseYear baseMonth baseDay" ); + return TCL_ERROR; } - yyHour = 0; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = MER24; - yyRelSeconds = 0; - yyRelMonth = 0; - yyRelDay = 0; - yyRelPointer = NULL; + + yyInput = Tcl_GetString( objv[1] ); yyHaveDate = 0; - yyHaveDay = 0; - yyHaveOrdinalMonth = 0; - yyHaveRel = 0; + if ( Tcl_GetIntFromObj( interp, objv[2], &yr ) != TCL_OK + || Tcl_GetIntFromObj( interp, objv[3], &mo ) != TCL_OK + || Tcl_GetIntFromObj( interp, objv[4], &da ) != TCL_OK ) { + return TCL_ERROR; + } + yyYear = yr; yyMonth = mo; yyDay = da; + yyHaveTime = 0; + yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; + yyHaveZone = 0; + yyTimezone = 0; yyDSTmode = DSTmaybe; - if (yyparse(info) || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || - yyHaveDay > 1 || yyHaveOrdinalMonth > 1) { - return -1; + yyHaveOrdinalMonth = 0; + yyMonthOrdinal = 0; + + yyHaveDay = 0; + yyDayOrdinal = 0; yyDayNumber = 0; + + yyHaveRel = 0; + yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; + + if ( yyparse( info ) ) { + Tcl_SetObjResult( interp, Tcl_NewStringObj( "syntax error", -1 ) ); + return TCL_ERROR; } - - if (yyHaveDate || yyHaveTime || yyHaveDay) { - if (yyYear < 0) { - yyYear = -yyYear; - } - /* - * The following line handles years that are specified using - * only two digits. The line of code below implements a policy - * defined by the X/Open workgroup on the millinium rollover. - * Note: some of those dates may not actually be valid on some - * platforms. The POSIX standard startes that the dates 70-99 - * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038. - * This later definition should work on all platforms. - */ - - if (yyYear < 100) { - if (yyYear >= 69) { - yyYear += 1900; - } else { - yyYear += 2000; - } - } - if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, - yyMeridian, yyDSTmode, &Start, info) < 0) { - return -1; - } + + if ( yyHaveDate > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one date in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveTime > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one time of day in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveZone > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one time zone in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveDay > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one weekday in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveOrdinalMonth > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one ordinal month in string", -1 ) ); + return TCL_ERROR; + } + + result = Tcl_NewObj(); + resultElement = Tcl_NewObj(); + if ( yyHaveDate ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyYear ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonth ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDay ) ); + } + Tcl_ListObjAppendElement( interp, result, resultElement ); + + if ( yyHaveTime ) { + Tcl_ListObjAppendElement( interp, result, + Tcl_NewIntObj( ToSeconds( yyHour, + yyMinutes, + yySeconds, + yyMeridian ) ) ); } else { - Start = now; - if (!yyHaveRel) { - Start -= ((tm->tm_hour * 60L * 60L) + - tm->tm_min * 60L) + tm->tm_sec; - } + Tcl_ListObjAppendElement( interp, result, Tcl_NewObj() ); } - Start += yyRelSeconds; - if (RelativeMonth(Start, yyRelMonth, &Time, info) < 0) { - return -1; + resultElement = Tcl_NewObj(); + if ( yyHaveZone ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( -yyTimezone ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( 1-yyDSTmode ) ); } - Start += Time; - - if (RelativeDay(Start, yyRelDay, &Time) < 0) { - return -1; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveRel ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelMonth ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelDay ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelSeconds ) ); } - Start += Time; - - if (yyHaveDay && !yyHaveDate) { - tod = NamedDay(Start, yyDayOrdinal, yyDayNumber); - Start += tod; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveDay && !yyHaveDate ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDayOrdinal ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDayNumber ) ); } - - if (yyHaveOrdinalMonth) { - tod = NamedMonth(Start, yyMonthOrdinal, yyMonth, info); - Start += tod; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveOrdinalMonth ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonthOrdinal ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonth ) ); } - - *timePtr = Start; - return 0; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + Tcl_SetObjResult( interp, result ); + return TCL_OK; } diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 7dfd205..3d04714 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclGetDate.y,v 1.24 2004/09/17 22:06:24 kennykb Exp $ + * RCS: @(#) $Id: tclGetDate.y,v 1.25 2004/09/27 14:31:17 kennykb Exp $ */ %{ @@ -27,9 +27,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCSID */ +#include "tclInt.h" + /* * Bison generates several labels that happen to be unused. MS Visual * C++ doesn't like that, and complains. Tell it to shut up. @@ -40,35 +41,70 @@ #endif /* _MSC_VER */ /* - * yyparse will accept a 'struct TclGetDateInfo' as its parameter; + * yyparse will accept a 'struct DateInfo' as its parameter; * that's where the parsed fields will be returned. */ -#define YYPARSE_PARAM info +typedef struct DateInfo { -#define yyDSTmode (((TclGetDateInfo*)info)->dateDSTmode) -#define yyDayOrdinal (((TclGetDateInfo*)info)->dateDayOrdinal) -#define yyDayNumber (((TclGetDateInfo*)info)->dateDayNumber) -#define yyMonthOrdinal (((TclGetDateInfo*)info)->dateMonthOrdinal) -#define yyHaveDate (((TclGetDateInfo*)info)->dateHaveDate) -#define yyHaveDay (((TclGetDateInfo*)info)->dateHaveDay) -#define yyHaveOrdinalMonth (((TclGetDateInfo*)info)->dateHaveOrdinalMonth) -#define yyHaveRel (((TclGetDateInfo*)info)->dateHaveRel) -#define yyHaveTime (((TclGetDateInfo*)info)->dateHaveTime) -#define yyHaveZone (((TclGetDateInfo*)info)->dateHaveZone) -#define yyTimezone (((TclGetDateInfo*)info)->dateTimezone) -#define yyDay (((TclGetDateInfo*)info)->dateDay) -#define yyMonth (((TclGetDateInfo*)info)->dateMonth) -#define yyYear (((TclGetDateInfo*)info)->dateYear) -#define yyHour (((TclGetDateInfo*)info)->dateHour) -#define yyMinutes (((TclGetDateInfo*)info)->dateMinutes) -#define yySeconds (((TclGetDateInfo*)info)->dateSeconds) -#define yyMeridian (((TclGetDateInfo*)info)->dateMeridian) -#define yyRelMonth (((TclGetDateInfo*)info)->dateRelMonth) -#define yyRelDay (((TclGetDateInfo*)info)->dateRelDay) -#define yyRelSeconds (((TclGetDateInfo*)info)->dateRelSeconds) + time_t dateYear; + time_t dateMonth; + time_t dateDay; + int dateHaveDate; -#include "tclInt.h" + 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; + + char *dateInput; + time_t *dateRelPointer; + +} DateInfo; + +#define YYPARSE_PARAM info +#define YYLEX_PARAM info + +#define yyDSTmode (((DateInfo*)info)->dateDSTmode) +#define yyDayOrdinal (((DateInfo*)info)->dateDayOrdinal) +#define yyDayNumber (((DateInfo*)info)->dateDayNumber) +#define yyMonthOrdinal (((DateInfo*)info)->dateMonthOrdinal) +#define yyHaveDate (((DateInfo*)info)->dateHaveDate) +#define yyHaveDay (((DateInfo*)info)->dateHaveDay) +#define yyHaveOrdinalMonth (((DateInfo*)info)->dateHaveOrdinalMonth) +#define yyHaveRel (((DateInfo*)info)->dateHaveRel) +#define yyHaveTime (((DateInfo*)info)->dateHaveTime) +#define yyHaveZone (((DateInfo*)info)->dateHaveZone) +#define yyTimezone (((DateInfo*)info)->dateTimezone) +#define yyDay (((DateInfo*)info)->dateDay) +#define yyMonth (((DateInfo*)info)->dateMonth) +#define yyYear (((DateInfo*)info)->dateYear) +#define yyHour (((DateInfo*)info)->dateHour) +#define yyMinutes (((DateInfo*)info)->dateMinutes) +#define yySeconds (((DateInfo*)info)->dateSeconds) +#define yyMeridian (((DateInfo*)info)->dateMeridian) +#define yyRelMonth (((DateInfo*)info)->dateRelMonth) +#define yyRelDay (((DateInfo*)info)->dateRelDay) +#define yyRelSeconds (((DateInfo*)info)->dateRelSeconds) +#define yyRelPointer (((DateInfo*)info)->dateRelPointer) +#define yyInput (((DateInfo*)info)->dateInput) #define EPOCH 1970 #define START_OF_TIME 1902 @@ -76,10 +112,7 @@ /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. - * I don't know how universal this is; K&R II, the NetBSD manpages, and - * ../compat/strftime.c all agree that tm_year is the year-1900. However, - * some systems may have a different value. This #define should be the - * same as in ../compat/strftime.c. + * Posix requires 1900. */ #define TM_YEAR_BASE 1900 @@ -113,36 +146,13 @@ typedef enum _MERIDIAN { /* - * Global variables. We could get rid of most of these by using a good - * union as the yacc stack. (This routine was originally written before - * yacc had the %union construct.) Maybe someday; right now we only use - * the %union very rarely. - */ - -static char *yyInput; -static time_t *yyRelPointer; - -/* * Prototypes of internal functions. */ static void TclDateerror _ANSI_ARGS_((char *s)); static time_t ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)); -static int Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year, - time_t Hours, time_t Minutes, time_t Seconds, - MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr, - VOID* info)); -static time_t DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future)); -static time_t NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal, - time_t DayNumber)); -static time_t NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal, - time_t MonthNumber, VOID* info)); -static int RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth, - time_t *TimePtr, VOID* info)); -static int RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay, - time_t *TimePtr)); static int LookupWord _ANSI_ARGS_((char *buff)); -static int TclDatelex _ANSI_ARGS_((void)); +static int TclDatelex _ANSI_ARGS_((void* info)); %} @@ -215,6 +225,7 @@ time : tUNUMBER tMERIDIAN { yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = ($5 % 100 + ($5 / 100) * 60); + ++yyHaveZone; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; @@ -229,6 +240,7 @@ time : tUNUMBER tMERIDIAN { yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = ($7 % 100 + ($7 / 100) * 60); + ++yyHaveZone; } ; @@ -621,7 +633,6 @@ TclDateerror(s) { } - static time_t ToSeconds(Hours, Minutes, Seconds, Meridian) time_t Hours; @@ -648,238 +659,6 @@ ToSeconds(Hours, Minutes, Seconds, Meridian) return -1; /* Should never be reached */ } -/* - *----------------------------------------------------------------------------- - * - * Convert -- - * - * Convert a {month, day, year, hours, minutes, seconds, meridian, dst} - * tuple into a clock seconds value. - * - * Results: - * 0 or -1 indicating success or failure. - * - * Side effects: - * Fills TimePtr with the computed value. - * - *----------------------------------------------------------------------------- - */ -static int -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr, info) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE DSTmode; - time_t *TimePtr; - VOID* info; -{ - static int DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t tod; - time_t Julian; - int i; - - /* Figure out how many days are in February for the given year. - * Every year divisible by 4 is a leap year. - * But, every year divisible by 100 is not a leap year. - * But, every year divisible by 400 is a leap year after all. - */ - DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28; - - /* Check the inputs for validity */ - if (Month < 1 || Month > 12 - || Year < START_OF_TIME || Year > END_OF_TIME - || Day < 1 || Day > DaysInMonth[(int)--Month]) - return -1; - - /* Start computing the value. First determine the number of days - * represented by the date, then multiply by the number of seconds/day. - */ - for (Julian = Day - 1, i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - if (Year >= EPOCH) { - for (i = EPOCH; i < Year; i++) - Julian += 365 + IsLeapYear(i); - } else { - for (i = Year; i < EPOCH; i++) - Julian -= 365 + IsLeapYear(i); - } - Julian *= SECSPERDAY; - - /* Add the timezone offset ?? */ - Julian += yyTimezone * 60L; - - /* Add the number of seconds represented by the time component */ - if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) - return -1; - Julian += tod; - - /* Perform a preliminary DST compensation ?? */ - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && TclpGetDate(&Julian, 0)->tm_isdst)) - Julian -= 60 * 60; - *TimePtr = Julian; - return 0; -} - - -static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; -{ - time_t StartDay; - time_t FutureDay; - StartDay = (TclpGetDate(&Start, 0)->tm_hour + 1) % 24; - FutureDay = (TclpGetDate(&Future, 0)->tm_hour + 1) % 24; - return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; -} - - -static time_t -NamedDay(Start, DayOrdinal, DayNumber) - time_t Start; - time_t DayOrdinal; - time_t DayNumber; -{ - struct tm *tm; - time_t now; - - now = Start; - tm = TclpGetDate(&now, 0); - now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - return DSTcorrect(Start, now); -} - -static time_t -NamedMonth(Start, MonthOrdinal, MonthNumber, info) - time_t Start; - time_t MonthOrdinal; - time_t MonthNumber; - VOID* info; -{ - struct tm *tm; - time_t now; - int result; - - now = Start; - tm = TclpGetDate(&now, 0); - /* To compute the next n'th month, we use this alg: - * add n to year value - * if currentMonth < requestedMonth decrement year value by 1 (so that - * doing next february from january gives us february of the current year) - * set day to 1, time to 0 - */ - tm->tm_year += MonthOrdinal; - if (tm->tm_mon < MonthNumber - 1) { - tm->tm_year--; - } - result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE, - (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now, info); - if (result < 0) { - return 0; - } - return DSTcorrect(Start, now); -} - -static int -RelativeMonth(Start, RelMonth, TimePtr, info) - time_t Start; - time_t RelMonth; - time_t *TimePtr; - VOID* info; -{ - struct tm *tm; - time_t Month; - time_t Year; - time_t Julian; - int result; - - if (RelMonth == 0) { - *TimePtr = 0; - return 0; - } - tm = TclpGetDate(&Start, 0); - Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth; - Year = Month / 12; - Month = Month % 12 + 1; - result = Convert(Month, (time_t) tm->tm_mday, Year, - (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, - MER24, DSTmaybe, &Julian, info); - - /* - * The Julian time returned above is behind by one day, if "month" - * or "year" is used to specify relative time and the GMT flag is true. - * This problem occurs only when the current time is closer to - * midnight, the difference being not more than its time difference - * with GMT. For example, in US/Pacific time zone, the problem occurs - * whenever the current time is between midnight to 8:00am or 7:00amDST. - * See Bug# 413397 for more details and sample script. - * To resolve this bug, we simply add the number of seconds corresponding - * to timezone difference with GMT to Julian time, if GMT flag is true. - */ - - if (yyTimezone == 0) { - Julian += TclpGetTimeZone((unsigned long) Start) * 60L; - } - - /* - * The following iteration takes into account the case were we jump - * into a "short month". Far example, "one month from Jan 31" will - * fail because there is no Feb 31. The code below will reduce the - * day and try converting the date until we succed or the date equals - * 28 (which always works unless the date is bad in another way). - */ - - while ((result != 0) && (tm->tm_mday > 28)) { - tm->tm_mday--; - result = Convert(Month, (time_t) tm->tm_mday, Year, - (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, - MER24, DSTmaybe, &Julian, info); - } - if (result != 0) { - return -1; - } - *TimePtr = DSTcorrect(Start, Julian); - return 0; -} - - -/* - *----------------------------------------------------------------------------- - * - * RelativeDay -- - * - * Given a starting time and a number of days before or after, compute the - * DST corrected difference between those dates. - * - * Results: - * 1 or -1 indicating success or failure. - * - * Side effects: - * Fills TimePtr with the computed value. - * - *----------------------------------------------------------------------------- - */ - -static int -RelativeDay(Start, RelDay, TimePtr) - time_t Start; - time_t RelDay; - time_t *TimePtr; -{ - time_t new; - - new = Start + (RelDay * 60 * 60 * 24); - *TimePtr = DSTcorrect(Start, new); - return 1; -} static int LookupWord(buff) @@ -1000,9 +779,8 @@ LookupWord(buff) return tID; } - static int -TclDatelex() +TclDatelex( void* info ) { register char c; register char *p; @@ -1058,116 +836,147 @@ TclDatelex() } } -/* - * Specify zone is of -50000 to force GMT. (This allows BST to work). - */ - int -TclGetDate(p, now, zone, timePtr) - char *p; - unsigned long now; - long zone; - unsigned long *timePtr; +TclClockOldscanObjCmd( clientData, interp, objc, objv ) + ClientData clientData; /* Unused */ + Tcl_Interp* interp; /* Tcl interpreter */ + int objc; /* Count of paraneters */ + Tcl_Obj *CONST *objv; /* Parameters */ { - struct tm *tm; - time_t Start; - time_t Time; - time_t tod; - int thisyear; - TclGetDateInfo dateInfo; + Tcl_Obj* result; + Tcl_Obj* resultElement; + int yr, mo, da; + DateInfo dateInfo; void* info = (void*) &dateInfo; - yyInput = p; - /* now has to be cast to a time_t for 64bit compliance */ - Start = now; - tm = TclpGetDate(&Start, (zone == -50000)); - thisyear = tm->tm_year + TM_YEAR_BASE; - yyYear = thisyear; - yyMonth = tm->tm_mon + 1; - yyDay = tm->tm_mday; - yyTimezone = zone; - if (zone == -50000) { - yyDSTmode = DSToff; /* assume GMT */ - yyTimezone = 0; - } else { - yyDSTmode = DSTmaybe; + if ( objc != 5 ) { + Tcl_WrongNumArgs( interp, 1, objv, + "stringToParse baseYear baseMonth baseDay" ); + return TCL_ERROR; } - yyHour = 0; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = MER24; - yyRelSeconds = 0; - yyRelMonth = 0; - yyRelDay = 0; - yyRelPointer = NULL; + + yyInput = Tcl_GetString( objv[1] ); yyHaveDate = 0; - yyHaveDay = 0; - yyHaveOrdinalMonth = 0; - yyHaveRel = 0; + if ( Tcl_GetIntFromObj( interp, objv[2], &yr ) != TCL_OK + || Tcl_GetIntFromObj( interp, objv[3], &mo ) != TCL_OK + || Tcl_GetIntFromObj( interp, objv[4], &da ) != TCL_OK ) { + return TCL_ERROR; + } + yyYear = yr; yyMonth = mo; yyDay = da; + yyHaveTime = 0; + yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; + yyHaveZone = 0; + yyTimezone = 0; yyDSTmode = DSTmaybe; - if (yyparse(info) || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || - yyHaveDay > 1 || yyHaveOrdinalMonth > 1) { - return -1; + yyHaveOrdinalMonth = 0; + yyMonthOrdinal = 0; + + yyHaveDay = 0; + yyDayOrdinal = 0; yyDayNumber = 0; + + yyHaveRel = 0; + yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; + + if ( yyparse( info ) ) { + Tcl_SetObjResult( interp, Tcl_NewStringObj( "syntax error", -1 ) ); + return TCL_ERROR; } - - if (yyHaveDate || yyHaveTime || yyHaveDay) { - if (yyYear < 0) { - yyYear = -yyYear; - } - /* - * The following line handles years that are specified using - * only two digits. The line of code below implements a policy - * defined by the X/Open workgroup on the millinium rollover. - * Note: some of those dates may not actually be valid on some - * platforms. The POSIX standard startes that the dates 70-99 - * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038. - * This later definition should work on all platforms. - */ - - if (yyYear < 100) { - if (yyYear >= 69) { - yyYear += 1900; - } else { - yyYear += 2000; - } - } - if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, - yyMeridian, yyDSTmode, &Start, info) < 0) { - return -1; - } + + if ( yyHaveDate > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one date in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveTime > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one time of day in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveZone > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one time zone in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveDay > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one weekday in string", -1 ) ); + return TCL_ERROR; + } + if ( yyHaveOrdinalMonth > 1 ) { + Tcl_SetObjResult + ( interp, + Tcl_NewStringObj( "more than one ordinal month in string", -1 ) ); + return TCL_ERROR; + } + + result = Tcl_NewObj(); + resultElement = Tcl_NewObj(); + if ( yyHaveDate ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyYear ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonth ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDay ) ); + } + Tcl_ListObjAppendElement( interp, result, resultElement ); + + if ( yyHaveTime ) { + Tcl_ListObjAppendElement( interp, result, + Tcl_NewIntObj( ToSeconds( yyHour, + yyMinutes, + yySeconds, + yyMeridian ) ) ); } else { - Start = now; - if (!yyHaveRel) { - Start -= ((tm->tm_hour * 60L * 60L) + - tm->tm_min * 60L) + tm->tm_sec; - } + Tcl_ListObjAppendElement( interp, result, Tcl_NewObj() ); } - Start += yyRelSeconds; - if (RelativeMonth(Start, yyRelMonth, &Time, info) < 0) { - return -1; + resultElement = Tcl_NewObj(); + if ( yyHaveZone ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( -yyTimezone ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( 1-yyDSTmode ) ); } - Start += Time; - - if (RelativeDay(Start, yyRelDay, &Time) < 0) { - return -1; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveRel ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelMonth ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelDay ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyRelSeconds ) ); } - Start += Time; - - if (yyHaveDay && !yyHaveDate) { - tod = NamedDay(Start, yyDayOrdinal, yyDayNumber); - Start += tod; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveDay && !yyHaveDate ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDayOrdinal ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyDayNumber ) ); } - - if (yyHaveOrdinalMonth) { - tod = NamedMonth(Start, yyMonthOrdinal, yyMonth, info); - Start += tod; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + resultElement = Tcl_NewObj(); + if ( yyHaveOrdinalMonth ) { + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonthOrdinal ) ); + Tcl_ListObjAppendElement( interp, resultElement, + Tcl_NewIntObj( yyMonth ) ); } - - *timePtr = Start; - return 0; + Tcl_ListObjAppendElement( interp, result, resultElement ); + + Tcl_SetObjResult( interp, result ); + return TCL_OK; } diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 9e45d90..6019d66 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -12,7 +12,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tclInt.decls,v 1.77 2004/08/25 01:11:03 dgp Exp $ +# RCS: @(#) $Id: tclInt.decls,v 1.78 2004/09/27 14:31:17 kennykb Exp $ library tcl @@ -124,10 +124,11 @@ declare 25 generic { # declare 26 generic { # char *TclGetCwd(Tcl_Interp *interp) # } -declare 27 generic { - int TclGetDate(char *p, unsigned long now, long zone, - unsigned long *timePtr) -} +# Removed in 8.5 +#declare 27 generic { +# int TclGetDate(char *p, unsigned long now, long zone, +# unsigned long *timePtr) +#} declare 28 generic { Tcl_Channel TclpGetDefaultStdChannel(int type) } @@ -526,10 +527,11 @@ declare 132 generic { declare 133 generic { struct tm *TclpGetDate(CONST time_t *time, int useGMT) } -declare 134 generic { - size_t TclpStrftime(char *s, size_t maxsize, CONST char *format, - CONST struct tm *t, int useGMT) -} +# Removed in 8.5 +#declare 134 generic { +# size_t TclpStrftime(char *s, size_t maxsize, CONST char *format, +# CONST struct tm *t, int useGMT) +#} #declare 135 generic { # int TclpCheckStackSpace(void) #} diff --git a/generic/tclInt.h b/generic/tclInt.h index ea3c934..4c8c940 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.174 2004/09/26 16:36:04 msofer Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.175 2004/09/27 14:31:18 kennykb Exp $ */ #ifndef _TCLINT @@ -2554,40 +2554,5 @@ EXTERN void TclDbInitNewObj _ANSI_ARGS_((Tcl_Obj *objPtr)); # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT -/* - * Data structure used to hold information returned from TclGetDate - */ - -typedef struct TclGetDateInfo { - - 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; - -} TclGetDateInfo; - #endif /* _TCLINT */ diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index f9675a2..42c8f62 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIntDecls.h,v 1.67 2004/08/25 01:11:04 dgp Exp $ + * RCS: @(#) $Id: tclIntDecls.h,v 1.68 2004/09/27 14:31:18 kennykb Exp $ */ #ifndef _TCLINTDECLS @@ -175,12 +175,7 @@ EXTERN int TclFormatInt _ANSI_ARGS_((char * buffer, long n)); EXTERN void TclFreePackageInfo _ANSI_ARGS_((Interp * iPtr)); #endif /* Slot 26 is reserved */ -#ifndef TclGetDate_TCL_DECLARED -#define TclGetDate_TCL_DECLARED -/* 27 */ -EXTERN int TclGetDate _ANSI_ARGS_((char * p, unsigned long now, - long zone, unsigned long * timePtr)); -#endif +/* Slot 27 is reserved */ #ifndef TclpGetDefaultStdChannel_TCL_DECLARED #define TclpGetDefaultStdChannel_TCL_DECLARED /* 28 */ @@ -691,13 +686,7 @@ EXTERN int TclpHasSockets _ANSI_ARGS_((Tcl_Interp * interp)); EXTERN struct tm * TclpGetDate _ANSI_ARGS_((CONST time_t * time, int useGMT)); #endif -#ifndef TclpStrftime_TCL_DECLARED -#define TclpStrftime_TCL_DECLARED -/* 134 */ -EXTERN size_t TclpStrftime _ANSI_ARGS_((char * s, size_t maxsize, - CONST char * format, CONST struct tm * t, - int useGMT)); -#endif +/* Slot 134 is reserved */ /* Slot 135 is reserved */ /* Slot 136 is reserved */ /* Slot 137 is reserved */ @@ -1081,7 +1070,7 @@ typedef struct TclIntStubs { int (*tclFormatInt) _ANSI_ARGS_((char * buffer, long n)); /* 24 */ void (*tclFreePackageInfo) _ANSI_ARGS_((Interp * iPtr)); /* 25 */ void *reserved26; - int (*tclGetDate) _ANSI_ARGS_((char * p, unsigned long now, long zone, unsigned long * timePtr)); /* 27 */ + void *reserved27; Tcl_Channel (*tclpGetDefaultStdChannel) _ANSI_ARGS_((int type)); /* 28 */ void *reserved29; void *reserved30; @@ -1193,7 +1182,7 @@ typedef struct TclIntStubs { void (*tcl_SetNamespaceResolvers) _ANSI_ARGS_((Tcl_Namespace * namespacePtr, Tcl_ResolveCmdProc * cmdProc, Tcl_ResolveVarProc * varProc, Tcl_ResolveCompiledVarProc * compiledVarProc)); /* 131 */ int (*tclpHasSockets) _ANSI_ARGS_((Tcl_Interp * interp)); /* 132 */ struct tm * (*tclpGetDate) _ANSI_ARGS_((CONST time_t * time, int useGMT)); /* 133 */ - size_t (*tclpStrftime) _ANSI_ARGS_((char * s, size_t maxsize, CONST char * format, CONST struct tm * t, int useGMT)); /* 134 */ + void *reserved134; void *reserved135; void *reserved136; void *reserved137; @@ -1367,10 +1356,7 @@ extern TclIntStubs *tclIntStubsPtr; (tclIntStubsPtr->tclFreePackageInfo) /* 25 */ #endif /* Slot 26 is reserved */ -#ifndef TclGetDate -#define TclGetDate \ - (tclIntStubsPtr->tclGetDate) /* 27 */ -#endif +/* Slot 27 is reserved */ #ifndef TclpGetDefaultStdChannel #define TclpGetDefaultStdChannel \ (tclIntStubsPtr->tclpGetDefaultStdChannel) /* 28 */ @@ -1716,10 +1702,7 @@ extern TclIntStubs *tclIntStubsPtr; #define TclpGetDate \ (tclIntStubsPtr->tclpGetDate) /* 133 */ #endif -#ifndef TclpStrftime -#define TclpStrftime \ - (tclIntStubsPtr->tclpStrftime) /* 134 */ -#endif +/* Slot 134 is reserved */ /* Slot 135 is reserved */ /* Slot 136 is reserved */ /* Slot 137 is reserved */ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 4983996..af99c25 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStubInit.c,v 1.101 2004/08/25 01:11:20 dgp Exp $ + * RCS: @(#) $Id: tclStubInit.c,v 1.102 2004/09/27 14:31:19 kennykb Exp $ */ #include "tclInt.h" @@ -106,7 +106,7 @@ TclIntStubs tclIntStubs = { TclFormatInt, /* 24 */ TclFreePackageInfo, /* 25 */ NULL, /* 26 */ - TclGetDate, /* 27 */ + NULL, /* 27 */ TclpGetDefaultStdChannel, /* 28 */ NULL, /* 29 */ NULL, /* 30 */ @@ -218,7 +218,7 @@ TclIntStubs tclIntStubs = { Tcl_SetNamespaceResolvers, /* 131 */ TclpHasSockets, /* 132 */ TclpGetDate, /* 133 */ - TclpStrftime, /* 134 */ + NULL, /* 134 */ NULL, /* 135 */ NULL, /* 136 */ NULL, /* 137 */ diff --git a/library/clock.tcl b/library/clock.tcl index d26c2c8..dce89e6 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -13,7 +13,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.tcl,v 1.5 2004/09/10 17:50:15 kennykb Exp $ +# RCS: @(#) $Id: clock.tcl,v 1.6 2004/09/27 14:31:20 kennykb Exp $ # #---------------------------------------------------------------------- @@ -400,70 +400,70 @@ namespace eval ::tcl::clock { dict set date era CE dict set date year [expr { 100 * [dict get $date century] + [dict get $date yearOfCentury] }] - set date [GetJulianDayFromEraYearMonthDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearMonthDay $date[set date {}]] } { century yearOfCentury dayOfYear } 2 { dict set date era CE dict set date year [expr { 100 * [dict get $date century] + [dict get $date yearOfCentury] }] - set date [GetJulianDayFromEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearDay $date[set date {}]] } { iso8601Century iso8601YearOfCentury iso8601Week dayOfWeek } 2 { dict set date era CE dict set date iso8601Year \ [expr { 100 * [dict get $date iso8601Century] + [dict get $date iso8601YearOfCentury] }] - set date [GetJulianDayFromEraYearWeekDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearWeekDay $date[set date {}]] } { yearOfCentury month dayOfMonth } 3 { - set date [InterpretTwoDigitYear [K $date [set date {}]] $baseTime] + set date [InterpretTwoDigitYear $date[set date {}] $baseTime] dict set date era CE - set date [GetJulianDayFromEraYearMonthDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearMonthDay $date[set date {}]] } { yearOfCentury dayOfYear } 3 { - set date [InterpretTwoDigitYear [K $date [set date {}]] $baseTime] + set date [InterpretTwoDigitYear $date[set date {}] $baseTime] dict set date era CE - set date [GetJulianDayFromEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearDay $date[set date {}]] } { iso8601YearOfCentury iso8601Week dayOfWeek } 3 { set date [InterpretTwoDigitYear \ - [K $date [set date {}]] $baseTime \ + $date[set date {}] $baseTime \ iso8601YearOfCentury iso8601Year] dict set date era CE - set date [GetJulianDayFromEraYearWeekDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearWeekDay $date[set date {}]] } { month dayOfMonth } 4 { - set date [AssignBaseYear [K $date [set date {}]] \ + set date [AssignBaseYear $date[set date {}] \ $baseTime $timeZone] - set date [GetJulianDayFromEraYearMonthDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearMonthDay $date[set date {}]] } { dayOfYear } 4 { - set date [AssignBaseYear [K $date [set date {}]] \ + set date [AssignBaseYear $date[set date {}] \ $baseTime $timeZone] - set date [GetJulianDayFromEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearDay $date[set date {}]] } { iso8601Week dayOfWeek } 4 { - set date [AssignBaseIso8601Year [K $date [set date {}]] \ + set date [AssignBaseIso8601Year $date[set date {}] \ $baseTime $timeZone] - set date [GetJulianDayFromEraYearWeekDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearWeekDay $date[set date {}]] } { dayOfMonth } 5 { - set date [AssignBaseMonth [K $date [set date {}]] \ + set date [AssignBaseMonth $date[set date {}] \ $baseTime $timeZone] - set date [GetJulianDayFromEraYearMonthDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearMonthDay $date[set date {}]] } { dayOfWeek } 6 { - set date [AssignBaseWeek [K $date [set date {}]] \ + set date [AssignBaseWeek $date[set date {}] \ $baseTime $timeZone] - set date [GetJulianDayFromEraYearWeekDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearWeekDay $date[set date {}]] } {} 7 { - set date [AssignBaseJulianDay [K $date [set date {}]] \ + set date [AssignBaseJulianDay $date[set date {}] \ $baseTime $timeZone] } } @@ -620,31 +620,6 @@ namespace eval ::tcl::clock { #---------------------------------------------------------------------- # -# K -- -# -# The K combinator returns its first argument. It's used for -# reference count management. -# -# Parameters: -# x - Argument to be unreferenced. -# y - Unused. -# -# Results: -# Returns the first argument. -# -# Side effects: -# None. -# -# The K combinator is used for its effect that [K $x [set x {}]] -# reads out the value of x destructively, giving an unshared Tcl -# object and avoiding 'copy on write' -# -#---------------------------------------------------------------------- - -proc ::tcl::clock::K { x y } { return $x } - -#---------------------------------------------------------------------- -# # clock format -- # # Formats a count of seconds since the Posix Epoch as a time @@ -745,14 +720,14 @@ proc ::tcl::clock::format { args } { # Convert the given time to local time. set date [dict create seconds $clockval] - set date [ConvertUTCToLocal [K $date [set date {}]] $timezone] + set date [ConvertUTCToLocal $date[set date {}] $timezone] # Extract the fields of the date. - set date [GetJulianDay [K $date [set date {}]]] - set date [GetGregorianEraYearDay [K $date [set date {}]]] - set date [GetMonthDay [K $date [set date {}]]] - set date [GetYearWeekDay [K $date [set date {}]]] + set date [GetJulianDay $date[set date {}]] + set date [GetGregorianEraYearDay $date[set date {}]] + set date [GetMonthDay $date[set date {}]] + set date [GetYearWeekDay $date[set date {}]] # Format the result @@ -774,12 +749,14 @@ proc ::tcl::clock::format { args } { append retval % } a { # Day of week, abbreviated - set dow [expr { [dict get $date dayOfWeek] % 7 }] + set dow [expr { [dict get $date dayOfWeek] + % $DaysPerWeek }] append retval \ [lindex [mc DAYS_OF_WEEK_ABBREV] $dow] } A { # Day of week, spelt out. - set dow [expr { [dict get $date dayOfWeek] % 7 }] + set dow [expr { [dict get $date dayOfWeek] + % $DaysPerWeek }] append retval [lindex [mc DAYS_OF_WEEK_FULL] $dow] } b - h { # Name of month, abbreviated. @@ -806,7 +783,7 @@ proc ::tcl::clock::format { args } { # alternative era set state percentE if { ![dict exists $date localeEra] } { - set date [GetLocaleEra [K $date [set date {}]]] + set date [GetLocaleEra $date[set date {}]] } } g { # Two-digit year relative to ISO8601 @@ -926,7 +903,7 @@ proc ::tcl::clock::format { args } { # first Sunday of the year is the # first day of week 01 set dow [dict get $date dayOfWeek] - if { $dow == 7 } { + if { $dow == $DaysPerWeek } { set dow 0 } incr dow @@ -944,7 +921,8 @@ proc ::tcl::clock::format { args } { w { # Day of the week (0-Sunday, # 6-Saturday) append retval \ - [expr { [dict get $date dayOfWeek] % 7 }] + [expr { [dict get $date dayOfWeek] + % $DaysPerWeek }] } W { # Week of the year (00-53). The first # Monday of the year is the first day @@ -967,23 +945,8 @@ proc ::tcl::clock::format { args } { } z { # The time zone as hours and minutes # east (+) or west (-) of Greenwich - set z [dict get $date tzOffset] - if { $z < 0 } { - set z [expr { - $z }] - append retval - - } else { - append retval + - } - append retval [::format %02d \ - [expr { $z / $SecondsPerHour }]] - set z [expr { $z % $SecondsPerHour }] - append retval \ - [::format %02d \ - [expr { $z / $SecondsPerMinute }]] - set z [expr { $z % $SecondsPerMinute }] - if { $z != 0 } { - append retval [::format %02d $z] - } + append retval [FormatNumericTimeZone \ + [dict get $date tzOffset]] } Z { # The name of the time zone append retval [dict get $date tzName] @@ -1071,7 +1034,8 @@ proc ::tcl::clock::format { args } { append retval \ [lindex \ [mc LOCALE_NUMERALS] \ - [expr { [dict get $date dayOfWeek] % 7 }]] + [expr { [dict get $date dayOfWeek] + % $DaysPerWeek }]] } y { # Year of the century in alternative # numerals @@ -1213,15 +1177,16 @@ proc ::tcl::clock::scan { args } { } if { ![info exists saw(-format)] } { - if { [info exists saw(-timezone)] || [info exists saw(-locale)] } { + # Perhaps someday we'll localize the legacy code. Right now, + # it's not localized. + if { [info exists saw(-locale)] } { return -code error \ -errorcode [list CLOCK flagWithLegacyFormat] \ - "legacy \[clock scan\] does not support -timezone or\ - -locale" + "legacy \[clock scan\] does not support -locale" } if { [catch { - Oldscan $string -base $base -gmt $gmt + FreeScan $string $base $timezone $locale } retval] } { return -code error \ -errorcode $::errorCode -errorinfo $::errorInfo \ @@ -1267,6 +1232,178 @@ proc ::tcl::clock::scan { args } { #---------------------------------------------------------------------- # +# FreeScan -- +# +# Scans a time in free format +# +# Parameters: +# string - String containing the time to scan +# base - Base time, expressed in seconds from the Epoch +# timezone - Default time zone in which the time will be expressed +# locale - (Unused) Name of the locale where the time will be scanned. +# +# Results: +# Returns the date and time extracted from the string in seconds +# from the epoch +# +#---------------------------------------------------------------------- + +proc ::tcl::clock::FreeScan { string base timezone locale } { + + variable SecondsPerDay + variable DaysPerWeek + variable PosixEpochAsJulianSeconds + + # Extract year, month and day from the base time for the + # parser to use as defaults + + set date [GetMonthDay \ + [GetGregorianEraYearDay \ + [GetJulianDay \ + [ConvertUTCToLocal \ + [dict create seconds $base] \ + $timezone]]]] + dict set date secondOfDay [expr { [dict get $date localSeconds] + % $SecondsPerDay }] + + # Parse the date. The parser will return a list comprising + # date, time, time zone, relative month/day/seconds, relative + # weekday, ordinal month. + + set status [catch { + Oldscan $string \ + [dict get $date year] \ + [dict get $date month] \ + [dict get $date dayOfMonth] + } result] + if { $status != 0 } { + return -code error "unable to convert date-time string \"$string\"" + } + + foreach { parseDate parseTime parseZone parseRel + parseWeekday parseOrdinalMonth } $result break + + # If the caller supplied a date in the string, update the 'date' dict + # with the value. If the caller didn't specify a time with the date, + # default to midnight. + + if { [llength $parseDate] > 0 } { + foreach { y m d } $parseDate break + if { $y < 100 } { + if { $y >= 39 } { + incr y 1900 + } else { + incr y 2000 + } + } + dict set date era CE + dict set date year $y + dict set date month $m + dict set date dayOfMonth $d + if { $parseTime eq {} } { + set parseTime 0 + } + } + + # If the caller supplied a time zone in the string, it comes back + # as a two-element list; the first element is the number of minutes + # east of Greenwich, and the second is a Daylight Saving Time + # indicator ( 1 == yes, 0 == no, -1 == unknown ). We make it into + # a time zone indicator of +-hhmm. + + if { [llength $parseZone] > 0 } { + foreach { minEast dstFlag } $parseZone break + set timezone [FormatNumericTimeZone \ + [expr { 60 * $minEast + 3600 * $dstFlag }]] + } + dict set date tzName $timezone + + # Assemble date, time, zone into seconds-from-epoch + + set date [GetJulianDayFromEraYearMonthDay $date[set date {}]] + if { $parseTime ne {} } { + dict set date secondOfDay $parseTime + } + dict set date localSeconds \ + [expr { -$::tcl::clock::PosixEpochAsJulianSeconds + + ( $::tcl::clock::SecondsPerDay + * wide([dict get $date julianDay]) ) + + [dict get $date secondOfDay] }] + set date [ConvertLocalToUTC $date[set date {}]] + set seconds [dict get $date seconds] + + # Do relative times + + if { [llength $parseRel] > 0 } { + foreach { relMonth relDay relSecond } $parseRel break + set seconds [add $seconds \ + $relMonth months $relDay days $relSecond seconds \ + -timezone $timezone -locale $locale] + } + + # Do relative weekday + + if { [llength $parseWeekday] > 0 } { + + # TODO - There's no reason for this to involve the + # ISO calendar; day of week is determined by + # Julian Day and there's no need to extract + # week of year + foreach {dayOrdinal dayOfWeek} $parseWeekday break + set date2 [GetJulianDay \ + [ConvertUTCToLocal \ + [dict create seconds $seconds] \ + $timezone]] + dict set date2 era CE + set jdwkday [WeekdayOnOrBefore $dayOfWeek \ + [expr { [dict get $date2 julianDay] + + $DaysPerWeek - 1}]] + incr jdwkday [expr { $DaysPerWeek * $dayOrdinal }] + if { $dayOrdinal > 0 } { + incr jdwkday [expr {- $DaysPerWeek }] + } + dict set date2 secondOfDay \ + [expr { [dict get $date2 localSeconds] % $SecondsPerDay }] + dict set date2 julianDay $jdwkday + dict set date2 localSeconds \ + [expr { -$PosixEpochAsJulianSeconds + + ( $SecondsPerDay * wide([dict get $date2 julianDay]) ) + + [dict get $date secondOfDay] }] + dict set date2 tzname $timezone + set date2 [ConvertLocalToUTC $date2[set date2 {}]] + set seconds [dict get $date2 seconds] + + } + + # Do relative month + + if { [llength $parseOrdinalMonth] > 0 } { + + foreach {monthOrdinal monthNumber} $parseOrdinalMonth break + if { $monthOrdinal > 0 } { + set monthDiff [expr { $monthNumber - [dict get $date month] }] + if { $monthDiff <= 0 } { + incr monthDiff 12 + } + incr monthOrdinal -1 + } else { + set monthDiff [expr { [dict get $date month] - $monthNumber }] + if { $monthDiff >= 0 } { + incr monthDiff -12 + } + incr monthOrdinal + } + set seconds [add $seconds $monthOrdinal years $monthDiff months \ + -timezone $timezone -locale $locale] + + } + + return $seconds +} + + +#---------------------------------------------------------------------- +# # ParseClockScanFormat -- # # Parses a format string given to [clock scan -format] @@ -1523,8 +1660,8 @@ proc ::tcl::clock::ParseClockScanFormat { formatString } { { %d dow} \n \ { if { $dow == 0 } { - set dow 7 - } elseif { $dow > 7 } { + set dow $DaysPerWeek + } elseif { $dow > $DaysPerWeek } { return -code error \ -errorcode [list CLOCK badDayOfWeek] \ "day of week is greater than 7" @@ -1688,8 +1825,8 @@ proc ::tcl::clock::ParseClockScanFormat { formatString } { { $field} [incr captureCount] \] \n \ { if { $dow == 0 } { - set dow 7 - } elseif { $dow > 7 } { + set dow $DaysPerWeek + } elseif { $dow > $DaysPerWeek } { return -code error \ -errorcode [list CLOCK badDayOfWeek] \ "day of week is greater than 7" @@ -1724,7 +1861,9 @@ proc ::tcl::clock::ParseClockScanFormat { formatString } { # Build the procedure - set procBody \n + set procBody { + variable ::tcl::clock::DaysPerWeek + } append procBody "if \{ !\[ regexp -nocase [list $re] \$string ->" for { set i 1 } { $i <= $captureCount } { incr i } { append procBody " " field $i @@ -1767,7 +1906,7 @@ proc ::tcl::clock::ParseClockScanFormat { formatString } { if { ![dict exists $fieldSet seconds] && ![dict exists $fieldSet starDate] } { append procBody { - set date [::tcl::clock::ConvertLocalToUTC [K $date [set date {}]]] + set date [::tcl::clock::ConvertLocalToUTC $date[set date {}]] } } @@ -2310,6 +2449,46 @@ proc ::tcl::clock::LocalizeFormat { format } { #---------------------------------------------------------------------- # +# FormatNumericTimeZone -- +# +# Formats a time zone as +hhmmss +# +# Parameters: +# z - Time zone in seconds east of Greenwich +# +# Results: +# Returns the time zone formatted in a numeric form +# +# Side effects: +# None. +# +#---------------------------------------------------------------------- + +proc ::tcl::clock::FormatNumericTimeZone { z } { + + variable SecondsPerHour + variable SecondsPerMinute + + if { $z < 0 } { + set z [expr { - $z }] + set retval - + } else { + set retval + + } + append retval [::format %02d [expr { $z / $SecondsPerHour }]] + set z [expr { $z % $SecondsPerHour }] + append retval [::format %02d [expr { $z / $SecondsPerMinute }]] + set z [expr { $z % $SecondsPerMinute }] + if { $z != 0 } { + append retval [::format %02d $z] + } + return $retval + +} + + +#---------------------------------------------------------------------- +# # FormatStarDate -- # # Formats a date as a StarDate. @@ -2399,7 +2578,7 @@ proc ::tcl::clock::ParseStarDate { year fractYear fractDay } { era CE \ year [expr { $year + $Roddenberry }] \ dayOfYear [expr { $fractYear * $DaysPerYear / 1000 + 1 }]] - set date [GetJulianDayFromGregorianEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromGregorianEraYearDay $date[set date {}]] # Determine whether the given year is a leap year @@ -2421,7 +2600,7 @@ proc ::tcl::clock::ParseStarDate { year fractYear fractDay } { } dict unset date julianDay dict unset date gregorian - set date [GetJulianDayFromGregorianEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromGregorianEraYearDay $date[set date {}]] return [expr { $SecondsPerDay * [dict get $date julianDay] - $PosixEpochAsJulianSeconds @@ -2529,9 +2708,9 @@ proc ::tcl::clock::AssignBaseYear { date baseTime timeZone } { # find the Gregorian year corresponding to that Julian Day. set date2 [dict create seconds $baseTime] - set date2 [ConvertUTCToLocal [K $date2 [set date2 {}]] $timeZone] - set date2 [GetJulianDay [K $date2 [set date2 {}]]] - set date2 [GetGregorianEraYearDay [K $date2 [set date2 {}]]] + set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone] + set date2 [GetJulianDay $date2[set date2 {}]] + set date2 [GetGregorianEraYearDay $date2[set date2 {}]] # Store the converted year @@ -2569,12 +2748,12 @@ proc ::tcl::clock::AssignBaseIso8601Year { date baseTime timeZone } { # Find the Julian Day Number corresponding to the base time set date2 [dict create seconds $baseTime] - set date2 [ConvertUTCToLocal [K $date2 [set date2 {}]] $timeZone] - set date2 [GetJulianDay [K $date2 [set date2 {}]]] + set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone] + set date2 [GetJulianDay $date2[set date2 {}]] # Calculate the ISO8601 date and transfer the year - set date2 [GetYearWeekDay [K $date2 [set date2 {}]]] + set date2 [GetYearWeekDay $date2[set date2 {}]] dict set date era CE dict set date iso8601Year [dict get $date2 iso8601Year] return $date @@ -2608,13 +2787,13 @@ proc ::tcl::clock::AssignBaseMonth { date baseTime timeZone } { # Find the Julian Day Number corresponding to the base time set date2 [dict create seconds $baseTime] - set date2 [ConvertUTCToLocal [K $date2 [set date2 {}]] $timeZone] - set date2 [GetJulianDay [K $date2 [set date2 {}]]] + set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone] + set date2 [GetJulianDay $date2[set date2 {}]] # Find the Gregorian year corresponding to that Julian Day - set date2 [GetGregorianEraYearDay [K $date2 [set date2 {}]]] - set date2 [GetMonthDay [K $date2 [set date2 {}]]] + set date2 [GetGregorianEraYearDay $date2[set date2 {}]] + set date2 [GetMonthDay $date2[set date2 {}]] dict set date era [dict get $date2 era] dict set date year [dict get $date2 year] dict set date month [dict get $date2 month] @@ -2649,12 +2828,12 @@ proc ::tcl::clock::AssignBaseWeek { date baseTime timeZone } { # Find the Julian Day Number corresponding to the base time set date2 [dict create seconds $baseTime] - set date2 [ConvertUTCToLocal [K $date2 [set date2 {}]] $timeZone] - set date2 [GetJulianDay [K $date2 [set date2 {}]]] + set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone] + set date2 [GetJulianDay $date2[set date2 {}]] # Calculate the ISO8601 date and transfer the year - set date2 [GetYearWeekDay [K $date2 [set date2 {}]]] + set date2 [GetYearWeekDay $date2[set date2 {}]] dict set date era CE dict set date iso8601Year [dict get $date2 iso8601Year] dict set date iso8601Week [dict get $date2 iso8601Week] @@ -2688,8 +2867,8 @@ proc ::tcl::clock::AssignBaseJulianDay { date baseTime timeZone } { # Find the Julian Day Number corresponding to the base time set date2 [dict create seconds $baseTime] - set date2 [ConvertUTCToLocal [K $date2 [set date2 {}]] $timeZone] - set date2 [GetJulianDay [K $date2 [set date2 {}]]] + set date2 [ConvertUTCToLocal $date2[set date2 {}] $timeZone] + set date2 [GetJulianDay $date2[set date2 {}]] dict set date julianDay [dict get $date2 julianDay] return $date @@ -2723,7 +2902,7 @@ proc ::tcl::clock::InterpretHMSP { date } { incr hr 12 } dict set date hour $hr - return [InterpretHMS [K $date [set date {}]]] + return [InterpretHMS $date[set date {}]] } @@ -2939,9 +3118,9 @@ proc ::tcl::clock::ConvertLocalToUTCViaC { localSeconds } { variable HoursPerDay set date [dict create localSeconds $localSeconds] - set date [GetJulianDay [K $date [set date {}]]] - set date [GetGregorianEraYearDay [K $date [set date {}]]] - set date [GetMonthDay [K $date [set date {}]]] + set date [GetJulianDay $date[set date {}]] + set date [GetGregorianEraYearDay $date[set date {}]] + set date [GetMonthDay $date[set date {}]] set retval \ [Mktime \ [dict get $date year] \ @@ -3046,7 +3225,7 @@ proc ::tcl::clock::ConvertUTCToLocalViaC { date } { # Convert to Julian Day - set date2 [GetJulianDayFromEraYearMonthDay [K $date2 [set date2 {}]]] + set date2 [GetJulianDayFromEraYearMonthDay $date2[set date2 {}]] # Reconvert to seconds from the epoch in local time. @@ -3848,7 +4027,7 @@ proc ::tcl::clock::DeterminePosixDSTTime { z bound y } { incr doy } dict set date dayOfYear $doy - set date [GetJulianDayFromEraYearDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearDay $date[set date {}]] } else { # Time was specified as a day of the week within a month @@ -3860,7 +4039,7 @@ proc ::tcl::clock::DeterminePosixDSTTime { z bound y } { set dow -1 } dict set date dayOfWeek $dow - set date [GetJulianDayFromEraYearMonthWeekDay [K $date [set date {}]]] + set date [GetJulianDayFromEraYearMonthWeekDay $date[set date {}]] } @@ -4148,6 +4327,8 @@ proc ::tcl::clock::GetMonthDay { date } { proc ::tcl::clock::GetYearWeekDay { date { keys { iso8601Year iso8601Week dayOfWeek } } } { + variable DaysPerWeek + set daysInFirstWeek 4 set firstDayOfWeek 1 @@ -4173,7 +4354,7 @@ proc ::tcl::clock::GetYearWeekDay { date dict set date1 dayOfWeek $firstDayOfWeek set date1 [GetJulianDayFromEraYearWeekDay \ - [K $date1 [set date1 {}]] \ + $date1[set date1 {}] \ $daysInFirstWeek \ $firstDayOfWeek \ { fiscalYear weekOfFiscalYear dayOfWeek }] @@ -4191,7 +4372,7 @@ proc ::tcl::clock::GetYearWeekDay { date } } set date1 [GetJulianDayFromEraYearWeekDay \ - [K $date1 [set date1 {}]] \ + $date1[set date1 {}] \ $daysInFirstWeek \ $firstDayOfWeek \ {fiscalYear weekOfFiscalYear dayOfWeek }] @@ -4202,10 +4383,10 @@ proc ::tcl::clock::GetYearWeekDay { date set fiscalYear [dict get $date1 fiscalYear] set dayOfFiscalYear [expr { $j - $startOfFiscalYear }] - set weekOfFiscalYear [expr { ( $dayOfFiscalYear / 7 ) + 1 }] - set dayOfWeek [expr { ( $dayOfFiscalYear + 1 ) % 7 }] + set weekOfFiscalYear [expr { ( $dayOfFiscalYear / $DaysPerWeek ) + 1 }] + set dayOfWeek [expr { ( $dayOfFiscalYear + 1 ) % $DaysPerWeek }] if { $dayOfWeek < $firstDayOfWeek } { - incr dayOfWeek 7 + incr dayOfWeek $DaysPerWeek } # Store the fiscal year, week, and day in the given slots in the @@ -4252,6 +4433,8 @@ proc ::tcl::clock::GetJulianDayFromEraYearWeekDay { { keys { iso8601Year iso8601Week dayOfWeek } } } { + variable DaysPerWeek + foreach var { fiscalYear fiscalWeek dayOfWeek } key $keys { set $var [dict get $date $key] } @@ -4263,7 +4446,7 @@ proc ::tcl::clock::GetJulianDayFromEraYearWeekDay { year $fiscalYear \ month 1 \ dayOfMonth $daysInFirstWeek] - set date2 [GetJulianDayFromEraYearMonthDay [K $date2 [set date2 {}]]] + set date2 [GetJulianDayFromEraYearMonthDay $date2[set date2 {}]] # Find the Julian Day Number of the start of that week. @@ -4273,7 +4456,7 @@ proc ::tcl::clock::GetJulianDayFromEraYearWeekDay { dict set date julianDay \ [expr { $jd - + ( 7 * ( $fiscalWeek - 1 ) ) + + ( $DaysPerWeek * ( $fiscalWeek - 1 ) ) + $dayOfWeek - $firstDayOfWeek }] return $date @@ -4459,9 +4642,9 @@ proc ::tcl::clock::GetJulianDayFromEraYearMonthWeekDay { date } { dict set date2 dayOfMonth 0 } else { dict incr date2 month - dict set date2 dayOfMonth 7 + dict set date2 dayOfMonth $DaysPerWeek } - set date2 [GetJulianDayFromEraYearMonthDay [K $date2 [set date2 {}]]] + set date2 [GetJulianDayFromEraYearMonthDay $date2[set date2 {}]] set wd0 [WeekdayOnOrBefore [dict get $date dayOfWeek] \ [dict get $date2 julianDay]] dict set date julianDay [expr { $wd0 + $DaysPerWeek * $week }] @@ -4533,8 +4716,10 @@ proc ::tcl::clock::IsGregorianLeapYear { date } { proc ::tcl::clock::WeekdayOnOrBefore { weekday j } { - set k [expr { ( $weekday + 6 ) % 7 }] - return [expr { $j - ( $j - $k ) % 7 }] + variable DaysPerWeek + + set k [expr { ( $weekday + 6 ) % $DaysPerWeek }] + return [expr { $j - ( $j - $k ) % $DaysPerWeek }] } @@ -4628,6 +4813,8 @@ proc ::tcl::clock::BSearch { list key } { proc ::tcl::clock::add { clockval args } { + variable DaysPerWeek + if { [llength $args] % 2 != 0 } { return -code error \ -errorcode [list CLOCK wrongNumArgs] \ @@ -4712,7 +4899,7 @@ proc ::tcl::clock::add { clockval args } { } weeks - week { - set clockval [AddDays [expr { 7 * $quantity }] \ + set clockval [AddDays [expr { $DaysPerWeek * $quantity }] \ $clockval $timezone] } days - day { @@ -4822,12 +5009,12 @@ proc ::tcl::clock::AddMonths { months clockval timezone } { # Reconvert to a number of seconds set date [GetJulianDayFromEraYearMonthDay \ - [K $date [set date {}]]] + $date[set date {}]] dict set date localSeconds \ [expr { -$PosixEpochAsJulianSeconds + ( $SecondsPerDay * wide([dict get $date julianDay]) ) + [dict get $date secondOfDay] }] - set date [ConvertLocalToUTC [K $date [set date {}]]] + set date [ConvertLocalToUTC $date[set date {}]] return [dict get $date seconds] @@ -4879,7 +5066,7 @@ proc ::tcl::clock::AddDays { days clockval timezone } { [expr { -$PosixEpochAsJulianSeconds + ( $SecondsPerDay * wide([dict get $date julianDay]) ) + [dict get $date secondOfDay] }] - set date [ConvertLocalToUTC [K $date [set date {}]]] + set date [ConvertLocalToUTC $date[set date {}]] return [dict get $date seconds] diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index 6def210..32cea2d 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixTime.c,v 1.21 2004/05/14 21:43:29 kennykb Exp $ + * RCS: @(#) $Id: tclUnixTime.c,v 1.22 2004/09/27 14:31:20 kennykb Exp $ */ #include "tclInt.h" @@ -289,61 +289,6 @@ TclpGetDate(time, useGMT) /* *---------------------------------------------------------------------- * - * TclpStrftime -- - * - * On Unix, we can safely call the native strftime implementation, - * and also ignore the useGMT parameter. - * - * Results: - * Returns the number of Unicode code points in the result string. - * - * - * Side effects: - * Stores the converted time in the buffer designated by the - * 's' parameter. - * - *---------------------------------------------------------------------- - */ - -size_t -TclpStrftime(s, maxsize, format, t, useGMT) - char *s; /* Buffer to receive the formatted string */ - size_t maxsize; /* Allocated length of the buffer */ - CONST char *format; /* Format to use for the conversion */ - CONST struct tm *t; /* Time to convert */ - int useGMT; /* Flag == 1 if converting in UTC */ -{ - Tcl_DString utf8Buffer; - size_t status; - char* utf8Format; - if (format[0] == '%' && format[1] == 'Q') { - /* Format as a stardate */ - sprintf(s, "Stardate %2d%03d.%01d", - (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), - (((t->tm_yday + 1) * 1000) / - (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), - (((t->tm_hour * 60) + t->tm_min)/144)); - return(strlen(s)); - } else { - Tcl_DStringInit( &utf8Buffer ); - utf8Format = Tcl_UtfToExternalDString( NULL, format, -1, &utf8Buffer ); - setlocale(LC_TIME, ""); - status = strftime( s, maxsize, utf8Format, t ); - Tcl_DStringFree( &utf8Buffer ); - if ( status > 0 ) { - Tcl_DStringInit ( &utf8Buffer ); - Tcl_ExternalToUtfDString( NULL, s, (int) status, &utf8Buffer ); - strcpy( s, Tcl_DStringValue( &utf8Buffer ) ); - Tcl_DStringFree( &utf8Buffer ); - } - return status; - } - -} - -/* - *---------------------------------------------------------------------- - * * TclpGmtime -- * * Wrapper around the 'gmtime' library function to make it thread diff --git a/win/Makefile.in b/win/Makefile.in index ac2ea0d..3a8160a 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -5,7 +5,7 @@ # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. # -# RCS: @(#) $Id: Makefile.in,v 1.80 2004/08/18 20:59:35 kennykb Exp $ +# RCS: @(#) $Id: Makefile.in,v 1.81 2004/09/27 14:31:21 kennykb Exp $ VERSION = @TCL_VERSION@ @@ -292,7 +292,7 @@ WIN_OBJS = \ tclWinTime.$(OBJEXT) COMPAT_OBJS = \ - strftime.$(OBJEXT) strtoll.$(OBJEXT) strtoull.$(OBJEXT) + strtoll.$(OBJEXT) strtoull.$(OBJEXT) PIPE_OBJS = stub16.$(OBJEXT) @@ -459,6 +459,17 @@ tclStubLib.${OBJEXT}: tclStubLib.c .rc.$(RES): $(RC) @RC_OUT@ $@ @RC_TYPE@ @RC_DEFINES@ @RC_INCLUDE@ "$(GENERIC_DIR_NATIVE)" @RC_INCLUDE@ "$(WIN_DIR_NATIVE)" @DEPARG@ +# The following target generates the file generic/tclDate.c +# from the yacc grammar found in generic/tclGetDate.y. This is +# only run by hand as yacc is not available in all environments. +# The name of the .c file is different than the name of the .y file +# so that make doesn't try to automatically regenerate the .c file. + +gendate: + bison --output-file=$(GENERIC_DIR)/tclDate.c \ + --name-prefix=TclDate \ + $(GENERIC_DIR)/tclGetDate.y + install: all install-binaries install-libraries install-doc install-binaries: binaries diff --git a/win/makefile.bc b/win/makefile.bc index e627f4e..2bc6f9e 100644 --- a/win/makefile.bc +++ b/win/makefile.bc @@ -193,7 +193,6 @@ TCLOBJS = \ $(TMPDIR)\regexec.obj \ $(TMPDIR)\regfree.obj \ $(TMPDIR)\regerror.obj \ - $(TMPDIR)\strftime.obj \ $(TMPDIR)\strtoll.obj \ $(TMPDIR)\strtoull.obj \ $(TMPDIR)\tclAlloc.obj \ diff --git a/win/makefile.vc b/win/makefile.vc index ec5628f..c553016 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -12,7 +12,7 @@ # Copyright (c) 2001-2004 David Gravereaux. # #------------------------------------------------------------------------------ -# RCS: @(#) $Id: makefile.vc,v 1.133 2004/09/08 00:05:54 davygrvy Exp $ +# RCS: @(#) $Id: makefile.vc,v 1.134 2004/09/27 14:31:21 kennykb Exp $ #------------------------------------------------------------------------------ !if !defined(MSDEVDIR) && !defined(MSVCDIR) @@ -247,7 +247,6 @@ TCLOBJS = \ $(TMP_DIR)\regerror.obj \ $(TMP_DIR)\regexec.obj \ $(TMP_DIR)\regfree.obj \ - $(TMP_DIR)\strftime.obj \ $(TMP_DIR)\strtoll.obj \ $(TMP_DIR)\strtoull.obj \ $(TMP_DIR)\tclAlloc.obj \ @@ -713,6 +712,17 @@ tclConfig: << !endif +# The following target generates the file generic/tclDate.c +# from the yacc grammar found in generic/tclGetDate.y. This is +# only run by hand as yacc is not available in all environments. +# The name of the .c file is different than the name of the .y file +# so that make doesn't try to automatically regenerate the .c file. + +gendate: + bison --output-file=$(GENERICDIR)/tclDate.c \ + --name-prefix=TclDate \ + $(GENERICDIR)/tclGetDate.y + #--------------------------------------------------------------------- # Special case object file targets #--------------------------------------------------------------------- diff --git a/win/tcl.dsp b/win/tcl.dsp index 23a4cc5..8c77c10 100644 --- a/win/tcl.dsp +++ b/win/tcl.dsp @@ -180,10 +180,6 @@ SOURCE=..\compat\stdlib.h # End Source File # Begin Source File -SOURCE=..\compat\strftime.c -# End Source File -# Begin Source File - SOURCE=..\compat\string.h # End Source File # Begin Source File -- cgit v0.12