Diff
Not logged in

Differences From Artifact [eba06ee972]:

To Artifact [04c92b399e]:


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
    const struct ClockCommand *clockCmdPtr;
    char cmdName[50];		/* Buffer large enough to hold the string
				 *::tcl::clock::GetJulianDayFromEraYearMonthDay
				 * plus a terminating NUL. */
    Command *cmdPtr;
    ClockClientData *data;

    static int initialized = 0;	/* global clock engine initialized (in process) */
    /*
     * Register handler to finalize clock on exit.
     */
    if (!initialized) {
	Tcl_CreateExitHandler(ClockFinalize, NULL);
	initialized = 1;
    }

    /*
     * Safe interps get [::clock] as alias to a parent, so do not need their
     * own copies of the support routines.
     */








|





|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
    const struct ClockCommand *clockCmdPtr;
    char cmdName[50];		/* Buffer large enough to hold the string
				 *::tcl::clock::GetJulianDayFromEraYearMonthDay
				 * plus a terminating NUL. */
    Command *cmdPtr;
    ClockClientData *data;

    static bool initialized = false;	/* global clock engine initialized (in process) */
    /*
     * Register handler to finalize clock on exit.
     */
    if (!initialized) {
	Tcl_CreateExitHandler(ClockFinalize, NULL);
	initialized = true;
    }

    /*
     * Safe interps get [::clock] as alias to a parent, so do not need their
     * own copies of the support routines.
     */

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
 *----------------------------------------------------------------------
 */

