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]]])
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;
}
p = 1000000000
min = -9223372036854775808
max = 9223372036854775807
+huge = 8857889956778499040639527525992734031025567913257255490371761260681427
.RECIPEPREFIX = >
all:
> @echo 0_1 $(intcmp $n,$n)
> @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);