mirror of
https://github.com/mirror/make.git
synced 2025-03-04 14:51:11 +08:00
Remove arbitrary limits on intcmp integers
We don't need to parse strings into C integer values to compare them. * src/function.c (parse_textint): Find boundaries of a numeric string. (func_intcmp): Use parse_textint() to compare integers textually. * tests/scripts/functions/intcmp: Test with extra-large numbers.
This commit is contained in:
parent
9230bfb9ae
commit
7192d0ec4a
@ -1276,6 +1276,49 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
Traverse NUMBER consisting of optional leading white space, optional
|
||||
sign, digits, and optional trailing white space.
|
||||
If number is not of the proper form, diagnose with MSG. Otherwise,
|
||||
return the address of of the first character after NUMBER, store
|
||||
into *SIGN an integer consistent with the number's sign (-1, 0, or 1)
|
||||
and store into *NUMSTART the address of NUMBER's first nonzero digit
|
||||
(if NUMBER contains only zero digits, store the address of the first
|
||||
character after NUMBER).
|
||||
*/
|
||||
static const char *
|
||||
parse_textint (const char *number, const char *msg,
|
||||
int *sign, const char **numstart)
|
||||
{
|
||||
const char *after_sign, *after_number;
|
||||
const char *p = next_token (number);
|
||||
int negative = *p == '-';
|
||||
int nonzero = 0;
|
||||
|
||||
if (*p == '\0')
|
||||
OS (fatal, *expanding_var, _("%s: empty value"), msg);
|
||||
|
||||
p += negative || *p == '+';
|
||||
after_sign = p;
|
||||
|
||||
while (*p == '0')
|
||||
p++;
|
||||
*numstart = p;
|
||||
|
||||
while (ISDIGIT (*p))
|
||||
if (*p++ == '0')
|
||||
nonzero = 1;
|
||||
after_number = p;
|
||||
*sign = negative ? -nonzero : nonzero;
|
||||
|
||||
/* Check for extra non-whitespace stuff after the value. */
|
||||
if (after_number == after_sign || *next_token (p) != '\0')
|
||||
OSS (fatal, *expanding_var, "%s: '%s'", msg, number);
|
||||
|
||||
return after_number;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
$(intcmp lhs,rhs[,lt-part[,eq-part[,gt-part]]])
|
||||
|
||||
@ -1293,34 +1336,40 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
|
||||
static char *
|
||||
func_intcmp (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
int lsign, rsign;
|
||||
const char *lnum, *rnum;
|
||||
char *lhs_str = expand_argument (argv[0], NULL);
|
||||
char *rhs_str = expand_argument (argv[1], NULL);
|
||||
long long lhs, rhs;
|
||||
const char *llim = parse_textint (lhs_str, _("non-numeric first argument to 'intcmp' function"), &lsign, &lnum);
|
||||
const char *rlim = parse_textint (rhs_str, _("non-numeric second argument to 'intcmp' function"), &rsign, &rnum);
|
||||
ptrdiff_t llen = llim - lnum;
|
||||
ptrdiff_t rlen = rlim - rnum;
|
||||
int cmp = lsign - rsign;
|
||||
|
||||
lhs = parse_numeric (lhs_str,
|
||||
_("invalid first argument to 'intcmp' function"));
|
||||
rhs = parse_numeric (rhs_str,
|
||||
_("invalid second argument to 'intcmp' function"));
|
||||
free (lhs_str);
|
||||
free (rhs_str);
|
||||
if (cmp == 0)
|
||||
{
|
||||
cmp = (llen > rlen) - (llen < rlen);
|
||||
if (cmp == 0)
|
||||
cmp = memcmp (lnum, rnum, llen);
|
||||
}
|
||||
|
||||
argv += 2;
|
||||
|
||||
if (*argv == NULL)
|
||||
/* Handle the special case where there are only two arguments. */
|
||||
if (!*argv && cmp == 0)
|
||||
{
|
||||
if (lhs == rhs)
|
||||
{
|
||||
char buf[INTSTR_LENGTH+1];
|
||||
sprintf (buf, "%lld", lhs);
|
||||
o = variable_buffer_output(o, buf, strlen (buf));
|
||||
}
|
||||
return o;
|
||||
if (lsign < 0)
|
||||
o = variable_buffer_output (o, "-", 1);
|
||||
o = variable_buffer_output(o, lnum - !lsign, llen + !lsign);
|
||||
}
|
||||
|
||||
if (lhs >= rhs)
|
||||
free (lhs_str);
|
||||
free (rhs_str);
|
||||
|
||||
if (*argv && cmp >= 0)
|
||||
{
|
||||
++argv;
|
||||
if (lhs > rhs && *argv && *(argv + 1))
|
||||
if (cmp > 0 && *argv && *(argv + 1))
|
||||
++argv;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ z = 0
|
||||
p = 1000000000
|
||||
min = -9223372036854775808
|
||||
max = 9223372036854775807
|
||||
huge = 8857889956778499040639527525992734031025567913257255490371761260681427
|
||||
.RECIPEPREFIX = >
|
||||
all:
|
||||
> @echo 0_1 $(intcmp $n,$n)
|
||||
@ -31,28 +32,36 @@ all:
|
||||
> @echo 4_1 $(intcmp $(max),$(min),lt,eq,gt)
|
||||
> @echo 4_2 $(intcmp $(min),$(min),lt,eq,gt)
|
||||
> @echo 4_3 $(intcmp $(max),$(max),lt,eq,gt)
|
||||
', '', "0_1 -10\n0_2\n0_3\n1_1\n1_2 lt\n1_3\n2_1 lt\n2_2 ge\n2_3 ge\n3_0\n3_1 lt\n3_2 gt\n3_3 eq\n4_0 lt\n4_1 gt\n4_2 eq\n4_3 eq\n");
|
||||
> @echo 5_0 $(intcmp -$(huge),$(huge),lt,eq,gt)
|
||||
> @echo 5_1 $(intcmp $(huge),-$(huge),lt,eq,gt)
|
||||
> @echo 5_2 $(intcmp -$(huge),-$(huge),lt,eq,gt)
|
||||
> @echo 5_3 $(intcmp +$(huge),$(huge),lt,eq,gt)
|
||||
', '', "0_1 -10\n0_2\n0_3\n1_1\n1_2 lt\n1_3\n2_1 lt\n2_2 ge\n2_3 ge\n3_0\n3_1 lt\n3_2 gt\n3_3 eq\n4_0 lt\n4_1 gt\n4_2 eq\n4_3 eq\n5_0 lt\n5_1 gt\n5_2 eq\n5_3 eq\n");
|
||||
|
||||
# Test error conditions
|
||||
|
||||
run_make_test('
|
||||
intcmp-e1: ; @echo $(intcmp 12a,1,foo)
|
||||
intcmp-e2: ; @echo $(intcmp 0,,foo)
|
||||
intcmp-e3: ; @echo $(intcmp -1,9999999999999999999,foo)
|
||||
intcmp-e4: ; @echo $(intcmp -1)
|
||||
intcmp-e5: ; @echo $(intcmp ,55)',
|
||||
intcmp-e3: ; @echo $(intcmp -1,)
|
||||
intcmp-e4: ; @echo $(intcmp ,55)',
|
||||
'intcmp-e1',
|
||||
"#MAKEFILE#:2: *** invalid first argument to 'intcmp' function: '12a'. Stop.",
|
||||
"#MAKEFILE#:2: *** non-numeric first argument to 'intcmp' function: '12a'. Stop.",
|
||||
512);
|
||||
|
||||
run_make_test(undef,
|
||||
'intcmp-e2',
|
||||
"#MAKEFILE#:3: *** invalid second argument to 'intcmp' function: empty value. Stop.",
|
||||
"#MAKEFILE#:3: *** non-numeric second argument to 'intcmp' function: empty value. Stop.",
|
||||
512);
|
||||
|
||||
run_make_test(undef,
|
||||
'intcmp-e3',
|
||||
"#MAKEFILE#:4: *** invalid second argument to 'intcmp' function: '9999999999999999999' out of range. Stop.",
|
||||
"#MAKEFILE#:4: *** non-numeric second argument to 'intcmp' function: empty value. Stop.",
|
||||
512);
|
||||
|
||||
run_make_test(undef,
|
||||
'intcmp-e4',
|
||||
"#MAKEFILE#:5: *** non-numeric first argument to 'intcmp' function: empty value. Stop.",
|
||||
512);
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user