static Tcl_Obj *
NormTimezoneObj(
    ClockClientData *dataPtr,	/* Client data containing literal pool */
    Tcl_Obj *timezoneObj,	/* Name of zone to find */
    int *loaded)		/* Used to recognized TZ was loaded */
{
    const char *tz;

    *loaded = 1;
    if (timezoneObj == dataPtr->lastSetupTimeZoneUnnorm
	    && dataPtr->lastSetupTimeZone != NULL) {
	return dataPtr->lastSetupTimeZone;
    }
    if (timezoneObj == dataPtr->prevSetupTimeZoneUnnorm
	    && dataPtr->prevSetupTimeZone != NULL) {
	return dataPtr->prevSetupTimeZone;







|



|







414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
 *----------------------------------------------------------------------
 */

static Tcl_Obj *
NormTimezoneObj(
    ClockClientData *dataPtr,	/* Client data containing literal pool */
    Tcl_Obj *timezoneObj,	/* Name of zone to find */
    bool *loaded)		/* Used to recognized TZ was loaded */
{
    const char *tz;

    *loaded = true;
    if (timezoneObj == dataPtr->lastSetupTimeZoneUnnorm
	    && dataPtr->lastSetupTimeZone != NULL) {
	return dataPtr->lastSetupTimeZone;
    }
    if (timezoneObj == dataPtr->prevSetupTimeZoneUnnorm
	    && dataPtr->prevSetupTimeZone != NULL) {
	return dataPtr->prevSetupTimeZone;
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    if (dataPtr->systemTimeZone != NULL
	    && strcmp(tz, TclGetString(dataPtr->systemTimeZone)) == 0) {
	return dataPtr->systemTimeZone;
    }
    if (strcmp(tz, Literals[LIT_GMT]) == 0) {
	TclSetObjRef(dataPtr->gmtSetupTimeZoneUnnorm, timezoneObj);
	if (dataPtr->gmtSetupTimeZone == NULL) {
	    *loaded = 0;
	}
	return dataPtr->literals[LIT_GMT];
    }
    /* unknown/unloaded tz - recache/revalidate later as last-setup if needed */
    *loaded = 0;
    return timezoneObj;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockGetSystemLocale --







|




|







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    if (dataPtr->systemTimeZone != NULL
	    && strcmp(tz, TclGetString(dataPtr->systemTimeZone)) == 0) {
	return dataPtr->systemTimeZone;
    }
    if (strcmp(tz, Literals[LIT_GMT]) == 0) {
	TclSetObjRef(dataPtr->gmtSetupTimeZoneUnnorm, timezoneObj);
	if (dataPtr->gmtSetupTimeZone == NULL) {
	    *loaded = false;
	}
	return dataPtr->literals[LIT_GMT];
    }
    /* unknown/unloaded tz - recache/revalidate later as last-setup if needed */
    *loaded = false;
    return timezoneObj;
}

/*
 *----------------------------------------------------------------------
 *
 * ClockGetSystemLocale --
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
		    && dataPtr->lastTZEpoch == lastTZEpoch) {
		Tcl_SetObjResult(interp, dataPtr->systemTimeZone);
	    }
	    break;
	}
	case CLOCK_SETUP_TZ:
	    if (i < objc) {
		int loaded;
		Tcl_Obj *timezoneObj = NormTimezoneObj(dataPtr, objv[i], &loaded);

		if (!loaded) {
		    TimezoneLoaded(dataPtr, timezoneObj, objv[i]);
		}
		Tcl_SetObjResult(interp, timezoneObj);
	    } else if (i + 1 >= objc && dataPtr->lastSetupTimeZone != NULL) {







|







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
		    && dataPtr->lastTZEpoch == lastTZEpoch) {
		Tcl_SetObjResult(interp, dataPtr->systemTimeZone);
	    }
	    break;
	}
	case CLOCK_SETUP_TZ:
	    if (i < objc) {
		bool loaded;
		Tcl_Obj *timezoneObj = NormTimezoneObj(dataPtr, objv[i], &loaded);

		if (!loaded) {
		    TimezoneLoaded(dataPtr, timezoneObj, objv[i]);
		}
		Tcl_SetObjResult(interp, timezoneObj);
	    } else if (i + 1 >= objc && dataPtr->lastSetupTimeZone != NULL) {
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308

1309
1310
1311
1312
1313
1314
1315
1316

Tcl_Obj *
ClockSetupTimeZone(
    ClockClientData *dataPtr,	/* Pointer to literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *timezoneObj)
{
    int loaded;
    Tcl_Obj *normTzObj;

    /* if cached (if already setup this one) */
    if (timezoneObj == dataPtr->literals[LIT_GMT]
	    && dataPtr->gmtSetupTZData != NULL) {
	return timezoneObj;
    }
    if ((timezoneObj == dataPtr->lastSetupTimeZone
	    || timezoneObj == dataPtr->lastSetupTimeZoneUnnorm)
	    && dataPtr->lastSetupTimeZone != NULL) {
	return dataPtr->lastSetupTimeZone;
    }
    if ((timezoneObj == dataPtr->prevSetupTimeZone
	    || timezoneObj == dataPtr->prevSetupTimeZoneUnnorm)
	    && dataPtr->prevSetupTimeZone != NULL) {
	return dataPtr->prevSetupTimeZone;
    }

    /* differentiate normalized (last, GMT and system) zones, because used often and already set */

    normTzObj = NormTimezoneObj(dataPtr, timezoneObj, &loaded);
    /* if loaded (setup already called for this TZ) */
    if (loaded) {
	return normTzObj;
    }

    /* before setup just take a look in TZData variable */
    if (Tcl_ObjGetVar2(interp, dataPtr->literals[LIT_TZDATA], timezoneObj, 0)) {







<
<
<

















>
|







1282
1283
1284
1285
1286
1287
1288



1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314

Tcl_Obj *
ClockSetupTimeZone(
    ClockClientData *dataPtr,	/* Pointer to literal pool, etc. */
    Tcl_Interp *interp,		/* Tcl interpreter */
    Tcl_Obj *timezoneObj)
{



    /* if cached (if already setup this one) */
    if (timezoneObj == dataPtr->literals[LIT_GMT]
	    && dataPtr->gmtSetupTZData != NULL) {
	return timezoneObj;
    }
    if ((timezoneObj == dataPtr->lastSetupTimeZone
	    || timezoneObj == dataPtr->lastSetupTimeZoneUnnorm)
	    && dataPtr->lastSetupTimeZone != NULL) {
	return dataPtr->lastSetupTimeZone;
    }
    if ((timezoneObj == dataPtr->prevSetupTimeZone
	    || timezoneObj == dataPtr->prevSetupTimeZoneUnnorm)
	    && dataPtr->prevSetupTimeZone != NULL) {
	return dataPtr->prevSetupTimeZone;
    }

    /* differentiate normalized (last, GMT and system) zones, because used often and already set */
    bool loaded;
    Tcl_Obj *normTzObj = NormTimezoneObj(dataPtr, timezoneObj, &loaded);
    /* if loaded (setup already called for this TZ) */
    if (loaded) {
	return normTzObj;
    }

    /* before setup just take a look in TZData variable */
    if (Tcl_ObjGetVar2(interp, dataPtr->literals[LIT_TZDATA], timezoneObj, 0)) {
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    Tcl_Obj *secondsObj;
    Tcl_Obj *dict;
    int changeover;
    TclDateFields fields;
    int created = 0;
    int status;

    fields.tzName = NULL;
    /*
     * Check params and convert time.
     */








|







1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    Tcl_Obj *secondsObj;
    Tcl_Obj *dict;
    int changeover;
    TclDateFields fields;
    bool created = false;
    int status;

    fields.tzName = NULL;
    /*
     * Check params and convert time.
     */

1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
    /*
     * Copy-on-write; set the 'seconds' field in the dictionary and place the
     * modified dictionary in the interpreter result.
     */

    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	created = 1;
	Tcl_IncrRefCount(dict);
    }
    status = Tcl_DictObjPut(interp, dict, dataPtr->literals[LIT_SECONDS],
	    Tcl_NewWideIntObj(fields.seconds));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }







|







1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
    /*
     * Copy-on-write; set the 'seconds' field in the dictionary and place the
     * modified dictionary in the interpreter result.
     */

    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	created = true;
	Tcl_IncrRefCount(dict);
    }
    status = Tcl_DictObjPut(interp, dict, dataPtr->literals[LIT_SECONDS],
	    Tcl_NewWideIntObj(fields.seconds));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
 */

static int
FetchEraField(
    Tcl_Interp *interp,
    Tcl_Obj *dict,
    Tcl_Obj *key,
    int *storePtr)
{
    Tcl_Obj *value = NULL;

    if (Tcl_DictObjGet(interp, dict, key, &value) != TCL_OK) {
	return TCL_ERROR;
    }
    if (value == NULL) {







|







1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
 */

static int
FetchEraField(
    Tcl_Interp *interp,
    Tcl_Obj *dict,
    Tcl_Obj *key,
    bool *storePtr)
{
    Tcl_Obj *value = NULL;

    if (Tcl_DictObjGet(interp, dict, key, &value) != TCL_OK) {
	return TCL_ERROR;
    }
    if (value == NULL) {
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
    int objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    TclDateFields fields;
    ClockClientData *data = (ClockClientData *)clientData;
    Tcl_Obj *const *lit = data->literals;
    int changeover;
    int isBce = 0;

    fields.tzName = NULL;

    /*
     * Check params.
     */








|







1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
    int objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    TclDateFields fields;
    ClockClientData *data = (ClockClientData *)clientData;
    Tcl_Obj *const *lit = data->literals;
    int changeover;
    bool isBce = false;

    fields.tzName = NULL;

    /*
     * Check params.
     */

1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740

    GetJulianDayFromEraYearMonthDay(&fields, changeover);

    /*
     * Store Julian day in the dictionary - copy on write.
     */

    int copied = 0;
    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	Tcl_IncrRefCount(dict);
	copied = 1;
    }
    int status = Tcl_DictObjPut(interp, dict, lit[LIT_JULIANDAY],
	    Tcl_NewWideIntObj(fields.julianDay));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }
    if (copied) {







|



|







1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738

    GetJulianDayFromEraYearMonthDay(&fields, changeover);

    /*
     * Store Julian day in the dictionary - copy on write.
     */

    bool copied = false;
    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	Tcl_IncrRefCount(dict);
	copied = true;
    }
    int status = Tcl_DictObjPut(interp, dict, lit[LIT_JULIANDAY],
	    Tcl_NewWideIntObj(fields.julianDay));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }
    if (copied) {
1771
1772
1773
1774
1775
1776
1777
1778

1779
1780
1781
1782
1783
1784
1785
    int objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    TclDateFields fields;
    Tcl_Obj *dict;
    ClockClientData *data = (ClockClientData *)clientData;
    Tcl_Obj *const *lit = data->literals;
    int changeover, status, copied = 0, isBce = 0;


    fields.tzName = NULL;

    /*
     * Check params.
     */








|
>







1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
    int objc,			/* Parameter count */
    Tcl_Obj *const *objv)	/* Parameter vector */
{
    TclDateFields fields;
    Tcl_Obj *dict;
    ClockClientData *data = (ClockClientData *)clientData;
    Tcl_Obj *const *lit = data->literals;
    int changeover, status;
    bool copied = false, isBce = false;

    fields.tzName = NULL;

    /*
     * Check params.
     */

1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
    /*
     * Store Julian day in the dictionary - copy on write.
     */

    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	Tcl_IncrRefCount(dict);
	copied = 1;
    }
    status = Tcl_DictObjPut(interp, dict, lit[LIT_JULIANDAY],
	    Tcl_NewWideIntObj(fields.julianDay));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }
    if (copied) {







|







1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
    /*
     * Store Julian day in the dictionary - copy on write.
     */

    if (Tcl_IsShared(dict)) {
	dict = Tcl_DuplicateObj(dict);
	Tcl_IncrRefCount(dict);
	copied = true;
    }
    status = Tcl_DictObjPut(interp, dict, lit[LIT_JULIANDAY],
	    Tcl_NewWideIntObj(fields.julianDay));
    if (status == TCL_OK) {
	Tcl_SetObjResult(interp, dict);
    }
    if (copied) {
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
	return TCL_ERROR;
    }

    /*
     * Fill in the date in 'fields' and use it to derive Julian Day.
     */

    fields->isBce = 0;
    fields->year = timeVal->tm_year + 1900;
    fields->month = timeVal->tm_mon + 1;
    fields->dayOfMonth = timeVal->tm_mday;
    GetJulianDayFromEraYearMonthDay(fields, changeover);

    /*
     * Convert that value to seconds.







|







2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
	return TCL_ERROR;
    }

    /*
     * Fill in the date in 'fields' and use it to derive Julian Day.
     */

    fields->isBce = false;
    fields->year = timeVal->tm_year + 1900;
    fields->month = timeVal->tm_mon + 1;
    fields->dayOfMonth = timeVal->tm_mday;
    GetJulianDayFromEraYearMonthDay(fields, changeover);

    /*
     * Convert that value to seconds.
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
    Tcl_WideInt n;

    if (jday >= changeover) {
	/*
	 * Gregorian calendar.
	 */

	fields->gregorian = 1;
	year = 1;

	/*
	 * n = Number of 400-year cycles since 1 January, 1 CE in the
	 * proleptic Gregorian calendar. day = remaining days.
	 */








|







2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
    Tcl_WideInt n;

    if (jday >= changeover) {
	/*
	 * Gregorian calendar.
	 */

	fields->gregorian = true;
	year = 1;

	/*
	 * n = Number of 400-year cycles since 1 January, 1 CE in the
	 * proleptic Gregorian calendar. day = remaining days.
	 */

2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
	}
	year += 100 * n;
    } else {
	/*
	 * Julian calendar.
	 */

	fields->gregorian = 0;
	year = 1;
	day = jday - JDAY_1_JAN_1_CE_JULIAN;
    }

    /*
     * n = number of 4-year cycles; days = remaining days.
     */







|







2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
	}
	year += 100 * n;
    } else {
	/*
	 * Julian calendar.
	 */

	fields->gregorian = false;
	year = 1;
	day = jday - JDAY_1_JAN_1_CE_JULIAN;
    }

    /*
     * n = number of 4-year cycles; days = remaining days.
     */
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
    year += n;

    /*
     * store era/year/day back into fields.
     */

    if (year <= 0) {
	fields->isBce = 1;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->year = year;
    }
    fields->dayOfYear = day + 1;
}

