aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-05-22 14:05:41 +0100
committerRon Yorston <rmy@pobox.com>2024-05-22 14:05:41 +0100
commit8248785e1d70b5365e2fc17e17dc2ba861c88dd1 (patch)
treefaa2baed93842559bb5b3efd3bfb553c61627e9e
parentc6b525f2afde0833d21b3f0132961a3b0178bbbb (diff)
downloadbusybox-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.c98
-rwxr-xr-xtestsuite/make.tests14
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 */
1431static int
1432compare_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 */
1429static int 1486static int
1430skip_line(const char *str1) 1487skip_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'
554cd .. || exit 1; rm -rf make.tempdir 2>/dev/null 554cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
555 555
556# ifeq/ifneq conditionals are supported
557testing 'make support ifeq and ifneq conditionals' \
558 "make -f -" "A OK\nB OK\n" "" '
559A = a
560B = b
561target:
562ifeq ($(A),a)
563 @echo A OK
564endif
565ifneq "a" "$B"
566 @echo B OK
567endif
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.