1 1.2 rillig # $NetBSD: char-005c-reverse-solidus.mk,v 1.2 2025/06/29 11:27:21 rillig Exp $ 2 1.1 rillig # 3 1.1 rillig # Tests for the character U+005C "REVERSE SOLIDUS". 4 1.1 rillig # 5 1.1 rillig # See also: 6 1.1 rillig # TODO 7 1.1 rillig # TODO 8 1.1 rillig # TODO 9 1.1 rillig 10 1.1 rillig # TODO: Where is this character used normally? 11 1.1 rillig # TODO: What are the edge cases? 12 1.1 rillig 13 1.1 rillig # TODO: escape '#' in lines 14 1.1 rillig # TODO: escape '#' in comments 15 1.1 rillig # TODO: escape ':' in modifiers 16 1.1 rillig # TODO: escape any character in condition strings 17 1.1 rillig 18 1.1 rillig # begin https://gnats.netbsd.org/46139 19 1.1 rillig 20 1.1 rillig # Too see the details of parsing, uncomment the following line. 21 1.1 rillig #.MAKEFLAGS: -dcpv 22 1.1 rillig 23 1.1 rillig # This backslash is treated as a line continuation. 24 1.1 rillig # It does not end up in the variable value. 25 1.1 rillig LINE_CONTINUATION=foo\ 26 1.1 rillig # This line is still part of the variable assignment 27 1.1 rillig .if ${LINE_CONTINUATION:C,[^a-z],<>,gW} != "foo" 28 1.1 rillig . error 29 1.1 rillig .endif 30 1.1 rillig 31 1.1 rillig # The variable value contains two backslashes. 32 1.1 rillig TWO_BACKSLASHES_AT_EOL=foo\\ 33 1.1 rillig .if ${TWO_BACKSLASHES_AT_EOL:C,[^a-z],<>,gW} != "foo<><>" 34 1.1 rillig . error 35 1.1 rillig .endif 36 1.1 rillig 37 1.1 rillig TRAILING_WHITESPACE=foo\ # trailing space 38 1.1 rillig .if ${TRAILING_WHITESPACE:C,[^a-z],<>,gW} != "foo<><>" 39 1.1 rillig . error 40 1.1 rillig .endif 41 1.1 rillig 42 1.1 rillig # The simplest was to produce a single backslash is the :U modifier. 43 1.1 rillig BACKSLASH= ${:U\\} 44 1.1 rillig .if ${BACKSLASH} != "\\" 45 1.1 rillig . error 46 1.1 rillig .endif 47 1.1 rillig BACKSLASH_C= ${:U1:C,.,\\,} 48 1.1 rillig .if ${BACKSLASH_C} != "\\" 49 1.1 rillig . error 50 1.1 rillig .endif 51 1.1 rillig 52 1.1 rillig # expect+5: Unclosed expression, expecting "}" for modifier "Mx\}" 53 1.1 rillig # At the point where the unclosed expression is detected, the ":M" modifier 54 1.1 rillig # has been applied to the expression. Its pattern is "x}", which doesn't 55 1.1 rillig # match the single backslash. 56 1.1 rillig # expect: while evaluating variable "BACKSLASH" with value "" 57 1.1 rillig .if ${BACKSLASH:Mx\} 58 1.1 rillig . error 59 1.1 rillig .else 60 1.1 rillig . error 61 1.1 rillig .endif 62 1.1 rillig 63 1.1 rillig # expect+1: Unclosed expression, expecting "}" for modifier "Mx\\}" 64 1.1 rillig .if ${BACKSLASH:Mx\\} 65 1.1 rillig . error 66 1.1 rillig .else 67 1.1 rillig . error 68 1.1 rillig .endif 69 1.1 rillig 70 1.1 rillig # expect+1: Unclosed expression, expecting "}" for modifier "Mx\\\\\\\\}" 71 1.1 rillig .if ${BACKSLASH:Mx\\\\\\\\} 72 1.1 rillig . error 73 1.1 rillig .else 74 1.1 rillig . error 75 1.1 rillig .endif 76 1.1 rillig 77 1.1 rillig # Adding more text after the backslash adds to the pattern, as the backslash 78 1.1 rillig # serves to escape the ":" that is otherwise used to separate the modifiers. 79 1.1 rillig # The result is a single ":M" modifier with the pattern "x:Nzzz". 80 1.1 rillig .if ${BACKSLASH:Mx\:Nzzz} != "" 81 1.1 rillig . error 82 1.1 rillig .endif 83 1.1 rillig 84 1.1 rillig # The pattern ends up as "x\:Nzzz". Only the sequence "\:" is unescaped, all 85 1.1 rillig # others, including "\\", are left as-is. 86 1.1 rillig .if ${BACKSLASH:Mx\\:Nzzz} != "" 87 1.1 rillig . error 88 1.1 rillig .endif 89 1.1 rillig 90 1.1 rillig # The pattern for the ":M" modifier ends up as "x\\\\\\\:Nzzz". Only the 91 1.1 rillig # sequence "\:" is unescaped, all others, including "\\", are left as-is. 92 1.1 rillig .if ${BACKSLASH:Mx\\\\\\\\:Nzzz} != "" 93 1.1 rillig . error 94 1.1 rillig .endif 95 1.1 rillig 96 1.1 rillig # The ":M" modifier is parsed differently than the other modifiers. To 97 1.1 rillig # circumvent the peculiarities of that parser, the pattern can be passed via 98 1.1 rillig # an expression. There, the usual escaping rules for modifiers apply. 99 1.1 rillig # expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M" 100 1.1 rillig .if ${BACKSLASH:M${BACKSLASH}} != "\\" 101 1.1 rillig . error 102 1.1 rillig .else 103 1.1 rillig . error 104 1.1 rillig .endif 105 1.1 rillig 106 1.1 rillig # Trying to bypass the parser by using a direct expression doesn't work, as 107 1.1 rillig # the parser for the ":M" modifier does not parse the subexpression like in 108 1.1 rillig # all other places, but instead counts the braces and tries to decode the 109 1.1 rillig # escaping, which fails in this case. 110 1.1 rillig # expect+1: Unclosed expression, expecting "}" for modifier "M${:U\\\\}} != "\\"" 111 1.1 rillig .if ${BACKSLASH:M${:U\\\\}} != "\\" 112 1.1 rillig . error 113 1.1 rillig .else 114 1.1 rillig . error 115 1.1 rillig .endif 116 1.1 rillig 117 1.1 rillig # Matching a backslash with the pattern matching characters works. 118 1.1 rillig .if ${BACKSLASH:M?} != "\\" 119 1.1 rillig . error 120 1.1 rillig .endif 121 1.1 rillig .if ${BACKSLASH:M*} != "\\" 122 1.1 rillig . error 123 1.1 rillig .endif 124 1.1 rillig .if ${BACKSLASH:M[Z-a]} != "\\" 125 1.1 rillig . error 126 1.1 rillig .endif 127 1.1 rillig .if ${BACKSLASH:M[\\]} != "\\" 128 1.1 rillig . error 129 1.1 rillig .endif 130 1.1 rillig 131 1.1 rillig # end https://gnats.netbsd.org/46139 132