/*
 *----------------------------------------------------------------------







|


|







2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
    year += n;

    /*
     * store era/year/day back into fields.
     */

    if (year <= 0) {
	fields->isBce = true;
	fields->year = 1 - year;
    } else {
	fields->isBce = false;
	fields->year = year;
    }
    fields->dayOfYear = day + 1;
}

/*
 *----------------------------------------------------------------------
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
    month = r + 1;
    ym1 = year - 1;

    /*
     * Adjust the year after reducing the month.
     */

    fields->gregorian = 1;
    if (year < 1) {
	fields->isBce = 1;
	fields->year = 1 - year;
    } else {
	fields->isBce = 0;
	fields->year = year;
    }

    /*
     * Try an initial conversion in the Gregorian calendar.
     */








|

|


|







2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
    month = r + 1;
    ym1 = year - 1;

    /*
     * Adjust the year after reducing the month.
     */

    fields->gregorian = true;
    if (year < 1) {
	fields->isBce = true;
	fields->year = 1 - year;
    } else {
	fields->isBce = false;
	fields->year = year;
    }

    /*
     * Try an initial conversion in the Gregorian calendar.
     */

2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855

    /*
     * If the resulting date is before the Gregorian changeover, convert in
     * the Julian calendar instead.
     */

    if (fields->julianDay < changeover) {
	fields->gregorian = 0;
	fields->julianDay = JDAY_1_JAN_1_CE_JULIAN - 1
		+ fields->dayOfMonth
		+ daysInPriorMonths[year%4 == 0][month - 1]
		+ (365 * ym1)
		+ ym1o4;
    }
}







