diff options
-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. |