make: clean up comments, code and testsdiff -r1.362 -r1.363 src/usr.bin/make/cond.c
(rillig)
--- src/usr.bin/make/cond.c 2024/02/07 07:21:22 1.362
+++ src/usr.bin/make/cond.c 2024/04/23 22:51:28 1.363
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: cond.c,v 1.362 2024/02/07 07:21:22 rillig Exp $ */ | 1 | /* $NetBSD: cond.c,v 1.363 2024/04/23 22:51:28 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -81,27 +81,27 @@ | @@ -81,27 +81,27 @@ | |||
81 | * of one of the .if directives or the condition in a | 81 | * of one of the .if directives or the condition in a | |
82 | * ':?then:else' variable modifier. | 82 | * ':?then:else' variable modifier. | |
83 | * | 83 | * | |
84 | * Cond_EndFile At the end of reading a makefile, ensure that the | 84 | * Cond_EndFile At the end of reading a makefile, ensure that the | |
85 | * conditional directives are well-balanced. | 85 | * conditional directives are well-balanced. | |
86 | */ | 86 | */ | |
87 | 87 | |||
88 | #include <errno.h> | 88 | #include <errno.h> | |
89 | 89 | |||
90 | #include "make.h" | 90 | #include "make.h" | |
91 | #include "dir.h" | 91 | #include "dir.h" | |
92 | 92 | |||
93 | /* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */ | 93 | /* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */ | |
94 | MAKE_RCSID("$NetBSD: cond.c,v 1.362 2024/02/07 07:21:22 rillig Exp $"); | 94 | MAKE_RCSID("$NetBSD: cond.c,v 1.363 2024/04/23 22:51:28 rillig Exp $"); | |
95 | 95 | |||
96 | /* | 96 | /* | |
97 | * Conditional expressions conform to this grammar: | 97 | * Conditional expressions conform to this grammar: | |
98 | * Or -> And ('||' And)* | 98 | * Or -> And ('||' And)* | |
99 | * And -> Term ('&&' Term)* | 99 | * And -> Term ('&&' Term)* | |
100 | * Term -> Function '(' Argument ')' | 100 | * Term -> Function '(' Argument ')' | |
101 | * Term -> Leaf Operator Leaf | 101 | * Term -> Leaf Operator Leaf | |
102 | * Term -> Leaf | 102 | * Term -> Leaf | |
103 | * Term -> '(' Or ')' | 103 | * Term -> '(' Or ')' | |
104 | * Term -> '!' Term | 104 | * Term -> '!' Term | |
105 | * Leaf -> "string" | 105 | * Leaf -> "string" | |
106 | * Leaf -> Number | 106 | * Leaf -> Number | |
107 | * Leaf -> VariableExpression | 107 | * Leaf -> VariableExpression | |
@@ -414,33 +414,32 @@ CondParser_StringExpr(CondParser *par, c | @@ -414,33 +414,32 @@ CondParser_StringExpr(CondParser *par, c | |||
414 | if (atStart && is_separator(par->p[0])) | 414 | if (atStart && is_separator(par->p[0])) | |
415 | return false; | 415 | return false; | |
416 | 416 | |||
417 | Buf_AddStr(buf, inout_str->str); | 417 | Buf_AddStr(buf, inout_str->str); | |
418 | FStr_Done(inout_str); | 418 | FStr_Done(inout_str); | |
419 | *inout_str = FStr_InitRefer(NULL); /* not finished yet */ | 419 | *inout_str = FStr_InitRefer(NULL); /* not finished yet */ | |
420 | return true; | 420 | return true; | |
421 | } | 421 | } | |
422 | 422 | |||
423 | /* | 423 | /* | |
424 | * Parse a string from an expression or an optionally quoted string, | 424 | * Parse a string from an expression or an optionally quoted string, | |
425 | * on the left-hand and right-hand sides of comparisons. | 425 | * on the left-hand and right-hand sides of comparisons. | |
426 | * | 426 | * | |
427 | * Results: | 427 | * Return the string without any enclosing quotes, or NULL on error. | |
428 | * Returns the string without any enclosing quotes, or NULL on error. | 428 | * Sets out_quoted if the leaf was a quoted string literal. | |
429 | * Sets out_quoted if the leaf was a quoted string literal. | |||
430 | */ | 429 | */ | |
431 | static void | 430 | static FStr | |
432 | CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK, | 431 | CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK, | |
433 | FStr *out_str, bool *out_quoted) | 432 | bool *out_quoted) | |
434 | { | 433 | { | |
435 | Buffer buf; | 434 | Buffer buf; | |
436 | FStr str; | 435 | FStr str; | |
437 | bool quoted; | 436 | bool quoted; | |
438 | const char *start; | 437 | const char *start; | |
439 | 438 | |||
440 | Buf_Init(&buf); | 439 | Buf_Init(&buf); | |
441 | str = FStr_InitRefer(NULL); | 440 | str = FStr_InitRefer(NULL); | |
442 | *out_quoted = quoted = par->p[0] == '"'; | 441 | *out_quoted = quoted = par->p[0] == '"'; | |
443 | start = par->p; | 442 | start = par->p; | |
444 | if (quoted) | 443 | if (quoted) | |
445 | par->p++; | 444 | par->p++; | |
446 | 445 | |||
@@ -482,27 +481,27 @@ CondParser_Leaf(CondParser *par, bool do | @@ -482,27 +481,27 @@ CondParser_Leaf(CondParser *par, bool do | |||
482 | str = FStr_InitRefer(NULL); | 481 | str = FStr_InitRefer(NULL); | |
483 | goto return_str; | 482 | goto return_str; | |
484 | } | 483 | } | |
485 | Buf_AddByte(&buf, par->p[0]); | 484 | Buf_AddByte(&buf, par->p[0]); | |
486 | par->p++; | 485 | par->p++; | |
487 | continue; | 486 | continue; | |
488 | } | 487 | } | |
489 | } | 488 | } | |
490 | return_buf: | 489 | return_buf: | |
491 | str = FStr_InitOwn(buf.data); | 490 | str = FStr_InitOwn(buf.data); | |
492 | buf.data = NULL; | 491 | buf.data = NULL; | |
493 | return_str: | 492 | return_str: | |
494 | Buf_Done(&buf); | 493 | Buf_Done(&buf); | |
495 | *out_str = str; | 494 | return str; | |
496 | } | 495 | } | |
497 | 496 | |||
498 | /* | 497 | /* | |
499 | * Evaluate a "comparison without operator", such as in ".if ${VAR}" or | 498 | * Evaluate a "comparison without operator", such as in ".if ${VAR}" or | |
500 | * ".if 0". | 499 | * ".if 0". | |
501 | */ | 500 | */ | |
502 | static bool | 501 | static bool | |
503 | EvalTruthy(CondParser *par, const char *value, bool quoted) | 502 | EvalTruthy(CondParser *par, const char *value, bool quoted) | |
504 | { | 503 | { | |
505 | double num; | 504 | double num; | |
506 | 505 | |||
507 | if (quoted) | 506 | if (quoted) | |
508 | return value[0] != '\0'; | 507 | return value[0] != '\0'; | |
@@ -592,47 +591,47 @@ CondParser_ComparisonOp(CondParser *par, | @@ -592,47 +591,47 @@ CondParser_ComparisonOp(CondParser *par, | |||
592 | * 0 | 591 | * 0 | |
593 | * ${VAR:Mpattern} | 592 | * ${VAR:Mpattern} | |
594 | * ${VAR} == value | 593 | * ${VAR} == value | |
595 | * ${VAR:U0} < 12345 | 594 | * ${VAR:U0} < 12345 | |
596 | */ | 595 | */ | |
597 | static Token | 596 | static Token | |
598 | CondParser_Comparison(CondParser *par, bool doEval) | 597 | CondParser_Comparison(CondParser *par, bool doEval) | |
599 | { | 598 | { | |
600 | Token t = TOK_ERROR; | 599 | Token t = TOK_ERROR; | |
601 | FStr lhs, rhs; | 600 | FStr lhs, rhs; | |
602 | ComparisonOp op; | 601 | ComparisonOp op; | |
603 | bool lhsQuoted, rhsQuoted; | 602 | bool lhsQuoted, rhsQuoted; | |
604 | 603 | |||
605 | CondParser_Leaf(par, doEval, par->leftUnquotedOK, &lhs, &lhsQuoted); | 604 | lhs = CondParser_Leaf(par, doEval, par->leftUnquotedOK, &lhsQuoted); | |
606 | if (lhs.str == NULL) | 605 | if (lhs.str == NULL) | |
607 | goto done_lhs; | 606 | goto done_lhs; | |
608 | 607 | |||
609 | CondParser_SkipWhitespace(par); | 608 | CondParser_SkipWhitespace(par); | |
610 | 609 | |||
611 | if (!CondParser_ComparisonOp(par, &op)) { | 610 | if (!CondParser_ComparisonOp(par, &op)) { | |
612 | t = ToToken(doEval && EvalTruthy(par, lhs.str, lhsQuoted)); | 611 | t = ToToken(doEval && EvalTruthy(par, lhs.str, lhsQuoted)); | |
613 | goto done_lhs; | 612 | goto done_lhs; | |
614 | } | 613 | } | |
615 | 614 | |||
616 | CondParser_SkipWhitespace(par); | 615 | CondParser_SkipWhitespace(par); | |
617 | 616 | |||
618 | if (par->p[0] == '\0') { | 617 | if (par->p[0] == '\0') { | |
619 | Parse_Error(PARSE_FATAL, | 618 | Parse_Error(PARSE_FATAL, | |
620 | "Missing right-hand side of operator '%s'", opname[op]); | 619 | "Missing right-hand side of operator '%s'", opname[op]); | |
621 | par->printedError = true; | 620 | par->printedError = true; | |
622 | goto done_lhs; | 621 | goto done_lhs; | |
623 | } | 622 | } | |
624 | 623 | |||
625 | CondParser_Leaf(par, doEval, true, &rhs, &rhsQuoted); | 624 | rhs = CondParser_Leaf(par, doEval, true, &rhsQuoted); | |
626 | t = rhs.str == NULL ? TOK_ERROR | 625 | t = rhs.str == NULL ? TOK_ERROR | |
627 | : !doEval ? TOK_FALSE | 626 | : !doEval ? TOK_FALSE | |
628 | : EvalCompare(par, lhs.str, lhsQuoted, op, rhs.str, rhsQuoted); | 627 | : EvalCompare(par, lhs.str, lhsQuoted, op, rhs.str, rhsQuoted); | |
629 | FStr_Done(&rhs); | 628 | FStr_Done(&rhs); | |
630 | 629 | |||
631 | done_lhs: | 630 | done_lhs: | |
632 | FStr_Done(&lhs); | 631 | FStr_Done(&lhs); | |
633 | return t; | 632 | return t; | |
634 | } | 633 | } | |
635 | 634 | |||
636 | /* | 635 | /* | |
637 | * The argument to empty() is a variable name, optionally followed by | 636 | * The argument to empty() is a variable name, optionally followed by | |
638 | * variable modifiers. | 637 | * variable modifiers. |
--- src/usr.bin/make/make.h 2024/04/20 10:18:55 1.330
+++ src/usr.bin/make/make.h 2024/04/23 22:51:28 1.331
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: make.h,v 1.330 2024/04/20 10:18:55 rillig Exp $ */ | 1 | /* $NetBSD: make.h,v 1.331 2024/04/23 22:51:28 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | 4 | * Copyright (c) 1988, 1989, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -389,27 +389,27 @@ typedef struct GNodeFlags { | @@ -389,27 +389,27 @@ typedef struct GNodeFlags { | |||
389 | 389 | |||
390 | typedef struct List StringList; | 390 | typedef struct List StringList; | |
391 | typedef struct ListNode StringListNode; | 391 | typedef struct ListNode StringListNode; | |
392 | 392 | |||
393 | typedef struct List GNodeList; | 393 | typedef struct List GNodeList; | |
394 | typedef struct ListNode GNodeListNode; | 394 | typedef struct ListNode GNodeListNode; | |
395 | 395 | |||
396 | typedef struct SearchPath { | 396 | typedef struct SearchPath { | |
397 | List /* of CachedDir */ dirs; | 397 | List /* of CachedDir */ dirs; | |
398 | } SearchPath; | 398 | } SearchPath; | |
399 | 399 | |||
400 | /* | 400 | /* | |
401 | * A graph node represents a target that can possibly be made, including its | 401 | * A graph node represents a target that can possibly be made, including its | |
402 | * relation to other targets and a lot of other details. | 402 | * relation to other targets. | |
403 | */ | 403 | */ | |
404 | typedef struct GNode { | 404 | typedef struct GNode { | |
405 | /* The target's name, such as "clean" or "make.c" */ | 405 | /* The target's name, such as "clean" or "make.c" */ | |
406 | char *name; | 406 | char *name; | |
407 | /* The unexpanded name of a .USE node */ | 407 | /* The unexpanded name of a .USE node */ | |
408 | char *uname; | 408 | char *uname; | |
409 | /* | 409 | /* | |
410 | * The full pathname of the file belonging to the target. | 410 | * The full pathname of the file belonging to the target. | |
411 | * | 411 | * | |
412 | * XXX: What about .PHONY targets? These don't have an associated | 412 | * XXX: What about .PHONY targets? These don't have an associated | |
413 | * path. | 413 | * path. | |
414 | */ | 414 | */ | |
415 | char *path; | 415 | char *path; | |
@@ -571,28 +571,28 @@ extern bool doing_depend; | @@ -571,28 +571,28 @@ extern bool doing_depend; | |||
571 | extern GNode *defaultNode; | 571 | extern GNode *defaultNode; | |
572 | 572 | |||
573 | /* | 573 | /* | |
574 | * Variables defined internally by make which should not override those set | 574 | * Variables defined internally by make which should not override those set | |
575 | * by makefiles. | 575 | * by makefiles. | |
576 | */ | 576 | */ | |
577 | extern GNode *SCOPE_INTERNAL; | 577 | extern GNode *SCOPE_INTERNAL; | |
578 | /* Variables defined in a global scope, e.g in the makefile itself. */ | 578 | /* Variables defined in a global scope, e.g in the makefile itself. */ | |
579 | extern GNode *SCOPE_GLOBAL; | 579 | extern GNode *SCOPE_GLOBAL; | |
580 | /* Variables defined on the command line. */ | 580 | /* Variables defined on the command line. */ | |
581 | extern GNode *SCOPE_CMDLINE; | 581 | extern GNode *SCOPE_CMDLINE; | |
582 | 582 | |||
583 | /* | 583 | /* | |
584 | * Value returned by Var_Parse when an error is encountered. It actually | 584 | * Value returned by Var_Parse when an error is encountered. It points to an | |
585 | * points to an empty string, so naive callers needn't worry about it. | 585 | * empty string, so naive callers needn't worry about it. | |
586 | */ | 586 | */ | |
587 | extern char var_Error[]; | 587 | extern char var_Error[]; | |
588 | 588 | |||
589 | /* The time at the start of this whole process */ | 589 | /* The time at the start of this whole process */ | |
590 | extern time_t now; | 590 | extern time_t now; | |
591 | 591 | |||
592 | /* | 592 | /* | |
593 | * The list of directories to search when looking for targets (set by the | 593 | * The list of directories to search when looking for targets (set by the | |
594 | * special target .PATH). | 594 | * special target .PATH). | |
595 | */ | 595 | */ | |
596 | extern SearchPath dirSearchPath; | 596 | extern SearchPath dirSearchPath; | |
597 | /* Used for .include "...". */ | 597 | /* Used for .include "...". */ | |
598 | extern SearchPath *parseIncPath; | 598 | extern SearchPath *parseIncPath; | |
@@ -668,31 +668,31 @@ void debug_printf(const char *, ...) MAK | @@ -668,31 +668,31 @@ void debug_printf(const char *, ...) MAK | |||
668 | #define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ | 668 | #define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ | |
669 | DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4)) | 669 | DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4)) | |
670 | #define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ | 670 | #define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ | |
671 | DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4, arg5)) | 671 | DEBUG_IMPL(module, (fmt, arg1, arg2, arg3, arg4, arg5)) | |
672 | 672 | |||
673 | typedef enum PrintVarsMode { | 673 | typedef enum PrintVarsMode { | |
674 | PVM_NONE, | 674 | PVM_NONE, | |
675 | PVM_UNEXPANDED, | 675 | PVM_UNEXPANDED, | |
676 | PVM_EXPANDED | 676 | PVM_EXPANDED | |
677 | } PrintVarsMode; | 677 | } PrintVarsMode; | |
678 | 678 | |||
679 | /* Command line options */ | 679 | /* Command line options */ | |
680 | typedef struct CmdOpts { | 680 | typedef struct CmdOpts { | |
681 | /* -B: whether we are make compatible */ | 681 | /* -B: whether to be compatible to traditional make */ | |
682 | bool compatMake; | 682 | bool compatMake; | |
683 | 683 | |||
684 | /* | 684 | /* | |
685 | * -d: debug control: There is one bit per module. It is up to the | 685 | * -d: debug control: There is one flag per module. It is up to the | |
686 | * module what debug information to print. | 686 | * module what debug information to print. | |
687 | */ | 687 | */ | |
688 | DebugFlags debug; | 688 | DebugFlags debug; | |
689 | 689 | |||
690 | /* -df: debug output is written here - default stderr */ | 690 | /* -df: debug output is written here - default stderr */ | |
691 | FILE *debug_file; | 691 | FILE *debug_file; | |
692 | 692 | |||
693 | /* | 693 | /* | |
694 | * -dL: lint mode | 694 | * -dL: lint mode | |
695 | * | 695 | * | |
696 | * Runs make in strict mode, with additional checks and better error | 696 | * Runs make in strict mode, with additional checks and better error | |
697 | * handling. | 697 | * handling. | |
698 | */ | 698 | */ |
--- src/usr.bin/make/parse.c 2024/04/20 10:18:55 1.720
+++ src/usr.bin/make/parse.c 2024/04/23 22:51:28 1.721
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: parse.c,v 1.720 2024/04/20 10:18:55 rillig Exp $ */ | 1 | /* $NetBSD: parse.c,v 1.721 2024/04/23 22:51:28 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | 4 | * Copyright (c) 1988, 1989, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -95,27 +95,27 @@ | @@ -95,27 +95,27 @@ | |||
95 | */ | 95 | */ | |
96 | 96 | |||
97 | #include <sys/types.h> | 97 | #include <sys/types.h> | |
98 | #include <sys/stat.h> | 98 | #include <sys/stat.h> | |
99 | #include <errno.h> | 99 | #include <errno.h> | |
100 | #include <stdarg.h> | 100 | #include <stdarg.h> | |
101 | 101 | |||
102 | #include "make.h" | 102 | #include "make.h" | |
103 | #include "dir.h" | 103 | #include "dir.h" | |
104 | #include "job.h" | 104 | #include "job.h" | |
105 | #include "pathnames.h" | 105 | #include "pathnames.h" | |
106 | 106 | |||
107 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ | 107 | /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ | |
108 | MAKE_RCSID("$NetBSD: parse.c,v 1.720 2024/04/20 10:18:55 rillig Exp $"); | 108 | MAKE_RCSID("$NetBSD: parse.c,v 1.721 2024/04/23 22:51:28 rillig Exp $"); | |
109 | 109 | |||
110 | /* Detects a multiple-inclusion guard in a makefile. */ | 110 | /* Detects a multiple-inclusion guard in a makefile. */ | |
111 | typedef enum { | 111 | typedef enum { | |
112 | GS_START, /* at the beginning of the file */ | 112 | GS_START, /* at the beginning of the file */ | |
113 | GS_COND, /* after the guard condition */ | 113 | GS_COND, /* after the guard condition */ | |
114 | GS_DONE, /* after the closing .endif */ | 114 | GS_DONE, /* after the closing .endif */ | |
115 | GS_NO /* the file is not guarded */ | 115 | GS_NO /* the file is not guarded */ | |
116 | } GuardState; | 116 | } GuardState; | |
117 | 117 | |||
118 | /* A file being parsed. */ | 118 | /* A file being parsed. */ | |
119 | typedef struct IncludedFile { | 119 | typedef struct IncludedFile { | |
120 | FStr name; /* absolute or relative to the cwd */ | 120 | FStr name; /* absolute or relative to the cwd */ | |
121 | unsigned lineno; /* 1-based */ | 121 | unsigned lineno; /* 1-based */ | |
@@ -1612,56 +1612,56 @@ ParseDependencySources(char *p, GNodeTyp | @@ -1612,56 +1612,56 @@ ParseDependencySources(char *p, GNodeTyp | |||
1612 | * which is where the nodes found for the targets are kept. | 1612 | * which is where the nodes found for the targets are kept. | |
1613 | * | 1613 | * | |
1614 | * The sources are parsed in much the same way as the targets, except | 1614 | * The sources are parsed in much the same way as the targets, except | |
1615 | * that they are expanded using the wildcarding scheme of the C-Shell, | 1615 | * that they are expanded using the wildcarding scheme of the C-Shell, | |
1616 | * and a target is created for each expanded word. Each of the resulting | 1616 | * and a target is created for each expanded word. Each of the resulting | |
1617 | * nodes is then linked to each of the targets as one of its children. | 1617 | * nodes is then linked to each of the targets as one of its children. | |
1618 | * | 1618 | * | |
1619 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled | 1619 | * Certain targets and sources such as .PHONY or .PRECIOUS are handled | |
1620 | * specially, see ParseSpecial. | 1620 | * specially, see ParseSpecial. | |
1621 | * | 1621 | * | |
1622 | * Transformation rules such as '.c.o' are also handled here, see | 1622 | * Transformation rules such as '.c.o' are also handled here, see | |
1623 | * Suff_AddTransform. | 1623 | * Suff_AddTransform. | |
1624 | * | 1624 | * | |
1625 | * Upon return, the value of the line is unspecified. | 1625 | * Upon return, the value of expandedLine is unspecified. | |
1626 | */ | 1626 | */ | |
1627 | static void | 1627 | static void | |
1628 | ParseDependency(char *line, const char *unexpanded_line) | 1628 | ParseDependency(char *expandedLine, const char *unexpandedLine) | |
1629 | { | 1629 | { | |
1630 | char *p; | 1630 | char *p; | |
1631 | SearchPathList *paths; /* search paths to alter when parsing a list | 1631 | SearchPathList *paths; /* search paths to alter when parsing a list | |
1632 | * of .PATH targets */ | 1632 | * of .PATH targets */ | |
1633 | GNodeType targetAttr; /* from special sources */ | 1633 | GNodeType targetAttr; /* from special sources */ | |
1634 | ParseSpecial special; /* in special targets, the children are | 1634 | ParseSpecial special; /* in special targets, the children are | |
1635 | * linked as children of the parent but not | 1635 | * linked as children of the parent but not | |
1636 | * vice versa */ | 1636 | * vice versa */ | |
1637 | GNodeType op; | 1637 | GNodeType op; | |
1638 | 1638 | |||
1639 | DEBUG1(PARSE, "ParseDependency(%s)\n", line); | 1639 | DEBUG1(PARSE, "ParseDependency(%s)\n", expandedLine); | |
1640 | p = line; | 1640 | p = expandedLine; | |
1641 | paths = NULL; | 1641 | paths = NULL; | |
1642 | targetAttr = OP_NONE; | 1642 | targetAttr = OP_NONE; | |
1643 | special = SP_NOT; | 1643 | special = SP_NOT; | |
1644 | 1644 | |||
1645 | if (!ParseDependencyTargets(&p, line, &special, &targetAttr, &paths, | 1645 | if (!ParseDependencyTargets(&p, expandedLine, &special, &targetAttr, | |
1646 | unexpanded_line)) | 1646 | &paths, unexpandedLine)) | |
1647 | goto out; | 1647 | goto out; | |
1648 | 1648 | |||
1649 | if (!Lst_IsEmpty(targets)) | 1649 | if (!Lst_IsEmpty(targets)) | |
1650 | CheckSpecialMundaneMixture(special); | 1650 | CheckSpecialMundaneMixture(special); | |
1651 | 1651 | |||
1652 | op = ParseDependencyOp(&p); | 1652 | op = ParseDependencyOp(&p); | |
1653 | if (op == OP_NONE) { | 1653 | if (op == OP_NONE) { | |
1654 | InvalidLineType(line, unexpanded_line); | 1654 | InvalidLineType(expandedLine, unexpandedLine); | |
1655 | goto out; | 1655 | goto out; | |
1656 | } | 1656 | } | |
1657 | ApplyDependencyOperator(op); | 1657 | ApplyDependencyOperator(op); | |
1658 | 1658 | |||
1659 | pp_skip_whitespace(&p); | 1659 | pp_skip_whitespace(&p); | |
1660 | 1660 | |||
1661 | ParseDependencySources(p, targetAttr, special, &paths); | 1661 | ParseDependencySources(p, targetAttr, special, &paths); | |
1662 | 1662 | |||
1663 | out: | 1663 | out: | |
1664 | if (paths != NULL) | 1664 | if (paths != NULL) | |
1665 | Lst_Free(paths); | 1665 | Lst_Free(paths); | |
1666 | } | 1666 | } | |
1667 | 1667 |
--- src/usr.bin/make/var.c 2024/04/21 21:59:48 1.1104
+++ src/usr.bin/make/var.c 2024/04/23 22:51:28 1.1105
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: var.c,v 1.1104 2024/04/21 21:59:48 rillig Exp $ */ | 1 | /* $NetBSD: var.c,v 1.1105 2024/04/23 22:51:28 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | 4 | * Copyright (c) 1988, 1989, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -71,93 +71,88 @@ | @@ -71,93 +71,88 @@ | |||
71 | /* | 71 | /* | |
72 | * Handling of variables and the expressions formed from them. | 72 | * Handling of variables and the expressions formed from them. | |
73 | * | 73 | * | |
74 | * Variables are set using lines of the form VAR=value. Both the variable | 74 | * Variables are set using lines of the form VAR=value. Both the variable | |
75 | * name and the value can contain references to other variables, by using | 75 | * name and the value can contain references to other variables, by using | |
76 | * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. | 76 | * expressions like ${VAR}, ${VAR:Modifiers}, ${${VARNAME}} or ${VAR:${MODS}}. | |
77 | * | 77 | * | |
78 | * Interface: | 78 | * Interface: | |
79 | * Var_Init Initialize this module. | 79 | * Var_Init Initialize this module. | |
80 | * | 80 | * | |
81 | * Var_End Clean up the module. | 81 | * Var_End Clean up the module. | |
82 | * | 82 | * | |
83 | * Var_Set | 83 | * Var_Set | |
84 | * Var_SetExpand | 84 | * Var_SetExpand Set the value of the variable, creating it if | |
85 | * Set the value of the variable, creating it if | |||
86 | * necessary. | 85 | * necessary. | |
87 | * | 86 | * | |
88 | * Var_Append | 87 | * Var_Append | |
89 | * Var_AppendExpand | 88 | * Var_AppendExpand | |
90 | * Append more characters to the variable, creating it if | 89 | * Append more characters to the variable, creating it if | |
91 | * necessary. A space is placed between the old value and | 90 | * necessary. A space is placed between the old value and | |
92 | * the new one. | 91 | * the new one. | |
93 | * | 92 | * | |
94 | * Var_Exists | 93 | * Var_Exists | |
95 | * Var_ExistsExpand | 94 | * Var_ExistsExpand | |
96 | * See if a variable exists. | 95 | * See if a variable exists. | |
97 | * | 96 | * | |
98 | * Var_Value Return the unexpanded value of a variable, or NULL if | 97 | * Var_Value Return the unexpanded value of a variable, or NULL if | |
99 | * the variable is undefined. | 98 | * the variable is undefined. | |
100 | * | 99 | * | |
101 | * Var_Subst Substitute all expressions in a string. | 100 | * Var_Subst Substitute all expressions in a string. | |
102 | * | 101 | * | |
103 | * Var_Parse Parse an expression such as ${VAR:Mpattern}. | 102 | * Var_Parse Parse an expression such as ${VAR:Mpattern}. | |
104 | * | 103 | * | |
105 | * Var_Delete | 104 | * Var_Delete Delete a variable. | |
106 | * Delete a variable. | |||
107 | * | 105 | * | |
108 | * Var_ReexportVars | 106 | * Var_ReexportVars | |
109 | * Export some or even all variables to the environment | 107 | * Export some or even all variables to the environment | |
110 | * of this process and its child processes. | 108 | * of this process and its child processes. | |
111 | * | 109 | * | |
112 | * Var_Export Export the variable to the environment of this process | 110 | * Var_Export Export the variable to the environment of this process | |
113 | * and its child processes. | 111 | * and its child processes. | |
114 | * | 112 | * | |
115 | * Var_UnExport Don't export the variable anymore. | 113 | * Var_UnExport Don't export the variable anymore. | |
116 | * | 114 | * | |
117 | * Debugging: | 115 | * Debugging: | |
118 | * Var_Stats Print out hashing statistics if in -dh mode. | 116 | * Var_Stats Print out hashing statistics if in -dh mode. | |
119 | * | 117 | * | |
120 | * Var_Dump Print out all variables defined in the given scope. | 118 | * Var_Dump Print out all variables defined in the given scope. | |
121 | * | |||
122 | * XXX: There's a lot of almost duplicate code in these functions that only | |||
123 | * differs in subtle details that are not mentioned in the manual page. | |||
124 | */ | 119 | */ | |
125 | 120 | |||
126 | #include <sys/stat.h> | 121 | #include <sys/stat.h> | |
127 | #include <sys/types.h> | 122 | #include <sys/types.h> | |
128 | #include <regex.h> | 123 | #include <regex.h> | |
129 | #include <errno.h> | 124 | #include <errno.h> | |
130 | #include <inttypes.h> | 125 | #include <inttypes.h> | |
131 | #include <limits.h> | 126 | #include <limits.h> | |
132 | #include <time.h> | 127 | #include <time.h> | |
133 | 128 | |||
134 | #include "make.h" | 129 | #include "make.h" | |
135 | #include "dir.h" | 130 | #include "dir.h" | |
136 | #include "job.h" | 131 | #include "job.h" | |
137 | #include "metachar.h" | 132 | #include "metachar.h" | |
138 | 133 | |||
139 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | 134 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | |
140 | MAKE_RCSID("$NetBSD: var.c,v 1.1104 2024/04/21 21:59:48 rillig Exp $"); | 135 | MAKE_RCSID("$NetBSD: var.c,v 1.1105 2024/04/23 22:51:28 rillig Exp $"); | |
141 | 136 | |||
142 | /* | 137 | /* | |
143 | * Variables are defined using one of the VAR=value assignments. Their | 138 | * Variables are defined using one of the VAR=value assignments. Their | |
144 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers | 139 | * value can be queried by expressions such as $V, ${VAR}, or with modifiers | |
145 | * such as ${VAR:S,from,to,g:Q}. | 140 | * such as ${VAR:S,from,to,g:Q}. | |
146 | * | 141 | * | |
147 | * There are 3 kinds of variables: scope variables, environment variables, | 142 | * There are 3 kinds of variables: scope variables, environment variables, | |
148 | * undefined variables. | 143 | * undefined variables. | |
149 | * | 144 | * | |
150 | * Scope variables are stored in a GNode.scope. The only way to undefine | 145 | * Scope variables are stored in GNode.vars. The only way to undefine | |
151 | * a scope variable is using the .undef directive. In particular, it must | 146 | * a scope variable is using the .undef directive. In particular, it must | |
152 | * not be possible to undefine a variable during the evaluation of an | 147 | * not be possible to undefine a variable during the evaluation of an | |
153 | * expression, or Var.name might point nowhere. (There is another, | 148 | * expression, or Var.name might point nowhere. (There is another, | |
154 | * unintended way to undefine a scope variable, see varmod-loop-delete.mk.) | 149 | * unintended way to undefine a scope variable, see varmod-loop-delete.mk.) | |
155 | * | 150 | * | |
156 | * Environment variables are short-lived. They are returned by VarFind, and | 151 | * Environment variables are short-lived. They are returned by VarFind, and | |
157 | * after using them, they must be freed using VarFreeShortLived. | 152 | * after using them, they must be freed using VarFreeShortLived. | |
158 | * | 153 | * | |
159 | * Undefined variables occur during evaluation of expressions such | 154 | * Undefined variables occur during evaluation of expressions such | |
160 | * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. | 155 | * as ${UNDEF:Ufallback} in Var_Parse and ApplyModifiers. | |
161 | */ | 156 | */ | |
162 | typedef struct Var { | 157 | typedef struct Var { | |
163 | /* | 158 | /* | |
@@ -172,27 +167,27 @@ typedef struct Var { | @@ -172,27 +167,27 @@ typedef struct Var { | |||
172 | 167 | |||
173 | /* The variable came from the command line. */ | 168 | /* The variable came from the command line. */ | |
174 | bool fromCmd:1; | 169 | bool fromCmd:1; | |
175 | 170 | |||
176 | /* | 171 | /* | |
177 | * The variable is short-lived. | 172 | * The variable is short-lived. | |
178 | * These variables are not registered in any GNode, therefore they | 173 | * These variables are not registered in any GNode, therefore they | |
179 | * must be freed after use. | 174 | * must be freed after use. | |
180 | */ | 175 | */ | |
181 | bool shortLived:1; | 176 | bool shortLived:1; | |
182 | 177 | |||
183 | /* | 178 | /* | |
184 | * The variable comes from the environment. | 179 | * The variable comes from the environment. | |
185 | * Appending to its value moves the variable to the global scope. | 180 | * Appending to its value depends on the scope, see var-op-append.mk. | |
186 | */ | 181 | */ | |
187 | bool fromEnvironment:1; | 182 | bool fromEnvironment:1; | |
188 | 183 | |||
189 | /* | 184 | /* | |
190 | * The variable value cannot be changed anymore, and the variable | 185 | * The variable value cannot be changed anymore, and the variable | |
191 | * cannot be deleted. Any attempts to do so are silently ignored, | 186 | * cannot be deleted. Any attempts to do so are silently ignored, | |
192 | * they are logged with -dv though. | 187 | * they are logged with -dv though. | |
193 | * Use .[NO]READONLY: to adjust. | 188 | * Use .[NO]READONLY: to adjust. | |
194 | * | 189 | * | |
195 | * See VAR_SET_READONLY. | 190 | * See VAR_SET_READONLY. | |
196 | */ | 191 | */ | |
197 | bool readOnly:1; | 192 | bool readOnly:1; | |
198 | 193 | |||
@@ -475,31 +470,28 @@ VarFindSubstring(Substring name, GNode * | @@ -475,31 +470,28 @@ VarFindSubstring(Substring name, GNode * | |||
475 | 470 | |||
476 | if (var == NULL && scope != SCOPE_CMDLINE) | 471 | if (var == NULL && scope != SCOPE_CMDLINE) | |
477 | var = GNode_FindVar(SCOPE_CMDLINE, name, nameHash); | 472 | var = GNode_FindVar(SCOPE_CMDLINE, name, nameHash); | |
478 | 473 | |||
479 | if (!opts.checkEnvFirst && var == NULL && scope != SCOPE_GLOBAL) { | 474 | if (!opts.checkEnvFirst && var == NULL && scope != SCOPE_GLOBAL) { | |
480 | var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); | 475 | var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); | |
481 | if (var == NULL && scope != SCOPE_INTERNAL) { | 476 | if (var == NULL && scope != SCOPE_INTERNAL) { | |
482 | /* SCOPE_INTERNAL is subordinate to SCOPE_GLOBAL */ | 477 | /* SCOPE_INTERNAL is subordinate to SCOPE_GLOBAL */ | |
483 | var = GNode_FindVar(SCOPE_INTERNAL, name, nameHash); | 478 | var = GNode_FindVar(SCOPE_INTERNAL, name, nameHash); | |
484 | } | 479 | } | |
485 | } | 480 | } | |
486 | 481 | |||
487 | if (var == NULL) { | 482 | if (var == NULL) { | |
488 | FStr envName; | 483 | FStr envName = Substring_Str(name); | |
489 | const char *envValue; | 484 | const char *envValue = getenv(envName.str); | |
490 | ||||
491 | envName = Substring_Str(name); | |||
492 | envValue = getenv(envName.str); | |||
493 | if (envValue != NULL) | 485 | if (envValue != NULL) | |
494 | return VarNew(envName, envValue, true, true, false); | 486 | return VarNew(envName, envValue, true, true, false); | |
495 | FStr_Done(&envName); | 487 | FStr_Done(&envName); | |
496 | 488 | |||
497 | if (opts.checkEnvFirst && scope != SCOPE_GLOBAL) { | 489 | if (opts.checkEnvFirst && scope != SCOPE_GLOBAL) { | |
498 | var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); | 490 | var = GNode_FindVar(SCOPE_GLOBAL, name, nameHash); | |
499 | if (var == NULL && scope != SCOPE_INTERNAL) | 491 | if (var == NULL && scope != SCOPE_INTERNAL) | |
500 | var = GNode_FindVar(SCOPE_INTERNAL, name, | 492 | var = GNode_FindVar(SCOPE_INTERNAL, name, | |
501 | nameHash); | 493 | nameHash); | |
502 | return var; | 494 | return var; | |
503 | } | 495 | } | |
504 | 496 | |||
505 | return NULL; | 497 | return NULL; | |
@@ -994,29 +986,30 @@ Var_SetWithFlags(GNode *scope, const cha | @@ -994,29 +986,30 @@ Var_SetWithFlags(GNode *scope, const cha | |||
994 | scope->name, name, val); | 986 | scope->name, name, val); | |
995 | return; | 987 | return; | |
996 | } | 988 | } | |
997 | 989 | |||
998 | /* | 990 | /* | |
999 | * Only look for a variable in the given scope since anything set | 991 | * Only look for a variable in the given scope since anything set | |
1000 | * here will override anything in a lower scope, so there's not much | 992 | * here will override anything in a lower scope, so there's not much | |
1001 | * point in searching them all. | 993 | * point in searching them all. | |
1002 | */ | 994 | */ | |
1003 | v = VarFind(name, scope, false); | 995 | v = VarFind(name, scope, false); | |
1004 | if (v == NULL) { | 996 | if (v == NULL) { | |
1005 | if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) { | 997 | if (scope == SCOPE_CMDLINE && !(flags & VAR_SET_NO_EXPORT)) { | |
1006 | /* | 998 | /* | |
1007 | * This var would normally prevent the same name being | 999 | * This variable would normally prevent the same name | |
1008 | * added to SCOPE_GLOBAL, so delete it from there if | 1000 | * being added to SCOPE_GLOBAL, so delete it from | |
1009 | * needed. Otherwise -V name may show the wrong value. | 1001 | * there if needed. Otherwise -V name may show the | |
1002 | * wrong value. | |||
1010 | * | 1003 | * | |
1011 | * See ExistsInCmdline. | 1004 | * See ExistsInCmdline. | |
1012 | */ | 1005 | */ | |
1013 | Var_Delete(SCOPE_GLOBAL, name); | 1006 | Var_Delete(SCOPE_GLOBAL, name); | |
1014 | } | 1007 | } | |
1015 | if (strcmp(name, ".SUFFIXES") == 0) { | 1008 | if (strcmp(name, ".SUFFIXES") == 0) { | |
1016 | /* special: treat as read-only */ | 1009 | /* special: treat as read-only */ | |
1017 | DEBUG3(VAR, | 1010 | DEBUG3(VAR, | |
1018 | "%s: ignoring '%s = %s' as it is read-only\n", | 1011 | "%s: ignoring '%s = %s' as it is read-only\n", | |
1019 | scope->name, name, val); | 1012 | scope->name, name, val); | |
1020 | return; | 1013 | return; | |
1021 | } | 1014 | } | |
1022 | v = VarAdd(name, val, scope, flags); | 1015 | v = VarAdd(name, val, scope, flags); | |
@@ -4706,30 +4699,29 @@ VarSubstPlain(const char **pp, Buffer *r | @@ -4706,30 +4699,29 @@ VarSubstPlain(const char **pp, Buffer *r | |||
4706 | const char *start = p; | 4699 | const char *start = p; | |
4707 | 4700 | |||
4708 | for (p++; *p != '$' && *p != '\0'; p++) | 4701 | for (p++; *p != '$' && *p != '\0'; p++) | |
4709 | continue; | 4702 | continue; | |
4710 | Buf_AddRange(res, start, p); | 4703 | Buf_AddRange(res, start, p); | |
4711 | *pp = p; | 4704 | *pp = p; | |
4712 | } | 4705 | } | |
4713 | 4706 | |||
4714 | /* | 4707 | /* | |
4715 | * Expand all expressions like $V, ${VAR}, $(VAR:Modifiers) in the | 4708 | * Expand all expressions like $V, ${VAR}, $(VAR:Modifiers) in the | |
4716 | * given string. | 4709 | * given string. | |
4717 | * | 4710 | * | |
4718 | * Input: | 4711 | * Input: | |
4719 | * str The string in which the expressions are | 4712 | * str The string in which the expressions are expanded. | |
4720 | * expanded. | 4713 | * scope The scope in which to start searching for variables. | |
4721 | * scope The scope in which to start searching for | 4714 | * The other scopes are searched as well. | |
4722 | * variables. The other scopes are searched as well. | |||
4723 | * emode The mode for parsing or evaluating subexpressions. | 4715 | * emode The mode for parsing or evaluating subexpressions. | |
4724 | */ | 4716 | */ | |
4725 | char * | 4717 | char * | |
4726 | Var_Subst(const char *str, GNode *scope, VarEvalMode emode) | 4718 | Var_Subst(const char *str, GNode *scope, VarEvalMode emode) | |
4727 | { | 4719 | { | |
4728 | const char *p = str; | 4720 | const char *p = str; | |
4729 | Buffer res; | 4721 | Buffer res; | |
4730 | 4722 | |||
4731 | /* | 4723 | /* | |
4732 | * Set true if an error has already been reported, to prevent a | 4724 | * Set true if an error has already been reported, to prevent a | |
4733 | * plethora of messages when recursing | 4725 | * plethora of messages when recursing | |
4734 | */ | 4726 | */ | |
4735 | static bool errorReported; | 4727 | static bool errorReported; |
--- src/usr.bin/make/unit-tests/cmd-errors-jobs.exp 2024/04/20 10:18:55 1.5
+++ src/usr.bin/make/unit-tests/cmd-errors-jobs.exp 2024/04/23 22:51:28 1.6
@@ -1,9 +1,9 @@ | @@ -1,9 +1,9 @@ | |||
1 | : undefined--eol | 1 | : undefined--eol | |
2 | make: in target "unclosed-variable": Unclosed variable "UNCLOSED" | 2 | make: in target "unclosed-expression": Unclosed variable "UNCLOSED" | |
3 | : unclosed-variable- | 3 | : unclosed-expression- | |
4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | 4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | |
5 | : unclosed-modifier- | 5 | : unclosed-modifier- | |
6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | 6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | |
7 | : unknown-modifier--eol | 7 | : unknown-modifier--eol | |
8 | : end-eol | 8 | : end-eol | |
9 | exit status 0 | 9 | exit status 0 |
--- src/usr.bin/make/unit-tests/cmd-errors-lint.exp 2024/04/20 10:18:55 1.5
+++ src/usr.bin/make/unit-tests/cmd-errors-lint.exp 2024/04/23 22:51:28 1.6
@@ -1,9 +1,9 @@ | @@ -1,9 +1,9 @@ | |||
1 | : undefined | 1 | : undefined | |
2 | make: in target "unclosed-variable": Unclosed variable "UNCLOSED" | 2 | make: in target "unclosed-expression": Unclosed variable "UNCLOSED" | |
3 | : unclosed-variable | 3 | : unclosed-expression | |
4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | 4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | |
5 | : unclosed-modifier | 5 | : unclosed-modifier | |
6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | 6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | |
7 | : unknown-modifier | 7 | : unknown-modifier | |
8 | : end | 8 | : end | |
9 | exit status 2 | 9 | exit status 2 |
--- src/usr.bin/make/unit-tests/cmd-errors.mk 2022/09/25 12:51:37 1.5
+++ src/usr.bin/make/unit-tests/cmd-errors.mk 2024/04/23 22:51:28 1.6
@@ -1,27 +1,28 @@ | @@ -1,27 +1,28 @@ | |||
1 | # $NetBSD: cmd-errors.mk,v 1.5 2022/09/25 12:51:37 rillig Exp $ | 1 | # $NetBSD: cmd-errors.mk,v 1.6 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Demonstrate how errors in variable expansions affect whether the commands | 3 | # Demonstrate how errors in expressions affect whether the commands | |
4 | # are actually executed in compat mode. | 4 | # are actually executed in compat mode. | |
5 | 5 | |||
6 | all: undefined unclosed-variable unclosed-modifier unknown-modifier end | 6 | all: undefined unclosed-expression unclosed-modifier unknown-modifier end | |
7 | 7 | |||
8 | # Undefined variables are not an error. They expand to empty strings. | 8 | # Undefined variables in expressions are not an error. They expand to empty | |
9 | # strings. | |||
9 | undefined: | 10 | undefined: | |
10 | : $@-${UNDEFINED}-eol | 11 | : $@-${UNDEFINED}-eol | |
11 | 12 | |||
12 | # XXX: As of 2020-11-01, this command is executed even though it contains | 13 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
13 | # parse errors. | 14 | # parse errors. | |
14 | unclosed-variable: | 15 | unclosed-expression: | |
15 | : $@-${UNCLOSED | 16 | : $@-${UNCLOSED | |
16 | 17 | |||
17 | # XXX: As of 2020-11-01, this command is executed even though it contains | 18 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
18 | # parse errors. | 19 | # parse errors. | |
19 | unclosed-modifier: | 20 | unclosed-modifier: | |
20 | : $@-${UNCLOSED: | 21 | : $@-${UNCLOSED: | |
21 | 22 | |||
22 | # XXX: As of 2020-11-01, this command is executed even though it contains | 23 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
23 | # parse errors. | 24 | # parse errors. | |
24 | unknown-modifier: | 25 | unknown-modifier: | |
25 | : $@-${UNKNOWN:Z}-eol | 26 | : $@-${UNKNOWN:Z}-eol | |
26 | 27 | |||
27 | end: | 28 | end: |
--- src/usr.bin/make/unit-tests/cmd-errors-jobs.mk 2024/04/20 10:18:55 1.3
+++ src/usr.bin/make/unit-tests/cmd-errors-jobs.mk 2024/04/23 22:51:28 1.4
@@ -1,31 +1,32 @@ | @@ -1,31 +1,32 @@ | |||
1 | # $NetBSD: cmd-errors-jobs.mk,v 1.3 2024/04/20 10:18:55 rillig Exp $ | 1 | # $NetBSD: cmd-errors-jobs.mk,v 1.4 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Demonstrate how errors in variable expansions affect whether the commands | 3 | # Demonstrate how errors in expressions affect whether the commands | |
4 | # are actually executed in jobs mode. | 4 | # are actually executed in jobs mode. | |
5 | 5 | |||
6 | .MAKEFLAGS: -j1 | 6 | .MAKEFLAGS: -j1 | |
7 | 7 | |||
8 | all: undefined unclosed-variable unclosed-modifier unknown-modifier end | 8 | all: undefined unclosed-expression unclosed-modifier unknown-modifier end | |
9 | 9 | |||
10 | # Undefined variables are not an error. They expand to empty strings. | 10 | # Undefined variables in expressions are not an error. They expand to empty | |
11 | # strings. | |||
11 | # expect: : undefined--eol | 12 | # expect: : undefined--eol | |
12 | undefined: | 13 | undefined: | |
13 | : $@-${UNDEFINED}-eol | 14 | : $@-${UNDEFINED}-eol | |
14 | 15 | |||
15 | # XXX: This command is executed even though it contains parse errors. | 16 | # XXX: This command is executed even though it contains parse errors. | |
16 | # expect: make: in target "unclosed-variable": Unclosed variable "UNCLOSED" | 17 | # expect: make: in target "unclosed-expression": Unclosed variable "UNCLOSED" | |
17 | # expect: : unclosed-variable- | 18 | # expect: : unclosed-expression- | |
18 | unclosed-variable: | 19 | unclosed-expression: | |
19 | : $@-${UNCLOSED | 20 | : $@-${UNCLOSED | |
20 | 21 | |||
21 | # XXX: This command is executed even though it contains parse errors. | 22 | # XXX: This command is executed even though it contains parse errors. | |
22 | # expect: make: Unclosed expression, expecting '}' for "UNCLOSED" | 23 | # expect: make: Unclosed expression, expecting '}' for "UNCLOSED" | |
23 | # expect: : unclosed-modifier- | 24 | # expect: : unclosed-modifier- | |
24 | unclosed-modifier: | 25 | unclosed-modifier: | |
25 | : $@-${UNCLOSED: | 26 | : $@-${UNCLOSED: | |
26 | 27 | |||
27 | # XXX: This command is executed even though it contains parse errors. | 28 | # XXX: This command is executed even though it contains parse errors. | |
28 | # expect: make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | 29 | # expect: make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | |
29 | # expect: : unknown-modifier--eol | 30 | # expect: : unknown-modifier--eol | |
30 | unknown-modifier: | 31 | unknown-modifier: | |
31 | : $@-${UNKNOWN:Z}-eol | 32 | : $@-${UNKNOWN:Z}-eol |
--- src/usr.bin/make/unit-tests/cmd-errors-lint.mk 2020/11/02 20:43:27 1.1
+++ src/usr.bin/make/unit-tests/cmd-errors-lint.mk 2024/04/23 22:51:28 1.2
@@ -1,30 +1,31 @@ | @@ -1,30 +1,31 @@ | |||
1 | # $NetBSD: cmd-errors-lint.mk,v 1.1 2020/11/02 20:43:27 rillig Exp $ | 1 | # $NetBSD: cmd-errors-lint.mk,v 1.2 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Demonstrate how errors in variable expansions affect whether the commands | 3 | # Demonstrate how errors in expressions affect whether the commands | |
4 | # are actually executed. | 4 | # are actually executed. | |
5 | 5 | |||
6 | .MAKEFLAGS: -dL | 6 | .MAKEFLAGS: -dL | |
7 | 7 | |||
8 | all: undefined unclosed-variable unclosed-modifier unknown-modifier end | 8 | all: undefined unclosed-expression unclosed-modifier unknown-modifier end | |
9 | 9 | |||
10 | # Undefined variables are not an error. They expand to empty strings. | 10 | # Undefined variables in expressions are not an error. They expand to empty | |
11 | # strings. | |||
11 | undefined: | 12 | undefined: | |
12 | : $@ ${UNDEFINED} | 13 | : $@ ${UNDEFINED} | |
13 | 14 | |||
14 | # XXX: As of 2020-11-01, this obvious syntax error is not detected. | 15 | # XXX: As of 2020-11-01, this obvious syntax error is not detected. | |
15 | # XXX: As of 2020-11-01, this command is executed even though it contains | 16 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
16 | # parse errors. | 17 | # parse errors. | |
17 | unclosed-variable: | 18 | unclosed-expression: | |
18 | : $@ ${UNCLOSED | 19 | : $@ ${UNCLOSED | |
19 | 20 | |||
20 | # XXX: As of 2020-11-01, this obvious syntax error is not detected. | 21 | # XXX: As of 2020-11-01, this obvious syntax error is not detected. | |
21 | # XXX: As of 2020-11-01, this command is executed even though it contains | 22 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
22 | # parse errors. | 23 | # parse errors. | |
23 | unclosed-modifier: | 24 | unclosed-modifier: | |
24 | : $@ ${UNCLOSED: | 25 | : $@ ${UNCLOSED: | |
25 | 26 | |||
26 | # XXX: As of 2020-11-01, this command is executed even though it contains | 27 | # XXX: As of 2020-11-01, this command is executed even though it contains | |
27 | # parse errors. | 28 | # parse errors. | |
28 | unknown-modifier: | 29 | unknown-modifier: | |
29 | : $@ ${UNKNOWN:Z} | 30 | : $@ ${UNKNOWN:Z} | |
30 | 31 |
--- src/usr.bin/make/unit-tests/cmd-errors.exp 2024/04/20 10:18:55 1.8
+++ src/usr.bin/make/unit-tests/cmd-errors.exp 2024/04/23 22:51:28 1.9
@@ -1,9 +1,9 @@ | @@ -1,9 +1,9 @@ | |||
1 | : undefined--eol | 1 | : undefined--eol | |
2 | make: in target "unclosed-variable": Unclosed variable "UNCLOSED" | 2 | make: in target "unclosed-expression": Unclosed variable "UNCLOSED" | |
3 | : unclosed-variable- | 3 | : unclosed-expression- | |
4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | 4 | make: Unclosed expression, expecting '}' for "UNCLOSED" | |
5 | : unclosed-modifier- | 5 | : unclosed-modifier- | |
6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | 6 | make: in target "unknown-modifier": while evaluating variable "UNKNOWN": Unknown modifier "Z" | |
7 | : unknown-modifier--eol | 7 | : unknown-modifier--eol | |
8 | : end-eol | 8 | : end-eol | |
9 | exit status 0 | 9 | exit status 0 |
--- src/usr.bin/make/unit-tests/cond-func-defined.exp 2023/11/19 21:47:52 1.8
+++ src/usr.bin/make/unit-tests/cond-func-defined.exp 2024/04/23 22:51:28 1.9
@@ -1,8 +1,5 @@ | @@ -1,8 +1,5 @@ | |||
1 | make: "cond-func-defined.mk" line 24: Missing closing parenthesis for defined() | 1 | make: "cond-func-defined.mk" line 24: Missing closing parenthesis for defined() | |
2 | make: "cond-func-defined.mk" line 34: Missing closing parenthesis for defined() | 2 | make: "cond-func-defined.mk" line 34: Missing closing parenthesis for defined() | |
3 | make: "cond-func-defined.mk" line 47: In .for loops, expressions for the loop variables are | |||
4 | make: "cond-func-defined.mk" line 49: substituted at evaluation time. There is no actual variable | |||
5 | make: "cond-func-defined.mk" line 51: involved, even if it feels like it. | |||
6 | make: Fatal errors encountered -- cannot continue | 3 | make: Fatal errors encountered -- cannot continue | |
7 | make: stopped in unit-tests | 4 | make: stopped in unit-tests | |
8 | exit status 1 | 5 | exit status 1 |
--- src/usr.bin/make/unit-tests/cmdline-undefined.mk 2023/11/19 21:47:52 1.4
+++ src/usr.bin/make/unit-tests/cmdline-undefined.mk 2024/04/23 22:51:28 1.5
@@ -1,16 +1,16 @@ | @@ -1,16 +1,16 @@ | |||
1 | # $NetBSD: cmdline-undefined.mk,v 1.4 2023/11/19 21:47:52 rillig Exp $ | 1 | # $NetBSD: cmdline-undefined.mk,v 1.5 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for undefined expressions in the command line. | 3 | # Tests for undefined variables in expressions in the command line. | |
4 | 4 | |||
5 | all: | 5 | all: | |
6 | # When the command line is parsed, variable assignments using the | 6 | # When the command line is parsed, variable assignments using the | |
7 | # '=' assignment operator do get their variable name expanded | 7 | # '=' assignment operator do get their variable name expanded | |
8 | # (which probably occurs rarely in practice, if at all), but their | 8 | # (which probably occurs rarely in practice, if at all), but their | |
9 | # variable value is not expanded, as usual. | 9 | # variable value is not expanded, as usual. | |
10 | # | 10 | # | |
11 | @echo 'The = assignment operator' | 11 | @echo 'The = assignment operator' | |
12 | @${.MAKE} -f ${MAKEFILE} print-undefined \ | 12 | @${.MAKE} -f ${MAKEFILE} print-undefined \ | |
13 | CMDLINE='Undefined is $${UNDEFINED}.' | 13 | CMDLINE='Undefined is $${UNDEFINED}.' | |
14 | @echo | 14 | @echo | |
15 | 15 | |||
16 | # The interesting case is using the ':=' assignment operator, which | 16 | # The interesting case is using the ':=' assignment operator, which |
--- src/usr.bin/make/unit-tests/cmdline.mk 2022/06/10 18:58:07 1.4
+++ src/usr.bin/make/unit-tests/cmdline.mk 2024/04/23 22:51:28 1.5
@@ -1,40 +1,40 @@ | @@ -1,40 +1,40 @@ | |||
1 | # $NetBSD: cmdline.mk,v 1.4 2022/06/10 18:58:07 rillig Exp $ | 1 | # $NetBSD: cmdline.mk,v 1.5 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for command line parsing and related special variables. | 3 | # Tests for command line parsing and related special variables. | |
4 | 4 | |||
5 | TMPBASE?= ${TMPDIR:U/tmp/uid${.MAKE.UID}} | 5 | TMPBASE?= ${TMPDIR:U/tmp/uid${.MAKE.UID}} | |
6 | SUB1= a7b41170-53f8-4cc2-bc5c-e4c3dd93ec45 # just a random UUID | 6 | SUB1= a7b41170-53f8-4cc2-bc5c-e4c3dd93ec45 # just a random UUID | |
7 | SUB2= 6a8899d2-d227-4b55-9b6b-f3c8eeb83fd5 # just a random UUID | 7 | SUB2= 6a8899d2-d227-4b55-9b6b-f3c8eeb83fd5 # just a random UUID | |
8 | MAKE_CMD= env TMPBASE=${TMPBASE}/${SUB1} ${.MAKE} -f ${MAKEFILE} -r | 8 | MAKE_CMD= env TMPBASE=${TMPBASE}/${SUB1} ${.MAKE} -f ${MAKEFILE} -r | |
9 | DIR2= ${TMPBASE}/${SUB2} | 9 | DIR2= ${TMPBASE}/${SUB2} | |
10 | DIR12= ${TMPBASE}/${SUB1}/${SUB2} | 10 | DIR12= ${TMPBASE}/${SUB1}/${SUB2} | |
11 | 11 | |||
12 | all: prepare-dirs | 12 | all: prepare-dirs | |
13 | all: makeobjdir-direct makeobjdir-indirect | 13 | all: makeobjdir-direct makeobjdir-indirect | |
14 | all: space-and-comment | 14 | all: space-and-comment | |
15 | 15 | |||
16 | prepare-dirs: | 16 | prepare-dirs: | |
17 | @rm -rf ${DIR2} ${DIR12} | 17 | @rm -rf ${DIR2} ${DIR12} | |
18 | @mkdir -p ${DIR2} ${DIR12} | 18 | @mkdir -p ${DIR2} ${DIR12} | |
19 | 19 | |||
20 | # The .OBJDIR can be set via the MAKEOBJDIR command line variable. | 20 | # The .OBJDIR can be set via the MAKEOBJDIR command line variable. | |
21 | # It must be a command line variable; an environment variable would not work. | 21 | # It must be a command line variable; an environment variable would not work. | |
22 | makeobjdir-direct: | 22 | makeobjdir-direct: | |
23 | @echo $@: | 23 | @echo $@: | |
24 | @${MAKE_CMD} MAKEOBJDIR=${DIR2} show-objdir | 24 | @${MAKE_CMD} MAKEOBJDIR=${DIR2} show-objdir | |
25 | 25 | |||
26 | # The .OBJDIR can be set via the MAKEOBJDIR command line variable, | 26 | # The .OBJDIR can be set via the MAKEOBJDIR command line variable, | |
27 | # and that variable could even contain the usual modifiers. | 27 | # and expressions based on that variable can contain the usual modifiers. | |
28 | # Since the .OBJDIR=MAKEOBJDIR assignment happens very early, | 28 | # Since the .OBJDIR=MAKEOBJDIR assignment happens very early, | |
29 | # the SUB2 variable in the modifier is not defined yet and is therefore empty. | 29 | # the SUB2 variable in the modifier is not defined yet and is therefore empty. | |
30 | # The SUB1 in the resulting path comes from the environment variable TMPBASE, | 30 | # The SUB1 in the resulting path comes from the environment variable TMPBASE, | |
31 | # see MAKE_CMD. | 31 | # see MAKE_CMD. | |
32 | makeobjdir-indirect: | 32 | makeobjdir-indirect: | |
33 | @echo $@: | 33 | @echo $@: | |
34 | @${MAKE_CMD} MAKEOBJDIR='$${TMPBASE}/$${SUB2}' show-objdir | 34 | @${MAKE_CMD} MAKEOBJDIR='$${TMPBASE}/$${SUB2}' show-objdir | |
35 | 35 | |||
36 | show-objdir: | 36 | show-objdir: | |
37 | @echo $@: ${.OBJDIR:Q} | 37 | @echo $@: ${.OBJDIR:Q} | |
38 | 38 | |||
39 | 39 | |||
40 | # Variable assignments in the command line are handled differently from | 40 | # Variable assignments in the command line are handled differently from |
--- src/usr.bin/make/unit-tests/comment.mk 2023/11/19 21:47:52 1.6
+++ src/usr.bin/make/unit-tests/comment.mk 2024/04/23 22:51:28 1.7
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: comment.mk,v 1.6 2023/11/19 21:47:52 rillig Exp $ | 1 | # $NetBSD: comment.mk,v 1.7 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Demonstrate how comments are written in makefiles. | 3 | # Demonstrate how comments are written in makefiles. | |
4 | 4 | |||
5 | # This is a comment. | 5 | # This is a comment. | |
6 | 6 | |||
7 | #\ | 7 | #\ | |
8 | This is a multiline comment. | 8 | This is a multiline comment. | |
9 | 9 | |||
10 | # Another multiline comment \ | 10 | # Another multiline comment \ | |
11 | that \ | 11 | that \ | |
12 | goes \ | 12 | goes \ | |
13 | on and on. | 13 | on and on. | |
14 | 14 | |||
@@ -43,29 +43,29 @@ VAR= value | @@ -43,29 +43,29 @@ VAR= value | |||
43 | # not count as a line continuation, therefore the variable assignment that | 43 | # not count as a line continuation, therefore the variable assignment that | |
44 | # follows is actively interpreted. \\ | 44 | # follows is actively interpreted. \\ | |
45 | VAR= not part of the comment | 45 | VAR= not part of the comment | |
46 | .if ${VAR} != "not part of the comment" | 46 | .if ${VAR} != "not part of the comment" | |
47 | . error | 47 | . error | |
48 | .endif | 48 | .endif | |
49 | 49 | |||
50 | # To escape a comment sign, precede it with a backslash. | 50 | # To escape a comment sign, precede it with a backslash. | |
51 | VAR= \# # Both in the assignment. | 51 | VAR= \# # Both in the assignment. | |
52 | .if ${VAR} != "\#" # And in the comparison. | 52 | .if ${VAR} != "\#" # And in the comparison. | |
53 | . error | 53 | . error | |
54 | .endif | 54 | .endif | |
55 | 55 | |||
56 | # Since 2012-03-24 the variable modifier :[#] does not need to be escaped. | 56 | # Since 2012-03-24 the modifier :[#] does not need to be escaped. | |
57 | # To keep the parsing code simple, any "[#" does not start a comment, even | 57 | # To keep the parsing code simple, the "#" in "[#" does not start a comment, | |
58 | # outside of an expression. | 58 | # regardless of the syntactical context it appears in. | |
59 | WORDS= ${VAR:[#]} [# | 59 | WORDS= ${VAR:[#]} [# | |
60 | .if ${WORDS} != "1 [#" | 60 | .if ${WORDS} != "1 [#" | |
61 | . error | 61 | . error | |
62 | .endif | 62 | .endif | |
63 | 63 | |||
64 | # An odd number of backslashes makes a line continuation, \\\ | 64 | # An odd number of backslashes makes a line continuation, \\\ | |
65 | no matter if it is 3 or 5 \\\\\ | 65 | no matter if it is 3 or 5 \\\\\ | |
66 | or 9 backslashes. \\\\\\\\\ | 66 | or 9 backslashes. \\\\\\\\\ | |
67 | This is the last line of the comment. | 67 | This is the last line of the comment. | |
68 | VAR= no comment anymore | 68 | VAR= no comment anymore | |
69 | .if ${VAR} != "no comment anymore" | 69 | .if ${VAR} != "no comment anymore" | |
70 | . error | 70 | . error | |
71 | .endif | 71 | .endif |
--- src/usr.bin/make/unit-tests/cond-cmp-string.mk 2023/11/19 21:47:52 1.18
+++ src/usr.bin/make/unit-tests/cond-cmp-string.mk 2024/04/23 22:51:28 1.19
@@ -1,41 +1,41 @@ | @@ -1,41 +1,41 @@ | |||
1 | # $NetBSD: cond-cmp-string.mk,v 1.18 2023/11/19 21:47:52 rillig Exp $ | 1 | # $NetBSD: cond-cmp-string.mk,v 1.19 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for string comparisons in .if conditions. | 3 | # Tests for string comparisons in .if conditions. | |
4 | 4 | |||
5 | # This is a simple comparison of string literals. | 5 | # This is a simple comparison of string literals. | |
6 | # Nothing surprising here. | 6 | # Nothing surprising here. | |
7 | .if "str" != "str" | 7 | .if "str" != "str" | |
8 | . error | 8 | . error | |
9 | .endif | 9 | .endif | |
10 | 10 | |||
11 | # The right-hand side of the comparison may be written without quotes. | 11 | # The right-hand side of the comparison may be written without quotes. | |
12 | .if "str" != str | 12 | .if "str" != str | |
13 | . error | 13 | . error | |
14 | .endif | 14 | .endif | |
15 | 15 | |||
16 | # The left-hand side of the comparison must be enclosed in quotes. | 16 | # The left-hand side of the comparison must be enclosed in quotes. | |
17 | # This one is not enclosed in quotes and thus generates an error message. | 17 | # This one is not enclosed in quotes and thus generates an error message. | |
18 | # expect+1: Malformed conditional (str != str) | 18 | # expect+1: Malformed conditional (str != str) | |
19 | .if str != str | 19 | .if str != str | |
20 | . error | 20 | . error | |
21 | .endif | 21 | .endif | |
22 | 22 | |||
23 | # The left-hand side of the comparison requires that any expression | 23 | # An expression that occurs on the left-hand side of the comparison must be | |
24 | # is defined. | 24 | # defined. | |
25 | # | 25 | # | |
26 | # The variable named "" is never defined, nevertheless it can be used as a | 26 | # The variable named "" is never defined, nevertheless it can be used as a | |
27 | # starting point for expressions. Applying the :U modifier to such | 27 | # starting point for an expression. Applying the :U modifier to such an | |
28 | # an undefined expression turns it into a defined expression. | 28 | # undefined expression turns it into a defined expression. | |
29 | # | 29 | # | |
30 | # See ApplyModifier_Defined and DEF_DEFINED. | 30 | # See ApplyModifier_Defined and DEF_DEFINED. | |
31 | .if ${:Ustr} != "str" | 31 | .if ${:Ustr} != "str" | |
32 | . error | 32 | . error | |
33 | .endif | 33 | .endif | |
34 | 34 | |||
35 | # Any character in a string literal may be escaped using a backslash. | 35 | # Any character in a string literal may be escaped using a backslash. | |
36 | # This means that "\n" does not mean a newline but a simple "n". | 36 | # This means that "\n" does not mean a newline but a simple "n". | |
37 | .if "string" != "\s\t\r\i\n\g" | 37 | .if "string" != "\s\t\r\i\n\g" | |
38 | . error | 38 | . error | |
39 | .endif | 39 | .endif | |
40 | 40 | |||
41 | # It is not possible to concatenate two string literals to form a single | 41 | # It is not possible to concatenate two string literals to form a single | |
@@ -59,53 +59,53 @@ | @@ -59,53 +59,53 @@ | |||
59 | # expect+1: Malformed conditional (!("value" === "value")) | 59 | # expect+1: Malformed conditional (!("value" === "value")) | |
60 | .if !("value" === "value") | 60 | .if !("value" === "value") | |
61 | . error | 61 | . error | |
62 | .else | 62 | .else | |
63 | . error | 63 | . error | |
64 | .endif | 64 | .endif | |
65 | 65 | |||
66 | # An expression can be enclosed in double quotes. | 66 | # An expression can be enclosed in double quotes. | |
67 | .if ${:Uword} != "${:Uword}" | 67 | .if ${:Uword} != "${:Uword}" | |
68 | . error | 68 | . error | |
69 | .endif | 69 | .endif | |
70 | 70 | |||
71 | # Between 2003-01-01 (maybe even earlier) and 2020-10-30, adding one of the | 71 | # Between 2003-01-01 (maybe even earlier) and 2020-10-30, adding one of the | |
72 | # characters " \t!=><" directly after an expression resulted in a | 72 | # characters " \t!=><" directly after an expression in a string literal | |
73 | # "Malformed conditional", even though the string was well-formed. | 73 | # resulted in a "Malformed conditional", even though the string was | |
74 | # well-formed. | |||
74 | .if ${:Uword } != "${:Uword} " | 75 | .if ${:Uword } != "${:Uword} " | |
75 | . error | 76 | . error | |
76 | .endif | 77 | .endif | |
77 | # Some other characters worked though, and some didn't. | 78 | # Some other characters worked though, and some didn't. | |
78 | # Those that are mentioned in is_separator didn't work. | 79 | # Those that are mentioned in is_separator didn't work. | |
79 | .if ${:Uword0} != "${:Uword}0" | 80 | .if ${:Uword0} != "${:Uword}0" | |
80 | . error | 81 | . error | |
81 | .endif | 82 | .endif | |
82 | .if ${:Uword&} != "${:Uword}&" | 83 | .if ${:Uword&} != "${:Uword}&" | |
83 | . error | 84 | . error | |
84 | .endif | 85 | .endif | |
85 | .if ${:Uword!} != "${:Uword}!" | 86 | .if ${:Uword!} != "${:Uword}!" | |
86 | . error | 87 | . error | |
87 | .endif | 88 | .endif | |
88 | .if ${:Uword<} != "${:Uword}<" | 89 | .if ${:Uword<} != "${:Uword}<" | |
89 | . error | 90 | . error | |
90 | .endif | 91 | .endif | |
91 | 92 | |||
92 | # Adding another expression to the string literal works though. | 93 | # Adding another expression to the string literal works though. | |
93 | .if ${:Uword} != "${:Uwo}${:Urd}" | 94 | .if ${:Uword} != "${:Uwo}${:Urd}" | |
94 | . error | 95 | . error | |
95 | .endif | 96 | .endif | |
96 | 97 | |||
97 | # Adding a space at the beginning of the quoted expression works | 98 | # Adding a space at the beginning of the quoted expression works though. | |
98 | # though. | |||
99 | .if ${:U word } != " ${:Uword} " | 99 | .if ${:U word } != " ${:Uword} " | |
100 | . error | 100 | . error | |
101 | .endif | 101 | .endif | |
102 | 102 | |||
103 | # If at least one side of the comparison is a string literal, the string | 103 | # If at least one side of the comparison is a string literal, the string | |
104 | # comparison is performed. | 104 | # comparison is performed. | |
105 | .if 12345 != "12345" | 105 | .if 12345 != "12345" | |
106 | . error | 106 | . error | |
107 | .endif | 107 | .endif | |
108 | 108 | |||
109 | # If at least one side of the comparison is a string literal, the string | 109 | # If at least one side of the comparison is a string literal, the string | |
110 | # comparison is performed. The ".0" in the left-hand side makes the two | 110 | # comparison is performed. The ".0" in the left-hand side makes the two | |
111 | # sides of the equation unequal. | 111 | # sides of the equation unequal. | |
@@ -135,20 +135,20 @@ | @@ -135,20 +135,20 @@ | |||
135 | . error | 135 | . error | |
136 | .else | 136 | .else | |
137 | . error | 137 | . error | |
138 | .endif | 138 | .endif | |
139 | 139 | |||
140 | # Strings cannot be compared relationally, only for equality. | 140 | # Strings cannot be compared relationally, only for equality. | |
141 | # expect+1: Comparison with '>=' requires both operands 'string' and 'string' to be numeric | 141 | # expect+1: Comparison with '>=' requires both operands 'string' and 'string' to be numeric | |
142 | .if "string" >= "string" | 142 | .if "string" >= "string" | |
143 | . error | 143 | . error | |
144 | .else | 144 | .else | |
145 | . error | 145 | . error | |
146 | .endif | 146 | .endif | |
147 | 147 | |||
148 | # Two variables with different values compare unequal. | 148 | # Two expressions with different values compare unequal. | |
149 | VAR1= value1 | 149 | VAR1= value1 | |
150 | VAR2= value2 | 150 | VAR2= value2 | |
151 | .if ${VAR1} != ${VAR2} | 151 | .if ${VAR1} != ${VAR2} | |
152 | .else | 152 | .else | |
153 | . error | 153 | . error | |
154 | .endif | 154 | .endif |
--- src/usr.bin/make/unit-tests/cond-func-defined.mk 2023/11/19 21:47:52 1.11
+++ src/usr.bin/make/unit-tests/cond-func-defined.mk 2024/04/23 22:51:28 1.12
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: cond-func-defined.mk,v 1.11 2023/11/19 21:47:52 rillig Exp $ | 1 | # $NetBSD: cond-func-defined.mk,v 1.12 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for the defined() function in .if conditions. | 3 | # Tests for the defined() function in .if conditions. | |
4 | 4 | |||
5 | DEF= defined | 5 | DEF= defined | |
6 | ${:UA B}= variable name with spaces | 6 | ${:UA B}= variable name with spaces | |
7 | 7 | |||
8 | .if !defined(DEF) | 8 | .if !defined(DEF) | |
9 | . error | 9 | . error | |
10 | .endif | 10 | .endif | |
11 | 11 | |||
12 | # Horizontal whitespace (space tab) after the opening parenthesis is ignored. | 12 | # Horizontal whitespace (space tab) after the opening parenthesis is ignored. | |
13 | .if !defined( DEF) | 13 | .if !defined( DEF) | |
14 | . error | 14 | . error | |
@@ -33,29 +33,26 @@ ${:UA B}= variable name with spaces | @@ -33,29 +33,26 @@ ${:UA B}= variable name with spaces | |||
33 | # expect+1: Missing closing parenthesis for defined() | 33 | # expect+1: Missing closing parenthesis for defined() | |
34 | .if defined(DEF | 34 | .if defined(DEF | |
35 | . error | 35 | . error | |
36 | .else | 36 | .else | |
37 | . error | 37 | . error | |
38 | .endif | 38 | .endif | |
39 | 39 | |||
40 | # Variables from .for loops are not defined. | 40 | # Variables from .for loops are not defined. | |
41 | # See directive-for.mk for more details. | 41 | # See directive-for.mk for more details. | |
42 | .for var in value | 42 | .for var in value | |
43 | . if defined(var) | 43 | . if defined(var) | |
44 | . error | 44 | . error | |
45 | . else | 45 | . else | |
46 | # expect+1: In .for loops, expressions for the loop variables are | 46 | # In .for loops, expressions based on the loop variables are substituted at | |
47 | . info In .for loops, expressions for the loop variables are | 47 | # evaluation time. There is no actual variable involved, even if the code in | |
48 | # expect+1: substituted at evaluation time. There is no actual variable | 48 | # the makefiles looks like it. | |
49 | . info substituted at evaluation time. There is no actual variable | |||
50 | # expect+1: involved, even if it feels like it. | |||
51 | . info involved, even if it feels like it. | |||
52 | . endif | 49 | . endif | |
53 | .endfor | 50 | .endfor | |
54 | 51 | |||
55 | # Neither of the conditions is true. Before July 2020, the right-hand | 52 | # Neither of the conditions is true. Before July 2020, the right-hand | |
56 | # condition was evaluated even though it was irrelevant. | 53 | # condition was evaluated even though it was irrelevant. | |
57 | .if defined(UNDEF) && ${UNDEF:Mx} != "" | 54 | .if defined(UNDEF) && ${UNDEF:Mx} != "" | |
58 | . error | 55 | . error | |
59 | .endif | 56 | .endif | |
60 | 57 | |||
61 | all: .PHONY | 58 | all: .PHONY |
--- src/usr.bin/make/unit-tests/varmod-ifelse.mk 2024/04/20 10:18:55 1.27
+++ src/usr.bin/make/unit-tests/varmod-ifelse.mk 2024/04/23 22:51:28 1.28
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: varmod-ifelse.mk,v 1.27 2024/04/20 10:18:55 rillig Exp $ | 1 | # $NetBSD: varmod-ifelse.mk,v 1.28 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for the ${cond:?then:else} variable modifier, which evaluates either | 3 | # Tests for the ${cond:?then:else} variable modifier, which evaluates either | |
4 | # the then-expression or the else-expression, depending on the condition. | 4 | # the then-expression or the else-expression, depending on the condition. | |
5 | # | 5 | # | |
6 | # The modifier was added on 1998-04-01. | 6 | # The modifier was added on 1998-04-01. | |
7 | # | 7 | # | |
8 | # Until 2015-10-11, the modifier always evaluated both the "then" and the | 8 | # Until 2015-10-11, the modifier always evaluated both the "then" and the | |
9 | # "else" expressions. | 9 | # "else" expressions. | |
10 | 10 | |||
11 | # TODO: Implementation | 11 | # TODO: Implementation | |
12 | 12 | |||
13 | # The variable name of the expression is expanded and then taken as the | 13 | # The variable name of the expression is expanded and then taken as the | |
14 | # condition. In the below example it becomes: | 14 | # condition. In the below example it becomes: | |
@@ -284,24 +284,24 @@ DELAYED= two | @@ -284,24 +284,24 @@ DELAYED= two | |||
284 | .info ${ ${:U \${DELAYED\} == "two"}:?yes:no} | 284 | .info ${ ${:U \${DELAYED\} == "two"}:?yes:no} | |
285 | INDIRECT_COND1= $${DELAYED} == "one" | 285 | INDIRECT_COND1= $${DELAYED} == "one" | |
286 | # expect+1: no | 286 | # expect+1: no | |
287 | .info ${ ${INDIRECT_COND1}:?yes:no} | 287 | .info ${ ${INDIRECT_COND1}:?yes:no} | |
288 | INDIRECT_COND2= $${DELAYED} == "two" | 288 | INDIRECT_COND2= $${DELAYED} == "two" | |
289 | # expect+1: yes | 289 | # expect+1: yes | |
290 | .info ${ ${INDIRECT_COND2}:?yes:no} | 290 | .info ${ ${INDIRECT_COND2}:?yes:no} | |
291 | 291 | |||
292 | 292 | |||
293 | .MAKEFLAGS: -d0 | 293 | .MAKEFLAGS: -d0 | |
294 | 294 | |||
295 | 295 | |||
296 | # In the modifier parts for the 'then' and 'else' branches, subexpressions are | 296 | # In the modifier parts for the 'then' and 'else' branches, subexpressions are | |
297 | # parsed in by inspecting the actual modifiers. In 2008, 2015, 2020, 2022 and | 297 | # parsed by inspecting the actual modifiers. In 2008, 2015, 2020, 2022 and | |
298 | # 2023, the exact parsing algorithm switched a few times, counting balanced | 298 | # 2023, the exact parsing algorithm switched a few times, counting balanced | |
299 | # braces instead of proper subexpressions, which meant that unbalanced braces | 299 | # braces instead of proper subexpressions, which meant that unbalanced braces | |
300 | # were parsed differently, depending on whether the branch was active or not. | 300 | # were parsed differently, depending on whether the branch was active or not. | |
301 | BRACES= }}} | 301 | BRACES= }}} | |
302 | NO= ${0:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}} | 302 | NO= ${0:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}} | |
303 | YES= ${1:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}} | 303 | YES= ${1:?${BRACES:S,}}},yes,}:${BRACES:S,}}},no,}} | |
304 | BOTH= <${YES}> <${NO}> | 304 | BOTH= <${YES}> <${NO}> | |
305 | .if ${BOTH} != "<yes> <no>" | 305 | .if ${BOTH} != "<yes> <no>" | |
306 | . error | 306 | . error | |
307 | .endif | 307 | .endif |
--- src/usr.bin/make/unit-tests/varmod-match.exp 2024/04/20 10:18:55 1.15
+++ src/usr.bin/make/unit-tests/varmod-match.exp 2024/04/23 22:51:28 1.16
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | make: "varmod-match.mk" line 289: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[' of modifier ':M' | 1 | make: "varmod-match.mk" line 290: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[' of modifier ':M' | |
2 | make: "varmod-match.mk" line 297: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[^' of modifier ':M' | 2 | make: "varmod-match.mk" line 298: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[^' of modifier ':M' | |
3 | make: "varmod-match.mk" line 305: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[-x1-3' of modifier ':M' | 3 | make: "varmod-match.mk" line 306: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[-x1-3' of modifier ':M' | |
4 | make: "varmod-match.mk" line 313: while evaluating variable "WORDS": warning: Unfinished character list in pattern '*[-x1-3' of modifier ':M' | 4 | make: "varmod-match.mk" line 314: while evaluating variable "WORDS": warning: Unfinished character list in pattern '*[-x1-3' of modifier ':M' | |
5 | make: "varmod-match.mk" line 322: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^-x1-3' of modifier ':M' | 5 | make: "varmod-match.mk" line 323: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^-x1-3' of modifier ':M' | |
6 | make: "varmod-match.mk" line 336: while evaluating variable "WORDS": warning: Unfinished character list in pattern '?[\' of modifier ':M' | 6 | make: "varmod-match.mk" line 337: while evaluating variable "WORDS": warning: Unfinished character list in pattern '?[\' of modifier ':M' | |
7 | make: "varmod-match.mk" line 344: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[x-' of modifier ':M' | 7 | make: "varmod-match.mk" line 345: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[x-' of modifier ':M' | |
8 | make: "varmod-match.mk" line 356: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[^x-' of modifier ':M' | 8 | make: "varmod-match.mk" line 357: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[^x-' of modifier ':M' | |
9 | make: "varmod-match.mk" line 364: while evaluating variable " : :: ": warning: Unfinished character list in pattern '[' of modifier ':M' | 9 | make: "varmod-match.mk" line 365: while evaluating variable " : :: ": warning: Unfinished character list in pattern '[' of modifier ':M' | |
10 | make: "varmod-match.mk" line 364: while evaluating variable " : :: ": Unknown modifier "]" | 10 | make: "varmod-match.mk" line 365: while evaluating variable " : :: ": Unknown modifier "]" | |
11 | make: "varmod-match.mk" line 364: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":") | 11 | make: "varmod-match.mk" line 365: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":") | |
12 | make: Fatal errors encountered -- cannot continue | 12 | make: Fatal errors encountered -- cannot continue | |
13 | make: stopped in unit-tests | 13 | make: stopped in unit-tests | |
14 | exit status 1 | 14 | exit status 1 |
--- src/usr.bin/make/unit-tests/varmod-match.mk 2024/04/20 10:18:55 1.21
+++ src/usr.bin/make/unit-tests/varmod-match.mk 2024/04/23 22:51:28 1.22
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: varmod-match.mk,v 1.21 2024/04/20 10:18:55 rillig Exp $ | 1 | # $NetBSD: varmod-match.mk,v 1.22 2024/04/23 22:51:28 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Tests for the ':M' modifier, which keeps only those words that match the | 3 | # Tests for the ':M' modifier, which keeps only those words that match the | |
4 | # given pattern. | 4 | # given pattern. | |
5 | # | 5 | # | |
6 | # Table of contents | 6 | # Table of contents | |
7 | # | 7 | # | |
8 | # 1. Pattern characters '*', '?' and '\' | 8 | # 1. Pattern characters '*', '?' and '\' | |
9 | # 2. Character lists and character ranges | 9 | # 2. Character lists and character ranges | |
10 | # 3. Parsing and escaping | 10 | # 3. Parsing and escaping | |
11 | # 4. Interaction with other modifiers | 11 | # 4. Interaction with other modifiers | |
12 | # 5. Performance | 12 | # 5. Performance | |
13 | # 6. Error handling | 13 | # 6. Error handling | |
14 | # 7. Historical bugs | 14 | # 7. Historical bugs | |
@@ -23,42 +23,42 @@ | @@ -23,42 +23,42 @@ | |||
23 | # ? matches 1 character | 23 | # ? matches 1 character | |
24 | # \x matches the character 'x' | 24 | # \x matches the character 'x' | |
25 | 25 | |||
26 | # The pattern is anchored both at the beginning and at the end of the word. | 26 | # The pattern is anchored both at the beginning and at the end of the word. | |
27 | # Since the pattern 'e' does not contain any pattern matching characters, it | 27 | # Since the pattern 'e' does not contain any pattern matching characters, it | |
28 | # matches exactly the word 'e', twice. | 28 | # matches exactly the word 'e', twice. | |
29 | .if ${a c e aa cc ee e f g:L:Me} != "e e" | 29 | .if ${a c e aa cc ee e f g:L:Me} != "e e" | |
30 | . error | 30 | . error | |
31 | .endif | 31 | .endif | |
32 | 32 | |||
33 | # The pattern character '?' matches exactly 1 character, the pattern character | 33 | # The pattern character '?' matches exactly 1 character, the pattern character | |
34 | # '*' matches 0 or more characters. The whole pattern matches all words that | 34 | # '*' matches 0 or more characters. The whole pattern matches all words that | |
35 | # start with 's' and have 3 or more characters. | 35 | # start with 's' and have 3 or more characters. | |
36 | .if ${One Two Three Four five six seven:L:Ms??*} != "six seven" | 36 | .if ${One Two Three Four five six seven so s:L:Ms??*} != "six seven" | |
37 | . error | 37 | . error | |
38 | .endif | 38 | .endif | |
39 | 39 | |||
40 | # Ensure that a pattern without placeholders only matches itself. | 40 | # A pattern without placeholders only matches itself. | |
41 | .if ${a aa aaa b ba baa bab:L:Ma} != "a" | 41 | .if ${a aa aaa b ba baa bab:L:Ma} != "a" | |
42 | . error | 42 | . error | |
43 | .endif | 43 | .endif | |
44 | 44 | |||
45 | # Ensure that a pattern that ends with '*' is properly anchored at the | 45 | # A pattern that ends with '*' is anchored at the | |
46 | # beginning. | 46 | # beginning. | |
47 | .if ${a aa aaa b ba baa bab:L:Ma*} != "a aa aaa" | 47 | .if ${a aa aaa b ba baa bab:L:Ma*} != "a aa aaa" | |
48 | . error | 48 | . error | |
49 | .endif | 49 | .endif | |
50 | 50 | |||
51 | # Ensure that a pattern that starts with '*' is properly anchored at the end. | 51 | # A pattern that starts with '*' is anchored at the end. | |
52 | .if ${a aa aaa b ba baa bab:L:M*a} != "a aa aaa ba baa" | 52 | .if ${a aa aaa b ba baa bab:L:M*a} != "a aa aaa ba baa" | |
53 | . error | 53 | . error | |
54 | .endif | 54 | .endif | |
55 | 55 | |||
56 | # Test the fast code path for '*' followed by a regular character. | 56 | # Test the fast code path for '*' followed by a regular character. | |
57 | .if ${:U file.c file.*c file.h file\.c :M*.c} != "file.c file\\.c" | 57 | .if ${:U file.c file.*c file.h file\.c :M*.c} != "file.c file\\.c" | |
58 | . error | 58 | . error | |
59 | .endif | 59 | .endif | |
60 | # Ensure that the fast code path correctly handles the backslash. | 60 | # Ensure that the fast code path correctly handles the backslash. | |
61 | .if ${:U file.c file.*c file.h file\.c :M*\.c} != "file.c file\\.c" | 61 | .if ${:U file.c file.*c file.h file\.c :M*\.c} != "file.c file\\.c" | |
62 | . error | 62 | . error | |
63 | .endif | 63 | .endif | |
64 | # Ensure that the fast code path correctly handles '\*'. | 64 | # Ensure that the fast code path correctly handles '\*'. | |
@@ -247,28 +247,29 @@ ${:U*}= asterisk | @@ -247,28 +247,29 @@ ${:U*}= asterisk | |||
247 | # TODO: ${VAR:M{{{)))} | 247 | # TODO: ${VAR:M{{{)))} | |
248 | # TODO: ${VAR:M${UNBALANCED}} | 248 | # TODO: ${VAR:M${UNBALANCED}} | |
249 | # TODO: ${VAR:M${:U(((\}\}\}}} | 249 | # TODO: ${VAR:M${:U(((\}\}\}}} | |
250 | 250 | |||
251 | 251 | |||
252 | # 4. Interaction with other modifiers | 252 | # 4. Interaction with other modifiers | |
253 | 253 | |||
254 | # The modifier ':tW' prevents splitting at whitespace. Even leading and | 254 | # The modifier ':tW' prevents splitting at whitespace. Even leading and | |
255 | # trailing whitespace is preserved. | 255 | # trailing whitespace is preserved. | |
256 | .if ${ plain string :L:tW:M*} != " plain string " | 256 | .if ${ plain string :L:tW:M*} != " plain string " | |
257 | . error | 257 | . error | |
258 | .endif | 258 | .endif | |
259 | 259 | |||
260 | # Without the modifier ':tW', the string is split into words. All whitespace | 260 | # Without the modifier ':tW', the string is split into words. Whitespace | |
261 | # around and between the words is normalized to a single space. | 261 | # around the words is discarded, and whitespace between the words is | |
262 | # normalized to a single space. | |||
262 | .if ${ plain string :L:M*} != "plain string" | 263 | .if ${ plain string :L:M*} != "plain string" | |
263 | . error | 264 | . error | |
264 | .endif | 265 | .endif | |
265 | 266 | |||
266 | 267 | |||
267 | # 5. Performance | 268 | # 5. Performance | |
268 | 269 | |||
269 | # Before 2020-06-13, this expression called Str_Match 601,080,390 times. | 270 | # Before 2020-06-13, this expression called Str_Match 601,080,390 times. | |
270 | # Since 2020-06-13, this expression calls Str_Match 1 time. | 271 | # Since 2020-06-13, this expression calls Str_Match 1 time. | |
271 | .if ${:U****************:M****************b} | 272 | .if ${:U****************:M****************b} | |
272 | .endif | 273 | .endif | |
273 | 274 | |||
274 | # Before 2023-06-22, this expression called Str_Match 2,621,112 times. | 275 | # Before 2023-06-22, this expression called Str_Match 2,621,112 times. | |
@@ -362,19 +363,26 @@ WORDS= [x- x x- y yyyyy | @@ -362,19 +363,26 @@ WORDS= [x- x x- y yyyyy | |||
362 | # expect+2: while evaluating variable " : :: ": Unknown modifier "]" | 363 | # expect+2: while evaluating variable " : :: ": Unknown modifier "]" | |
363 | # expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":") | 364 | # expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":") | |
364 | .if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":" | 365 | .if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":" | |
365 | . error | 366 | . error | |
366 | .else | 367 | .else | |
367 | . error | 368 | . error | |
368 | .endif | 369 | .endif | |
369 | 370 | |||
370 | 371 | |||
371 | # 7. Historical bugs | 372 | # 7. Historical bugs | |
372 | 373 | |||
373 | # Before var.c 1.1031 from 2022-08-24, the following expressions caused an | 374 | # Before var.c 1.1031 from 2022-08-24, the following expressions caused an | |
374 | # out-of-bounds read beyond the indirect ':M' modifiers. | 375 | # out-of-bounds read beyond the indirect ':M' modifiers. | |
375 | .if ${:U:${:UM\\}} # The ':M' pattern need not be unescaped, the | 376 | # | |
376 | . error # resulting pattern is '\', it never matches | 377 | # The argument to the inner ':U' is unescaped to 'M\'. | |
377 | .endif # anything. | 378 | # This 'M\' becomes an # indirect modifier ':M' with the pattern '\'. | |
378 | .if ${:U:${:UM\\\:\\}} # The ':M' pattern must be unescaped, the | 379 | # The pattern '\' never matches. | |
379 | . error # resulting pattern is ':\', it never matches | 380 | .if ${:U:${:UM\\}} | |
380 | .endif # anything. | 381 | . error | |
382 | .endif | |||
383 | # The argument to the inner ':U' is unescaped to 'M\:\'. | |||
384 | # This 'M\:\' becomes an indirect modifier ':M' with the pattern ':\'. | |||
385 | # The pattern ':\' never matches. | |||
386 | .if ${:U:${:UM\\\:\\}} | |||
387 | . error | |||
388 | .endif |