|







2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854

    /*
     * If the resulting date is before the Gregorian changeover, convert in
     * the Julian calendar instead.
     */

    if (fields->julianDay < changeover) {
	fields->gregorian = false;
	fields->julianDay = JDAY_1_JAN_1_CE_JULIAN - 1
		+ fields->dayOfMonth
		+ daysInPriorMonths[year%4 == 0][month - 1]
		+ (365 * ym1)
		+ ym1o4;
    }
}
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
    } else {
	year = fields->year;
    }

    ym1 = year - 1;

    /* Try the Gregorian calendar first. */
    fields->gregorian = 1;
    fields->julianDay =
	    1721425
	    + fields->dayOfYear
	    + (365 * ym1)
	    + (ym1 / 4)
	    - (ym1 / 100)
	    + (ym1 / 400);

    /* If the date is before the Gregorian change, use the Julian calendar. */

    if (fields->julianDay < changeover) {
	fields->gregorian = 0;
	fields->julianDay =
		1721423
		+ fields->dayOfYear
		+ (365 * ym1)
		+ (ym1 / 4);
    }
}







|











|







2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
    } else {
	year = fields->year;
    }

    ym1 = year - 1;

    /* Try the Gregorian calendar first. */
    fields->gregorian = true;
    fields->julianDay =
	    1721425
	    + fields->dayOfYear
	    + (365 * ym1)
	    + (ym1 / 4)
	    - (ym1 / 100)
	    + (ym1 / 400);

    /* If the date is before the Gregorian change, use the Julian calendar. */

    if (fields->julianDay < changeover) {
	fields->gregorian = false;
	fields->julianDay =
		1721423
		+ fields->dayOfYear
		+ (365 * ym1)
		+ (ym1 / 4);
    }
}
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
    Tcl_Size objc,		/* Parameter count */
    Tcl_Obj *const objv[],	/* Parameter vector */
    ClockOperation operation,	/* What operation are we doing: format, scan, add */
    const char *syntax)		/* Syntax of the current command */
{
    Tcl_Interp *interp = opts->interp;
    ClockClientData *dataPtr = opts->dataPtr;
    int gmtFlag = 0;
    static const char *const options[] = {
	"-base", "-format", "-gmt", "-locale", "-timezone", "-validate", NULL
    };
    enum optionInd {
	CLC_ARGS_BASE, CLC_ARGS_FORMAT, CLC_ARGS_GMT, CLC_ARGS_LOCALE,
	CLC_ARGS_TIMEZONE, CLC_ARGS_VALIDATE
    };
    int optionIndex;		/* Index of an option. */
    int saw = 0;		/* Flag == 1 if option was seen already. */
    Tcl_Size i, baseIdx;
    Tcl_WideInt baseVal;	/* Base time, expressed in seconds from the Epoch */

    if (operation == CLC_OP_SCN) {
	/* default flags (from configure) */
	opts->flags |= dataPtr->defFlags & CLF_VALIDATE;
    } else {







|








|







3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
    Tcl_Size objc,		/* Parameter count */
    Tcl_Obj *const objv[],	/* Parameter vector */
    ClockOperation operation,	/* What operation are we doing: format, scan, add */
    const char *syntax)		/* Syntax of the current command */
{
    Tcl_Interp *interp = opts->interp;
    ClockClientData *dataPtr = opts->dataPtr;
    bool gmtFlag = false;
    static const char *const options[] = {
	"-base", "-format", "-gmt", "-locale", "-timezone", "-validate", NULL
    };
    enum optionInd {
	CLC_ARGS_BASE, CLC_ARGS_FORMAT, CLC_ARGS_GMT, CLC_ARGS_LOCALE,
	CLC_ARGS_TIMEZONE, CLC_ARGS_VALIDATE
    };
    int optionIndex;		/* Index of an option. */
    int saw = 0;		/* Bit flags: 1 if option was seen already. */
    Tcl_Size i, baseIdx;
    Tcl_WideInt baseVal;	/* Base time, expressed in seconds from the Epoch */

    if (operation == CLC_OP_SCN) {
	/* default flags (from configure) */
	opts->flags |= dataPtr->defFlags & CLF_VALIDATE;
    } else {
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
	case CLC_ARGS_BASE:
	    opts->baseObj = objv[(baseIdx = i + 1)];
	    break;
	case CLC_ARGS_VALIDATE:
	    if (operation != CLC_OP_SCN) {
		goto badOptionMsg;
	    } else {
		int val;

		if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &val) != TCL_OK) {
		    return TCL_ERROR;
		}
		if (val) {
		    opts->flags |= CLF_VALIDATE;
		} else {







|







3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
	case CLC_ARGS_BASE:
	    opts->baseObj = objv[(baseIdx = i + 1)];
	    break;
	case CLC_ARGS_VALIDATE:
	    if (operation != CLC_OP_SCN) {
		goto badOptionMsg;
	    } else {
		bool val;

		if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &val) != TCL_OK) {
		    return TCL_ERROR;
		}
		if (val) {
		    opts->flags |= CLF_VALIDATE;
		} else {
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
    Tcl_Obj *const objv[])	/* Parameter values */
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    static const char *syntax = "clock format clockval|now "
	    "?-format string? "
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE?";
    int ret;
    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateFormat dateFmt;		/* Common structure used for formatting */

    /* even number of arguments */
    if ((objc & 1) == 1) {
	Tcl_WrongNumArgs(interp, 0, objv, syntax);
	TclSetErrorCode(interp, "CLOCK", "wrongNumArgs");
	return TCL_ERROR;
    }

    memset(&dateFmt, 0, sizeof(dateFmt));

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    ret = ClockParseFmtScnArgs(&opts, &dateFmt.date, objc, objv,
	    CLC_OP_FMT, "-format, -gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* Default format */
    if (opts.formatObj == NULL) {







<

















|







3505
3506
3507
3508
3509
3510
3511

3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
    Tcl_Obj *const objv[])	/* Parameter values */
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    static const char *syntax = "clock format clockval|now "
	    "?-format string? "
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE?";

    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateFormat dateFmt;		/* Common structure used for formatting */

    /* even number of arguments */
    if ((objc & 1) == 1) {
	Tcl_WrongNumArgs(interp, 0, objv, syntax);
	TclSetErrorCode(interp, "CLOCK", "wrongNumArgs");
	return TCL_ERROR;
    }

    memset(&dateFmt, 0, sizeof(dateFmt));

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    int ret = ClockParseFmtScnArgs(&opts, &dateFmt.date, objc, objv,
	    CLC_OP_FMT, "-format, -gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* Default format */
    if (opts.formatObj == NULL) {
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    static const char *syntax = "clock scan string "
	    "?-base seconds? "
	    "?-format string? "
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE? ?-validate boolean?";
    int ret;
    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateInfo yy;		/* Common structure used for parsing */
    DateInfo *info = &yy;

    /* even number of arguments */
    if ((objc & 1) == 1) {
	Tcl_WrongNumArgs(interp, 0, objv, syntax);
	TclSetErrorCode(interp, "CLOCK", "wrongNumArgs");
	return TCL_ERROR;
    }

    ClockInitDateInfo(&yy);

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_SCN, "-base, -format, -gmt, -locale, -timezone or -validate");
    if (ret != TCL_OK) {
	goto done;
    }

    /* seconds are in localSeconds (relative base date), so reset time here */
    yyHour = yyMinutes = yySeconds = yySecondOfDay = 0;







<


















|







3574
3575
3576
3577
3578
3579
3580

3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
{
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    static const char *syntax = "clock scan string "
	    "?-base seconds? "
	    "?-format string? "
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE? ?-validate boolean?";

    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateInfo yy;		/* Common structure used for parsing */
    DateInfo *info = &yy;

    /* even number of arguments */
    if ((objc & 1) == 1) {
	Tcl_WrongNumArgs(interp, 0, objv, syntax);
	TclSetErrorCode(interp, "CLOCK", "wrongNumArgs");
	return TCL_ERROR;
    }

    ClockInitDateInfo(&yy);

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    int ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_SCN, "-base, -format, -gmt, -locale, -timezone or -validate");
    if (ret != TCL_OK) {
	goto done;
    }

    /* seconds are in localSeconds (relative base date), so reset time here */
    yyHour = yyMinutes = yySeconds = yySecondOfDay = 0;
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
    if (info->flags & CLF_YEAR) {
	if (yyYear < 100) {
	    if (yyYear >= dataPtr->yearOfCenturySwitch) {
		yyYear -= 100;
	    }
	    yyYear += dataPtr->currentYearCentury;
	}
	yydate.isBce = 0;
	info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS;
    }

    /*
     * If the caller supplied a time zone in the string, make it into a time
     * zone indicator of +-hhmm and setup this time zone.
     */







|







3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
    if (info->flags & CLF_YEAR) {
	if (yyYear < 100) {
	    if (yyYear >= dataPtr->yearOfCenturySwitch) {
		yyYear -= 100;
	    }
	    yyYear += dataPtr->currentYearCentury;
	}
	yydate.isBce = false;
	info->flags |= CLF_ASSEMBLE_JULIANDAY|CLF_ASSEMBLE_SECONDS;
    }

    /*
     * If the caller supplied a time zone in the string, make it into a time
     * zone indicator of +-hhmm and setup this time zone.
     */
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231

	/* if needed assemble julianDay now */
	if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	}

	yydate.isBce = 0;
	yydate.julianDay = WeekdayOnOrBefore(yyDayOfWeek, yydate.julianDay + 6)
		+ 7 * yyDayOrdinal;
	if (yyDayOrdinal > 0) {
	    yydate.julianDay -= 7;
	}
	info->flags |= CLF_ASSEMBLE_DATE|CLF_ASSEMBLE_SECONDS;
    }







|







4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228

	/* if needed assemble julianDay now */
	if (info->flags & CLF_ASSEMBLE_JULIANDAY) {
	    GetJulianDayFromEraYearMonthDay(&yydate, GREGORIAN_CHANGE_DATE);
	    info->flags &= ~CLF_ASSEMBLE_JULIANDAY;
	}

	yydate.isBce = false;
	yydate.julianDay = WeekdayOnOrBefore(yyDayOfWeek, yydate.julianDay + 6)
		+ 7 * yyDayOrdinal;
	if (yyDayOrdinal > 0) {
	    yydate.julianDay -= 7;
	}
	info->flags |= CLF_ASSEMBLE_DATE|CLF_ASSEMBLE_SECONDS;
    }
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[])	/* Parameter values */
{
    static const char *syntax = "clock add clockval|now ?number units?..."
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE?";
    ClockClientData *dataPtr = (ClockClientData *)clientData;
    int ret;
    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateInfo yy;		/* Common structure used for parsing */
    DateInfo *info = &yy;

    /* add "week" to units also (because otherwise ambiguous) */
    static const char *const units[] = {
	"years",	"months",	    "week",	    "weeks",







<







4391
4392
4393
4394
4395
4396
4397

4398
4399
4400
4401
4402
4403
4404
    int objc,			/* Parameter count */
    Tcl_Obj *const objv[])	/* Parameter values */
{
    static const char *syntax = "clock add clockval|now ?number units?..."
	    "?-gmt boolean? "
	    "?-locale LOCALE? ?-timezone ZONE?";
    ClockClientData *dataPtr = (ClockClientData *)clientData;

    ClockFmtScnCmdArgs opts;	/* Format, locale, timezone and base */
    DateInfo yy;		/* Common structure used for parsing */
    DateInfo *info = &yy;

    /* add "week" to units also (because otherwise ambiguous) */
    static const char *const units[] = {
	"years",	"months",	    "week",	    "weeks",
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
    ClockInitDateInfo(&yy);

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_ADD, "-gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* time together as seconds of the day */
    yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;







|







4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
    ClockInitDateInfo(&yy);

    /*
     * Extract values for the keywords.
     */

    ClockInitFmtScnArgs(dataPtr, interp, &opts);
    int ret = ClockParseFmtScnArgs(&opts, &yy.date, objc, objv,
	    CLC_OP_ADD, "-gmt, -locale, or -timezone");
    if (ret != TCL_OK) {
	goto done;
    }

    /* time together as seconds of the day */
    yySecondOfDay = yydate.localSeconds % SECONDS_PER_DAY;
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
	Tcl_Obj *returnOpts;
	Tcl_Obj *objResult;
	Tcl_Obj *errorStack;
	int resetErrorStack;
    } InterpState;

    Interp *iPtr = (Interp *)interp;
    int ret, flags = 0;
    InterpState *statePtr;

    if (objc == 1) {
	/* wrong # args : */
	return Tcl_CatchObjCmd(NULL, interp, objc, objv);
    }

    statePtr = (InterpState *)Tcl_SaveInterpState(interp, 0);
    if (!statePtr->errorInfo) {
	/* todo: avoid traced get of errorInfo here */
	TclInitObjRef(statePtr->errorInfo,
		Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, 0));
	flags |= ERR_LEGACY_COPY;
    }
    if (!statePtr->errorCode) {
	/* todo: avoid traced get of errorCode here */
	TclInitObjRef(statePtr->errorCode,
		Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, 0));
	flags |= ERR_LEGACY_COPY;
    }

    /* original catch */
    ret = Tcl_CatchObjCmd(NULL, interp, objc, objv);

    if (ret == TCL_ERROR) {
	Tcl_DiscardInterpState((Tcl_InterpState)statePtr);
	return TCL_ERROR;
    }
    /* overwrite result in state with catch result */
    TclSetObjRef(statePtr->objResult, Tcl_GetObjResult(interp));







