From fb4109fcf1747a450454d72242aea4216986e8a8 Mon Sep 17 00:00:00 2001 From: sebres Date: Sun, 24 Mar 2024 16:37:19 +0000 Subject: still one fix for [1f40aa83c552f597], now for freescan (overflow in tests clock-6.10e/clock-6.10f): rewritten with common str2int now --- generic/tclClockFmt.c | 10 +++++++++ generic/tclDate.c | 56 ++++++++++++++++++++++++--------------------------- generic/tclDate.h | 2 ++ generic/tclGetDate.y | 56 ++++++++++++++++++++++++--------------------------- 4 files changed, 64 insertions(+), 60 deletions(-) diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 76af74c..6ce478f 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -140,6 +140,16 @@ _str2wideInt( *out = val; return TCL_OK; } +int +TclAtoWIe( + Tcl_WideInt *out, + const char *p, + const char *e, + int sign) +{ + return _str2wideInt(out, p, e, sign); +} + #if defined(__GNUC__) || defined(__GNUG__) # pragma GCC reset_options diff --git a/generic/tclDate.c b/generic/tclDate.c index e419585..af07ee1 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -221,7 +221,7 @@ extern int TclDatedebug; union YYSTYPE { - long long Number; + Tcl_WideInt Number; enum _MERIDIAN Meridian; @@ -2512,44 +2512,40 @@ TclDatelex( if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ - /* - * Convert the string into a number; count the number of digits. + /* + * Count the number of digits. */ - long long num = c - '0'; p = (char *)yyInput; - while (isdigit(UCHAR(c = *(++p)))) { - if (num >= 0) { - num *= 10; num += c - '0'; - } - } - yylvalPtr->Number = num; + while (isdigit(UCHAR(*++p))) {}; yyDigitCount = p - yyInput; + /* + * A number with 12 or 14 digits is considered an ISO 8601 date. + */ + if (yyDigitCount == 14 || yyDigitCount == 12) { + /* long form of ISO 8601 (without separator), either + * YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date + * (8 chars is isodate) */ + p = (char *)yyInput+8; + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } + yyDigitCount = 8; + yyInput = p; + location->last_column = yyInput - info->dateStart - 1; + return tISOBASL; + } + /* + * Convert the string into a number + */ + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } yyInput = p; - /* * A number with 6 or more digits is considered an ISO 8601 base. */ - location->last_column = yyInput - info->dateStart - 1; if (yyDigitCount >= 6) { - if (yyDigitCount == 14 || yyDigitCount == 12) { - /* long form of ISO 8601 (without separator), either - * YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date - * (8 chars is isodate) */ - p = (char *)tokStart; - num = *p++ - '0'; - do { - num *= 10; num += *p++ - '0'; - } while (p - tokStart < 8); - yylvalPtr->Number = num; - yyDigitCount = 8; - yyInput = p; - location->last_column = yyInput - info->dateStart - 1; - return tISOBASL; - } - if (yyDigitCount > 14) { /* overflow */ - return tID; - } if (yyDigitCount == 8) { return tISOBAS8; } diff --git a/generic/tclDate.h b/generic/tclDate.h index 8a1e8cd..adc3e85 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -547,6 +547,8 @@ MODULE_SCOPE int ClockMCSetIdx(ClockFmtScnCmdArgs *opts, int mcKey, MODULE_SCOPE char * TclItoAw(char *buf, int val, char padchar, unsigned short int width); +MODULE_SCOPE int + TclAtoWIe(Tcl_WideInt *out, const char *p, const char *e, int sign); MODULE_SCOPE Tcl_Obj* ClockFrmObjGetLocFmtKey(Tcl_Interp *interp, diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 077d751..612845d 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -103,7 +103,7 @@ typedef enum _DSTMODE { %} %union { - long long Number; + Tcl_WideInt Number; enum _MERIDIAN Meridian; } @@ -888,44 +888,40 @@ TclDatelex( if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ - /* - * Convert the string into a number; count the number of digits. + /* + * Count the number of digits. */ - long long num = c - '0'; p = (char *)yyInput; - while (isdigit(UCHAR(c = *(++p)))) { - if (num >= 0) { - num *= 10; num += c - '0'; - } - } - yylvalPtr->Number = num; + while (isdigit(UCHAR(*++p))) {}; yyDigitCount = p - yyInput; + /* + * A number with 12 or 14 digits is considered an ISO 8601 date. + */ + if (yyDigitCount == 14 || yyDigitCount == 12) { + /* long form of ISO 8601 (without separator), either + * YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date + * (8 chars is isodate) */ + p = (char *)yyInput+8; + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } + yyDigitCount = 8; + yyInput = p; + location->last_column = yyInput - info->dateStart - 1; + return tISOBASL; + } + /* + * Convert the string into a number + */ + if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) { + return tID; /* overflow*/ + } yyInput = p; - /* * A number with 6 or more digits is considered an ISO 8601 base. */ - location->last_column = yyInput - info->dateStart - 1; if (yyDigitCount >= 6) { - if (yyDigitCount == 14 || yyDigitCount == 12) { - /* long form of ISO 8601 (without separator), either - * YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date - * (8 chars is isodate) */ - p = (char *)tokStart; - num = *p++ - '0'; - do { - num *= 10; num += *p++ - '0'; - } while (p - tokStart < 8); - yylvalPtr->Number = num; - yyDigitCount = 8; - yyInput = p; - location->last_column = yyInput - info->dateStart - 1; - return tISOBASL; - } - if (yyDigitCount > 14) { /* overflow */ - return tID; - } if (yyDigitCount == 8) { return tISOBAS8; } -- cgit v0.12