summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclClockFmt.c60
-rw-r--r--tests/clock.test14
2 files changed, 54 insertions, 20 deletions
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c
index 40c6c92..4ab2423 100644
--- a/generic/tclClockFmt.c
+++ b/generic/tclClockFmt.c
@@ -28,6 +28,10 @@ TCL_DECLARE_MUTEX(ClockFmtMutex); /* Serializes access to common format list. */
static void ClockFmtScnStorageDelete(ClockFmtScnStorage *fss);
static void ClockFrmScnFinalize(void *);
+#ifndef TCL_CLOCK_FULL_COMPAT
+#define TCL_CLOCK_FULL_COMPAT 1
+#endif
+
/*
* Derivation of tclStringHashKeyType with another allocEntryProc
*/
@@ -1019,7 +1023,8 @@ static const char *
FindTokenBegin(
const char *p,
const char *end,
- ClockScanToken *tok)
+ ClockScanToken *tok,
+ int flags)
{
if (p < end) {
char c;
@@ -1028,15 +1033,19 @@ FindTokenBegin(
switch (tok->map->type) {
case CTOKT_INT:
case CTOKT_WIDE:
- /* should match at least one digit */
- while (!isdigit(UCHAR(*p)) && (p = Tcl_UtfNext(p)) < end) {}
+ if (!(flags & CLF_STRICT)) {
+ /* should match at least one digit or space */
+ while (!isdigit(UCHAR(*p)) && !isspace(UCHAR(*p)) &&
+ (p = Tcl_UtfNext(p)) < end) {}
+ } else {
+ /* should match at least one digit */
+ while (!isdigit(UCHAR(*p)) && (p = Tcl_UtfNext(p)) < end) {}
+ }
return p;
case CTOKT_WORD:
c = *(tok->tokWord.start);
- /* should match at least to the first char of this word */
- while (*p != c && (p = Tcl_UtfNext(p)) < end) {}
- return p;
+ goto findChar;
case CTOKT_SPACE:
while (!isspace(UCHAR(*p)) && (p = Tcl_UtfNext(p)) < end) {}
@@ -1044,7 +1053,15 @@ FindTokenBegin(
case CTOKT_CHAR:
c = *((char *)tok->map->data);
- while (*p != c && (p = Tcl_UtfNext(p)) < end) {}
+findChar:
+ if (!(flags & CLF_STRICT)) {
+ /* should match the char or space */
+ while (*p != c && !isspace(UCHAR(*p)) &&
+ (p = Tcl_UtfNext(p)) < end) {}
+ } else {
+ /* should match the char */
+ while (*p != c && (p = Tcl_UtfNext(p)) < end) {}
+ }
return p;
}
}
@@ -1069,6 +1086,7 @@ FindTokenBegin(
static void
DetermineGreedySearchLen(
+ ClockFmtScnCmdArgs *opts,
DateInfo *info,
ClockScanToken *tok,
int *minLenPtr,
@@ -1083,7 +1101,8 @@ DetermineGreedySearchLen(
if ((tok + 1)->map) {
end -= tok->endDistance + yySpaceCount;
/* find position of next known token */
- p = FindTokenBegin(p, end, tok + 1);
+ p = FindTokenBegin(p, end, tok + 1,
+ TCL_CLOCK_FULL_COMPAT ? opts->flags : CLF_STRICT);
if (p < end) {
minLen = p - yyInput;
}
@@ -1134,7 +1153,8 @@ DetermineGreedySearchLen(
/* try to find laTok between [lookAhMin, lookAhMax] */
while (minLen < maxLen) {
- const char *f = FindTokenBegin(p, end, laTok);
+ const char *f = FindTokenBegin(p, end, laTok,
+ TCL_CLOCK_FULL_COMPAT ? opts->flags : CLF_STRICT);
/* if found (not below lookAhMax) */
if (f < end) {
break;
@@ -1518,7 +1538,7 @@ ClockScnToken_Month_Proc(
int minLen, maxLen;
TclStrIdxTree *idxTree;
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
/* get or create tree in msgcat dict */
@@ -1550,7 +1570,7 @@ ClockScnToken_DayOfWeek_Proc(
char curTok = *tok->tokWord.start;
TclStrIdxTree *idxTree;
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
/* %u %w %Ou %Ow */
if (curTok != 'a' && curTok != 'A'
@@ -1621,7 +1641,7 @@ ClockScnToken_amPmInd_Proc(
int minLen, maxLen;
Tcl_Obj *amPmObj[2];
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
amPmObj[0] = ClockMCGet(opts, MCLIT_AM);
amPmObj[1] = ClockMCGet(opts, MCLIT_PM);
@@ -1656,7 +1676,7 @@ ClockScnToken_LocaleERA_Proc(
int minLen, maxLen;
Tcl_Obj *eraObj[6];
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
eraObj[0] = ClockMCGet(opts, MCLIT_BCE);
eraObj[1] = ClockMCGet(opts, MCLIT_CE);
@@ -1693,7 +1713,7 @@ ClockScnToken_LocaleListMatcher_Proc(
int minLen, maxLen;
TclStrIdxTree *idxTree;
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
/* get or create tree in msgcat dict */
@@ -1716,7 +1736,7 @@ ClockScnToken_LocaleListMatcher_Proc(
static int
ClockScnToken_JDN_Proc(
- TCL_UNUSED(ClockFmtScnCmdArgs *),
+ ClockFmtScnCmdArgs *opts,
DateInfo *info,
ClockScanToken *tok)
{
@@ -1725,7 +1745,7 @@ ClockScnToken_JDN_Proc(
Tcl_WideInt intJD;
int fractJD = 0, fractJDDiv = 1;
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
end = yyInput + maxLen;
@@ -1796,7 +1816,7 @@ ClockScnToken_TimeZone_Proc(
const char *p = yyInput;
Tcl_Obj *tzObjStor = NULL;
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
/* numeric timezone */
if (*p == '+' || *p == '-') {
@@ -1879,7 +1899,7 @@ ClockScnToken_TimeZone_Proc(
static int
ClockScnToken_StarDate_Proc(
- TCL_UNUSED(ClockFmtScnCmdArgs *),
+ ClockFmtScnCmdArgs *opts,
DateInfo *info,
ClockScanToken *tok)
{
@@ -1888,7 +1908,7 @@ ClockScnToken_StarDate_Proc(
int year, fractYear, fractDayDiv, fractDay;
static const char *stardatePref = "stardate ";
- DetermineGreedySearchLen(info, tok, &minLen, &maxLen);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &maxLen);
end = yyInput + maxLen;
@@ -2436,7 +2456,7 @@ ClockScan(
}
}
- DetermineGreedySearchLen(info, tok, &minLen, &size);
+ DetermineGreedySearchLen(opts, info, tok, &minLen, &size);
if (size < map->minSize) {
/* missing input -> error */
diff --git a/tests/clock.test b/tests/clock.test
index a0b2a6a..8072a68 100644
--- a/tests/clock.test
+++ b/tests/clock.test
@@ -37032,12 +37032,26 @@ test clock-44.1 {regression test - time zone name containing hyphen } \
}
} \
-result {12:34:56-0500}
+
test clock-44.2 {regression test - time zone containing only two digits} \
-body {
clock scan 1985-04-12T10:15:30+04 -format %Y-%m-%dT%H:%M:%S%Z
} \
-result 482134530
+test clock-44.3 {regression test - spaces between some scan tokens are optional (TCL_CLOCK_FULL_COMPAT, no-strict only)} \
+ -body {
+ list [clock scan {9 Apr 2024} -format {%d %b%Y} -gmt 1] \
+ [clock scan {Tue, 9 Apr 2024 00:00:00 +0000} -format {%a, %d %b%Y %H:%M:%S %Z} -gmt 1]
+ } \
+ -result {1712620800 1712620800}
+test clock-44.4 {regression test - spaces between all scan tokens are optional (TCL_CLOCK_FULL_COMPAT, no-strict only)} \
+ -body {
+ list [clock scan {9 Apr 2024} -format {%d%b%Y} -gmt 1] \
+ [clock scan {Tue, 9 Apr 2024 00:00:00 +0000} -format {%a,%d%b%Y%H:%M:%S%Z} -gmt 1]
+ } \
+ -result {1712620800 1712620800}
+
test clock-45.1 {compat: scan regression on spaces (multiple spaces in format)} \
-body {
list \