|
<






|














|







4614
4615
4616
4617
4618
4619
4620
4621

4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
	Tcl_Obj *returnOpts;
	Tcl_Obj *objResult;
	Tcl_Obj *errorStack;
	int resetErrorStack;
    } InterpState;

    Interp *iPtr = (Interp *)interp;
    int flags = 0;


    if (objc == 1) {
	/* wrong # args : */
	return Tcl_CatchObjCmd(NULL, interp, objc, objv);
    }

    InterpState *statePtr = (InterpState *)Tcl_SaveInterpState(interp, 0);
    if (!statePtr->errorInfo) {
	/* todo: avoid traced get of errorInfo here */
	TclInitObjRef(statePtr->errorInfo,
		Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, 0));
	flags |= ERR_LEGACY_COPY;
    }
    if (!statePtr->errorCode) {
	/* todo: avoid traced get of errorCode here */
	TclInitObjRef(statePtr->errorCode,
		Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, 0));
	flags |= ERR_LEGACY_COPY;
    }

    /* original catch */
    int ret = Tcl_CatchObjCmd(NULL, interp, objc, objv);

    if (ret == TCL_ERROR) {
	Tcl_DiscardInterpState((Tcl_InterpState)statePtr);
	return TCL_ERROR;
    }
    /* overwrite result in state with catch result */
    TclSetObjRef(statePtr->objResult, Tcl_GetObjResult(interp));