diff options
author | Ron Yorston <rmy@pobox.com> | 2024-05-22 14:05:41 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-05-22 14:05:41 +0100 |
commit | 8248785e1d70b5365e2fc17e17dc2ba861c88dd1 (patch) | |
tree | faa2baed93842559bb5b3efd3bfb553c61627e9e | |
parent | c6b525f2afde0833d21b3f0132961a3b0178bbbb (diff) | |
download | busybox-w32-8248785e1d70b5365e2fc17e17dc2ba861c88dd1.tar.gz busybox-w32-8248785e1d70b5365e2fc17e17dc2ba861c88dd1.tar.bz2 busybox-w32-8248785e1d70b5365e2fc17e17dc2ba861c88dd1.zip |
make: add support for ifeq/ifneq
Add support for the conditional directives ifeq and ifneq.
These follow GNU make in allowing things like:
ifeq (arg1,arg2)
ifeq 'arg1' 'arg2'
In the second case single or double quotes may be used.
Macros are expanded in the two arguments and the resulting strings
are compared.
Adds 240-248 bytes.
-rw-r--r-- | miscutils/make.c | 98 | ||||
-rwxr-xr-x | testsuite/make.tests | 14 |
2 files changed, 96 insertions, 16 deletions
diff --git a/miscutils/make.c b/miscutils/make.c index c69dcec8a..063d0662d 100644 --- a/miscutils/make.c +++ b/miscutils/make.c | |||
@@ -1419,17 +1419,74 @@ enum { | |||
1419 | 1419 | ||
1420 | #define IFDEF 0 | 1420 | #define IFDEF 0 |
1421 | #define IFNDEF 1 | 1421 | #define IFNDEF 1 |
1422 | #define IFEQ 2 | ||
1423 | #define IFNEQ 3 | ||
1422 | #define ELSE 0 | 1424 | #define ELSE 0 |
1423 | #define ENDIF 1 | 1425 | #define ENDIF 1 |
1424 | 1426 | ||
1425 | /* | 1427 | /* |
1428 | * Extract strings following ifeq/ifneq and compare them. | ||
1429 | * Return -1 on error. | ||
1430 | */ | ||
1431 | static int | ||
1432 | compare_strings(char *arg1) | ||
1433 | { | ||
1434 | char *arg2, *end, term, *t1, *t2; | ||
1435 | int ret; | ||
1436 | |||
1437 | // Get first string terminator. | ||
1438 | if (arg1[0] == '(') | ||
1439 | term = ','; | ||
1440 | else if (arg1[0] == '"' || arg1[0] == '\'') | ||
1441 | term = arg1[0]; | ||
1442 | else | ||
1443 | return -1; | ||
1444 | |||
1445 | arg2 = find_char(++arg1, term); | ||
1446 | if (arg2 == NULL) | ||
1447 | return -1; | ||
1448 | *arg2++ = '\0'; | ||
1449 | |||
1450 | // Get second string terminator. | ||
1451 | if (term == ',') { | ||
1452 | term = ')'; | ||
1453 | } else { | ||
1454 | // Skip spaces between quoted strings. | ||
1455 | while (isspace(arg2[0])) | ||
1456 | arg2++; | ||
1457 | if (arg2[0] == '"' || arg2[0] == '\'') | ||
1458 | term = arg2[0]; | ||
1459 | else | ||
1460 | return -1; | ||
1461 | ++arg2; | ||
1462 | } | ||
1463 | |||
1464 | end = find_char(arg2, term); | ||
1465 | if (end == NULL) | ||
1466 | return -1; | ||
1467 | *end++ = '\0'; | ||
1468 | |||
1469 | if (gettok(&end) != NULL) { | ||
1470 | warning("unexpected text"); | ||
1471 | } | ||
1472 | |||
1473 | t1 = expand_macros(arg1, FALSE); | ||
1474 | t2 = expand_macros(arg2, FALSE); | ||
1475 | |||
1476 | ret = strcmp(t1, t2) == 0; | ||
1477 | free(t1); | ||
1478 | free(t2); | ||
1479 | return ret; | ||
1480 | } | ||
1481 | |||
1482 | /* | ||
1426 | * Process conditional directives and return TRUE if the current line | 1483 | * Process conditional directives and return TRUE if the current line |
1427 | * should be skipped. | 1484 | * should be skipped. |
1428 | */ | 1485 | */ |
1429 | static int | 1486 | static int |
1430 | skip_line(const char *str1) | 1487 | skip_line(const char *str1) |
1431 | { | 1488 | { |
1432 | char *copy, *q, *token, *next_token; | 1489 | char *copy, *q, *token; |
1433 | bool new_level = TRUE; | 1490 | bool new_level = TRUE; |
1434 | // Default is to return skip flag for current level | 1491 | // Default is to return skip flag for current level |
1435 | int ret = cstate[clevel] & SKIP_LINE; | 1492 | int ret = cstate[clevel] & SKIP_LINE; |
@@ -1441,11 +1498,9 @@ skip_line(const char *str1) | |||
1441 | copy = xstrdup(str1); | 1498 | copy = xstrdup(str1); |
1442 | q = process_line(copy); | 1499 | q = process_line(copy); |
1443 | if ((token = gettok(&q)) != NULL) { | 1500 | if ((token = gettok(&q)) != NULL) { |
1444 | next_token = gettok(&q); | ||
1445 | |||
1446 | switch (index_in_strings("else\0endif\0", token)) { | 1501 | switch (index_in_strings("else\0endif\0", token)) { |
1447 | case ENDIF: | 1502 | case ENDIF: |
1448 | if (next_token != NULL) | 1503 | if (gettok(&q) != NULL) |
1449 | error_unexpected("text"); | 1504 | error_unexpected("text"); |
1450 | if (clevel == 0) | 1505 | if (clevel == 0) |
1451 | error_unexpected(token); | 1506 | error_unexpected(token); |
@@ -1463,23 +1518,39 @@ skip_line(const char *str1) | |||
1463 | else | 1518 | else |
1464 | cstate[clevel] &= ~SKIP_LINE; | 1519 | cstate[clevel] &= ~SKIP_LINE; |
1465 | 1520 | ||
1466 | if (next_token == NULL) { | 1521 | token = gettok(&q); |
1522 | if (token == NULL) { | ||
1467 | // Simple else with no conditional directive | 1523 | // Simple else with no conditional directive |
1468 | cstate[clevel] &= ~EXPECT_ELSE; | 1524 | cstate[clevel] &= ~EXPECT_ELSE; |
1469 | ret = TRUE; | 1525 | ret = TRUE; |
1470 | goto end; | 1526 | goto end; |
1471 | } else { | 1527 | } else { |
1472 | // A conditional directive is now required ('else if'). | 1528 | // A conditional directive is now required ('else if'). |
1473 | token = next_token; | ||
1474 | next_token = gettok(&q); | ||
1475 | new_level = FALSE; | 1529 | new_level = FALSE; |
1476 | } | 1530 | } |
1477 | break; | ||
1478 | } | 1531 | } |
1479 | 1532 | ||
1480 | key = index_in_strings("ifdef\0ifndef\0", token); | 1533 | key = index_in_strings("ifdef\0ifndef\0ifeq\0ifneq\0", token); |
1481 | if (key != -1) { | 1534 | if (key != -1) { |
1482 | if (next_token != NULL && gettok(&q) == NULL) { | 1535 | int match; |
1536 | |||
1537 | if (key == IFDEF || key == IFNDEF) { | ||
1538 | // ifdef/ifndef: find out if macro is defined. | ||
1539 | char *name = gettok(&q); | ||
1540 | if (name != NULL && gettok(&q) == NULL) { | ||
1541 | char *t = expand_macros(name, FALSE); | ||
1542 | struct macro *mp = getmp(t); | ||
1543 | match = mp != NULL && mp->m_val[0] != '\0'; | ||
1544 | free(t); | ||
1545 | } else { | ||
1546 | match = -1; | ||
1547 | } | ||
1548 | } else { | ||
1549 | // ifeq/ifneq: compare strings. | ||
1550 | match = compare_strings(q); | ||
1551 | } | ||
1552 | |||
1553 | if (match >= 0) { | ||
1483 | if (new_level) { | 1554 | if (new_level) { |
1484 | // Start a new level. | 1555 | // Start a new level. |
1485 | if (clevel == IF_MAX) | 1556 | if (clevel == IF_MAX) |
@@ -1494,17 +1565,12 @@ skip_line(const char *str1) | |||
1494 | } | 1565 | } |
1495 | 1566 | ||
1496 | if (!(cstate[clevel] & GOT_MATCH)) { | 1567 | if (!(cstate[clevel] & GOT_MATCH)) { |
1497 | char *t = expand_macros(next_token, FALSE); | 1568 | if (key == IFNDEF || key == IFNEQ) |
1498 | struct macro *mp = getmp(t); | ||
1499 | int match = mp != NULL && mp->m_val[0] != '\0'; | ||
1500 | |||
1501 | if (key == IFNDEF) | ||
1502 | match = !match; | 1569 | match = !match; |
1503 | if (match) { | 1570 | if (match) { |
1504 | cstate[clevel] &= ~SKIP_LINE; | 1571 | cstate[clevel] &= ~SKIP_LINE; |
1505 | cstate[clevel] |= GOT_MATCH; | 1572 | cstate[clevel] |= GOT_MATCH; |
1506 | } | 1573 | } |
1507 | free(t); | ||
1508 | } | 1574 | } |
1509 | } else { | 1575 | } else { |
1510 | error("invalid condition"); | 1576 | error("invalid condition"); |
diff --git a/testsuite/make.tests b/testsuite/make.tests index 5119a77d3..ba3855973 100755 --- a/testsuite/make.tests +++ b/testsuite/make.tests | |||
@@ -553,6 +553,20 @@ src.o: src.c src.h | |||
553 | ' | 553 | ' |
554 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | 554 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null |
555 | 555 | ||
556 | # ifeq/ifneq conditionals are supported | ||
557 | testing 'make support ifeq and ifneq conditionals' \ | ||
558 | "make -f -" "A OK\nB OK\n" "" ' | ||
559 | A = a | ||
560 | B = b | ||
561 | target: | ||
562 | ifeq ($(A),a) | ||
563 | @echo A OK | ||
564 | endif | ||
565 | ifneq "a" "$B" | ||
566 | @echo B OK | ||
567 | endif | ||
568 | ' | ||
569 | |||
556 | # An empty original suffix indicates that every word should have | 570 | # An empty original suffix indicates that every word should have |
557 | # the new suffix added. If neither suffix is provided the words | 571 | # the new suffix added. If neither suffix is provided the words |
558 | # remain unchanged. | 572 | # remain unchanged. |