1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-23 04:30:24 +02:00

30647, 30649: allow underscores in numeric constants

This commit is contained in:
Peter Stephenson 2012-09-11 16:02:41 +00:00
parent d88365d964
commit e550c98d69
6 changed files with 112 additions and 19 deletions

View file

@ -452,7 +452,7 @@ lexconstant(void)
nptr++;
if (*nptr == 'x' || *nptr == 'X') {
/* Let zstrtol parse number with base */
yyval.u.l = zstrtol(ptr, &ptr, 0);
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
/* Should we set lastbase here? */
lastbase = 16;
return NUM;
@ -466,13 +466,13 @@ lexconstant(void)
* it can't be a base indication (always decimal)
* or a floating point number.
*/
for (ptr2 = nptr; idigit(*ptr2); ptr2++)
for (ptr2 = nptr; idigit(*ptr2) || *ptr2 == '_'; ptr2++)
;
if (ptr2 > nptr && *ptr2 != '.' && *ptr2 != 'e' &&
*ptr2 != 'E' && *ptr2 != '#')
{
yyval.u.l = zstrtol(ptr, &ptr, 0);
yyval.u.l = zstrtol_underscore(ptr, &ptr, 0, 1);
lastbase = 8;
return NUM;
}
@ -481,17 +481,43 @@ lexconstant(void)
}
else
{
while (idigit(*nptr))
while (idigit(*nptr) || *nptr == '_')
nptr++;
}
if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
char *ptr2;
/* it's a float */
yyval.type = MN_FLOAT;
#ifdef USE_LOCALE
prev_locale = dupstring(setlocale(LC_NUMERIC, NULL));
setlocale(LC_NUMERIC, "POSIX");
#endif
if (*nptr == '.') {
nptr++;
while (idigit(*nptr) || *nptr == '_')
nptr++;
}
if (*nptr == 'e' || *nptr == 'E') {
nptr++;
if (*nptr == '+' || *nptr == '-')
nptr++;
while (idigit(*nptr) || *nptr == '_')
nptr++;
}
for (ptr2 = ptr; ptr2 < nptr; ptr2++) {
if (*ptr2 == '_') {
int len = nptr - ptr;
ptr = strdup(ptr);
for (ptr2 = ptr; len; len--) {
if (*ptr2 == '_')
chuck(ptr2);
else
ptr2++;
}
break;
}
}
yyval.u.d = strtod(ptr, &nptr);
#ifdef USE_LOCALE
if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
@ -503,11 +529,12 @@ lexconstant(void)
ptr = nptr;
} else {
/* it's an integer */
yyval.u.l = zstrtol(ptr, &ptr, 10);
yyval.u.l = zstrtol_underscore(ptr, &ptr, 10, 1);
if (*ptr == '#') {
ptr++;
yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l);
lastbase = yyval.u.l;
yyval.u.l = zstrtol_underscore(ptr, &ptr, lastbase, 1);
}
}
return NUM;

View file

@ -2030,13 +2030,20 @@ skipparens(char inpar, char outpar, char **s)
return level;
}
/**/
mod_export zlong
zstrtol(const char *s, char **t, int base)
{
return zstrtol_underscore(s, t, base, 0);
}
/* Convert string to zlong (see zsh.h). This function (without the z) *
* is contained in the ANSI standard C library, but a lot of them seem *
* to be broken. */
/**/
mod_export zlong
zstrtol(const char *s, char **t, int base)
zstrtol_underscore(const char *s, char **t, int base, int underscore)
{
const char *inp, *trunc = NULL;
zulong calc = 0, newcalc = 0;
@ -2062,22 +2069,24 @@ zstrtol(const char *s, char **t, int base)
if (base < 2 || base > 36) {
zerr("invalid base (must be 2 to 36 inclusive): %d", base);
return (zlong)0;
} else if (base <= 10)
for (; *s >= '0' && *s < ('0' + base); s++) {
if (trunc)
} else if (base <= 10) {
for (; (*s >= '0' && *s < ('0' + base)) ||
(underscore && *s == '_'); s++) {
if (trunc || *s == '_')
continue;
newcalc = calc * base + *s - '0';
if (newcalc < calc)
{
trunc = s;
continue;
trunc = s;
continue;
}
calc = newcalc;
}
else
} else {
for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10))
|| (*s >= 'A' && *s < ('A' + base - 10)); s++) {
if (trunc)
|| (*s >= 'A' && *s < ('A' + base - 10))
|| (underscore && *s == '_'); s++) {
if (trunc || *s == '_')
continue;
newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9);
if (newcalc < calc)
@ -2087,6 +2096,7 @@ zstrtol(const char *s, char **t, int base)
}
calc = newcalc;
}
}
/*
* Special case: check for a number that was just too long for