make(1): add enough tests to cover the ApplyModifier functions Only a few return statements are still missing from the code coverage. In ApplyModifier_Assign, the test for an empty variable name is skipped for now since it segfaults. In ApplyModifier_SysV after the second ParseModifierPart, the branch for the missing delimiter is not reached since this case is already checked for in the first part of the function. To trigger this branch, a specially crafted, unrealistic string needs to be created, and that's too complicated for the moment.diff -r1.353 -r1.354 src/usr.bin/make/var.c
(rillig)
--- src/usr.bin/make/var.c 2020/07/28 17:18:40 1.353
+++ src/usr.bin/make/var.c 2020/07/29 19:48:33 1.354
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: var.c,v 1.353 2020/07/28 17:18:40 rillig Exp $ */ | 1 | /* $NetBSD: var.c,v 1.354 2020/07/29 19:48:33 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. | |
@@ -59,34 +59,34 @@ | @@ -59,34 +59,34 @@ | |||
59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
68 | * SUCH DAMAGE. | 68 | * SUCH DAMAGE. | |
69 | */ | 69 | */ | |
70 | 70 | |||
71 | #ifndef MAKE_NATIVE | 71 | #ifndef MAKE_NATIVE | |
72 | static char rcsid[] = "$NetBSD: var.c,v 1.353 2020/07/28 17:18:40 rillig Exp $"; | 72 | static char rcsid[] = "$NetBSD: var.c,v 1.354 2020/07/29 19:48:33 rillig Exp $"; | |
73 | #else | 73 | #else | |
74 | #include <sys/cdefs.h> | 74 | #include <sys/cdefs.h> | |
75 | #ifndef lint | 75 | #ifndef lint | |
76 | #if 0 | 76 | #if 0 | |
77 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; | 77 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; | |
78 | #else | 78 | #else | |
79 | __RCSID("$NetBSD: var.c,v 1.353 2020/07/28 17:18:40 rillig Exp $"); | 79 | __RCSID("$NetBSD: var.c,v 1.354 2020/07/29 19:48:33 rillig Exp $"); | |
80 | #endif | 80 | #endif | |
81 | #endif /* not lint */ | 81 | #endif /* not lint */ | |
82 | #endif | 82 | #endif | |
83 | 83 | |||
84 | /*- | 84 | /*- | |
85 | * var.c -- | 85 | * var.c -- | |
86 | * Variable-handling functions | 86 | * Variable-handling functions | |
87 | * | 87 | * | |
88 | * Interface: | 88 | * Interface: | |
89 | * Var_Set Set the value of a variable in the given | 89 | * Var_Set Set the value of a variable in the given | |
90 | * context. The variable is created if it doesn't | 90 | * context. The variable is created if it doesn't | |
91 | * yet exist. | 91 | * yet exist. | |
92 | * | 92 | * | |
@@ -2513,27 +2513,27 @@ ApplyModifier_Regex(const char *mod, App | @@ -2513,27 +2513,27 @@ ApplyModifier_Regex(const char *mod, App | |||
2513 | #endif | 2513 | #endif | |
2514 | 2514 | |||
2515 | static void | 2515 | static void | |
2516 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | 2516 | ModifyWord_Copy(const char *word, SepBuf *buf, void *data MAKE_ATTR_UNUSED) | |
2517 | { | 2517 | { | |
2518 | SepBuf_AddStr(buf, word); | 2518 | SepBuf_AddStr(buf, word); | |
2519 | } | 2519 | } | |
2520 | 2520 | |||
2521 | /* :ts<separator> */ | 2521 | /* :ts<separator> */ | |
2522 | static Boolean | 2522 | static Boolean | |
2523 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) | 2523 | ApplyModifier_ToSep(const char *sep, ApplyModifiersState *st) | |
2524 | { | 2524 | { | |
2525 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { | 2525 | if (sep[0] != st->endc && (sep[1] == st->endc || sep[1] == ':')) { | |
2526 | /* ":ts<unrecognised><endc>" or ":ts<unrecognised>:" */ | 2526 | /* ":ts<any><endc>" or ":ts<any>:" */ | |
2527 | st->sep = sep[0]; | 2527 | st->sep = sep[0]; | |
2528 | st->next = sep + 1; | 2528 | st->next = sep + 1; | |
2529 | } else if (sep[0] == st->endc || sep[0] == ':') { | 2529 | } else if (sep[0] == st->endc || sep[0] == ':') { | |
2530 | /* ":ts<endc>" or ":ts:" */ | 2530 | /* ":ts<endc>" or ":ts:" */ | |
2531 | st->sep = '\0'; /* no separator */ | 2531 | st->sep = '\0'; /* no separator */ | |
2532 | st->next = sep; | 2532 | st->next = sep; | |
2533 | } else if (sep[0] == '\\') { | 2533 | } else if (sep[0] == '\\') { | |
2534 | const char *xp = sep + 1; | 2534 | const char *xp = sep + 1; | |
2535 | int base = 8; /* assume octal */ | 2535 | int base = 8; /* assume octal */ | |
2536 | 2536 | |||
2537 | switch (sep[1]) { | 2537 | switch (sep[1]) { | |
2538 | case 'n': | 2538 | case 'n': | |
2539 | st->sep = '\n'; | 2539 | st->sep = '\n'; |
--- src/usr.bin/make/unit-tests/Makefile 2020/07/28 22:44:44 1.75
+++ src/usr.bin/make/unit-tests/Makefile 2020/07/29 19:48:33 1.76
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: Makefile,v 1.75 2020/07/28 22:44:44 rillig Exp $ | 1 | # $NetBSD: Makefile,v 1.76 2020/07/29 19:48:33 rillig Exp $ | |
2 | # | 2 | # | |
3 | # Unit tests for make(1) | 3 | # Unit tests for make(1) | |
4 | # | 4 | # | |
5 | # The main targets are: | 5 | # The main targets are: | |
6 | # | 6 | # | |
7 | # all: | 7 | # all: | |
8 | # run all the tests | 8 | # run all the tests | |
9 | # test: | 9 | # test: | |
10 | # run 'all', and compare to expected results | 10 | # run 'all', and compare to expected results | |
11 | # accept: | 11 | # accept: | |
12 | # move generated output to expected results | 12 | # move generated output to expected results | |
13 | # | 13 | # | |
14 | # Settable variables | 14 | # Settable variables | |
@@ -84,26 +84,27 @@ ENV.envfirst= FROM_ENV=value-from-env | @@ -84,26 +84,27 @@ ENV.envfirst= FROM_ENV=value-from-env | |||
84 | ENV.export= -i PATH=${PATH:Q} | 84 | ENV.export= -i PATH=${PATH:Q} | |
85 | ENV.varmisc= FROM_ENV=env | 85 | ENV.varmisc= FROM_ENV=env | |
86 | ENV.varmisc+= FROM_ENV_BEFORE=env | 86 | ENV.varmisc+= FROM_ENV_BEFORE=env | |
87 | ENV.varmisc+= FROM_ENV_AFTER=env | 87 | ENV.varmisc+= FROM_ENV_AFTER=env | |
88 | 88 | |||
89 | # Override make flags for some of the tests; default is -k. | 89 | # Override make flags for some of the tests; default is -k. | |
90 | FLAGS.doterror= # none | 90 | FLAGS.doterror= # none | |
91 | FLAGS.envfirst= -e | 91 | FLAGS.envfirst= -e | |
92 | FLAGS.export= -r | 92 | FLAGS.export= -r | |
93 | FLAGS.order= -j1 | 93 | FLAGS.order= -j1 | |
94 | FLAGS.vardebug= -k -dv FROM_CMDLINE= | 94 | FLAGS.vardebug= -k -dv FROM_CMDLINE= | |
95 | 95 | |||
96 | # Some tests need extra post-processing. | 96 | # Some tests need extra post-processing. | |
97 | SED_CMDS.moderrs+= -e 's,\(substitution error:\).*,\1 (details omitted),' | |||
97 | SED_CMDS.modmisc+= -e 's,\(substitution error:\).*,\1 (details omitted),' | 98 | SED_CMDS.modmisc+= -e 's,\(substitution error:\).*,\1 (details omitted),' | |
98 | SED_CMDS.varshell+= -e 's,^[a-z]*sh: ,,' | 99 | SED_CMDS.varshell+= -e 's,^[a-z]*sh: ,,' | |
99 | SED_CMDS.varshell+= -e '/command/s,No such.*,not found,' | 100 | SED_CMDS.varshell+= -e '/command/s,No such.*,not found,' | |
100 | 101 | |||
101 | # Some tests need an additional round of postprocessing. | 102 | # Some tests need an additional round of postprocessing. | |
102 | POSTPROC.vardebug= ${TOOL_SED} -n -e '/:RELEVANT = yes/,/:RELEVANT = no/p' | 103 | POSTPROC.vardebug= ${TOOL_SED} -n -e '/:RELEVANT = yes/,/:RELEVANT = no/p' | |
103 | 104 | |||
104 | # End of the configuration section. | 105 | # End of the configuration section. | |
105 | 106 | |||
106 | .MAIN: all | 107 | .MAIN: all | |
107 | 108 | |||
108 | UNIT_TESTS:= ${.PARSEDIR} | 109 | UNIT_TESTS:= ${.PARSEDIR} | |
109 | .PATH: ${UNIT_TESTS} | 110 | .PATH: ${UNIT_TESTS} |
--- src/usr.bin/make/unit-tests/moderrs.exp 2020/07/29 18:48:47 1.7
+++ src/usr.bin/make/unit-tests/moderrs.exp 2020/07/29 19:48:33 1.8
@@ -52,14 +52,86 @@ TheVariable | @@ -52,14 +52,86 @@ TheVariable | |||
52 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier S | 52 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier S | |
53 | 1: TheVariable | 53 | 1: TheVariable | |
54 | make: Unclosed substitution for VAR (, missing) | 54 | make: Unclosed substitution for VAR (, missing) | |
55 | 2: | 55 | 2: | |
56 | make: Unclosed substitution for VAR (, missing) | 56 | make: Unclosed substitution for VAR (, missing) | |
57 | 3: | 57 | 3: | |
58 | make: Unclosed substitution for VAR (, missing) | 58 | make: Unclosed substitution for VAR (, missing) | |
59 | 59 | |||
60 | make: Unclosed substitution for VAR (, missing) | 60 | make: Unclosed substitution for VAR (, missing) | |
61 | 61 | |||
62 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier S | 62 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier S | |
63 | TheVariable | 63 | TheVariable | |
64 | TheVariable | 64 | TheVariable | |
65 | mod-regex-delimiter: | |||
66 | make: RE substitution error: (details omitted) | |||
67 | make: Unclosed substitution for VAR (, missing) | |||
68 | echo | |||
69 | make: Unclosed substitution for VAR (, missing) | |||
70 | ||||
71 | make: Unclosed substitution for VAR (, missing) | |||
72 | ||||
73 | make: Unclosed substitution for VAR (, missing) | |||
74 | ||||
75 | make: Unclosed substitution for VAR (, missing) | |||
76 | ||||
77 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier C | |||
78 | TheVariable | |||
79 | TheVariable | |||
80 | make: RE substitution error: (details omitted) | |||
81 | 1: | |||
82 | make: Unclosed substitution for VAR (, missing) | |||
83 | 2: | |||
84 | make: Unclosed substitution for VAR (, missing) | |||
85 | 3: | |||
86 | make: Unclosed substitution for VAR (, missing) | |||
87 | ||||
88 | make: Unclosed substitution for VAR (, missing) | |||
89 | ||||
90 | make: Unclosed variable specification (expecting '}') for "VAR" (value "TheVariable") modifier C | |||
91 | TheVariable | |||
92 | TheVariable | |||
93 | mod-ts-parse: | |||
94 | 112358132134 | |||
95 | 15152535558513521534 | |||
96 | make: Bad modifier `:ts\65oct' for FIB | |||
97 | 65oct} | |||
98 | make: Bad modifier `:tsxy' for FIB | |||
99 | xy} | |||
100 | mod-t-parse: | |||
101 | make: Bad modifier `:txy' for FIB | |||
102 | y} | |||
103 | make: Bad modifier `:t' for FIB | |||
104 | ||||
105 | make: Bad modifier `:t' for FIB | |||
106 | M*} | |||
107 | mod-ifelse-parse: | |||
108 | make: Unclosed substitution for FIB (: missing) | |||
109 | ||||
110 | make: Unclosed substitution for FIB (: missing) | |||
111 | ||||
112 | make: Unclosed substitution for FIB (} missing) | |||
113 | ||||
114 | make: Unclosed substitution for FIB (} missing) | |||
115 | ||||
116 | then | |||
117 | mod-assign-parse: | |||
118 | make: Unknown modifier ':' | |||
119 | ||||
120 | make: Unclosed substitution for ASSIGN (} missing) | |||
121 | ||||
122 | mod-remember-parse: | |||
123 | 1 1 2 3 5 8 13 21 34 | |||
124 | make: Unknown modifier '_' | |||
125 | ||||
126 | mod-sysv-parse: | |||
127 | make: Unknown modifier '3' | |||
128 | make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3 | |||
129 | ||||
130 | make: Unknown modifier '3' | |||
131 | make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3 | |||
132 | ||||
133 | make: Unknown modifier '3' | |||
134 | make: Unclosed variable specification (expecting '}') for "FIB" (value "") modifier 3 | |||
135 | ||||
136 | 1 1 2 x3 5 8 1x3 21 34 | |||
65 | exit status 0 | 137 | exit status 0 |
--- src/usr.bin/make/unit-tests/moderrs.mk 2020/07/29 18:48:47 1.6
+++ src/usr.bin/make/unit-tests/moderrs.mk 2020/07/29 19:48:33 1.7
@@ -1,28 +1,37 @@ | @@ -1,28 +1,37 @@ | |||
1 | # $Id: moderrs.mk,v 1.6 2020/07/29 18:48:47 rillig Exp $ | 1 | # $Id: moderrs.mk,v 1.7 2020/07/29 19:48:33 rillig Exp $ | |
2 | # | 2 | # | |
3 | # various modifier error tests | 3 | # various modifier error tests | |
4 | 4 | |||
5 | VAR=TheVariable | 5 | VAR=TheVariable | |
6 | # incase we have to change it ;-) | 6 | # incase we have to change it ;-) | |
7 | MOD_UNKN=Z | 7 | MOD_UNKN=Z | |
8 | MOD_TERM=S,V,v | 8 | MOD_TERM=S,V,v | |
9 | MOD_S:= ${MOD_TERM}, | 9 | MOD_S:= ${MOD_TERM}, | |
10 | 10 | |||
11 | FIB= 1 1 2 3 5 8 13 21 34 | |||
12 | ||||
11 | all: modunkn modunknV varterm vartermV modtermV modloop | 13 | all: modunkn modunknV varterm vartermV modtermV modloop | |
12 | all: modloop-close | 14 | all: modloop-close | |
13 | all: modwords | 15 | all: modwords | |
14 | all: modexclam | 16 | all: modexclam | |
15 | all: mod-subst-delimiter | 17 | all: mod-subst-delimiter | |
18 | all: mod-regex-delimiter | |||
19 | all: mod-ts-parse | |||
20 | all: mod-t-parse | |||
21 | all: mod-ifelse-parse | |||
22 | all: mod-assign-parse | |||
23 | all: mod-remember-parse | |||
24 | all: mod-sysv-parse | |||
16 | 25 | |||
17 | modunkn: | 26 | modunkn: | |
18 | @echo "Expect: Unknown modifier 'Z'" | 27 | @echo "Expect: Unknown modifier 'Z'" | |
19 | @echo "VAR:Z=${VAR:Z}" | 28 | @echo "VAR:Z=${VAR:Z}" | |
20 | 29 | |||
21 | modunknV: | 30 | modunknV: | |
22 | @echo "Expect: Unknown modifier 'Z'" | 31 | @echo "Expect: Unknown modifier 'Z'" | |
23 | @echo "VAR:${MOD_UNKN}=${VAR:${MOD_UNKN}}" | 32 | @echo "VAR:${MOD_UNKN}=${VAR:${MOD_UNKN}}" | |
24 | 33 | |||
25 | varterm: | 34 | varterm: | |
26 | @echo "Expect: Unclosed variable specification for VAR" | 35 | @echo "Expect: Unclosed variable specification for VAR" | |
27 | @echo VAR:S,V,v,=${VAR:S,V,v, | 36 | @echo VAR:S,V,v,=${VAR:S,V,v, | |
28 | 37 | |||
@@ -89,13 +98,72 @@ mod-subst-delimiter: | @@ -89,13 +98,72 @@ mod-subst-delimiter: | |||
89 | @echo ${VAR:S, | 98 | @echo ${VAR:S, | |
90 | @echo ${VAR:S,from | 99 | @echo ${VAR:S,from | |
91 | @echo ${VAR:S,from, | 100 | @echo ${VAR:S,from, | |
92 | @echo ${VAR:S,from,to | 101 | @echo ${VAR:S,from,to | |
93 | @echo ${VAR:S,from,to, | 102 | @echo ${VAR:S,from,to, | |
94 | @echo ${VAR:S,from,to,} | 103 | @echo ${VAR:S,from,to,} | |
95 | @echo 1: ${VAR:S | 104 | @echo 1: ${VAR:S | |
96 | @echo 2: ${VAR:S, | 105 | @echo 2: ${VAR:S, | |
97 | @echo 3: ${VAR:S,from | 106 | @echo 3: ${VAR:S,from | |
98 | @echo ${VAR:S,from, | 107 | @echo ${VAR:S,from, | |
99 | @echo ${VAR:S,from,to | 108 | @echo ${VAR:S,from,to | |
100 | @echo ${VAR:S,from,to, | 109 | @echo ${VAR:S,from,to, | |
101 | @echo ${VAR:S,from,to,} | 110 | @echo ${VAR:S,from,to,} | |
111 | ||||
112 | # XXX: Where does the "echo" in the output of "${VAR:C" come from? | |||
113 | mod-regex-delimiter: | |||
114 | @echo $@: | |||
115 | @echo ${VAR:C | |||
116 | @echo ${VAR:C, | |||
117 | @echo ${VAR:C,from | |||
118 | @echo ${VAR:C,from, | |||
119 | @echo ${VAR:C,from,to | |||
120 | @echo ${VAR:C,from,to, | |||
121 | @echo ${VAR:C,from,to,} | |||
122 | @echo 1: ${VAR:C | |||
123 | @echo 2: ${VAR:C, | |||
124 | @echo 3: ${VAR:C,from | |||
125 | @echo ${VAR:C,from, | |||
126 | @echo ${VAR:C,from,to | |||
127 | @echo ${VAR:C,from,to, | |||
128 | @echo ${VAR:C,from,to,} | |||
129 | ||||
130 | mod-ts-parse: | |||
131 | @echo $@: | |||
132 | @echo ${FIB:ts} | |||
133 | @echo ${FIB:ts\65} # octal 065 == U+0035 == '5' | |||
134 | @echo ${FIB:ts\65oct} # bad modifier | |||
135 | @echo ${FIB:tsxy} # modifier too long | |||
136 | ||||
137 | mod-t-parse: | |||
138 | @echo $@: | |||
139 | @echo ${FIB:txy} | |||
140 | @echo ${FIB:t} | |||
141 | @echo ${FIB:t:M*} | |||
142 | ||||
143 | mod-ifelse-parse: | |||
144 | @echo $@: | |||
145 | @echo ${FIB:? | |||
146 | @echo ${FIB:?then | |||
147 | @echo ${FIB:?then: | |||
148 | @echo ${FIB:?then:else | |||
149 | @echo ${FIB:?then:else} | |||
150 | ||||
151 | mod-assign-parse: | |||
152 | @echo $@: | |||
153 | @echo ${ASSIGN::x} # 'x' is an unknown assignment operator | |||
154 | # disabled for now; segfaults on NetBSD-8.0-x86_64 in Var_Parse line 3636: | |||
155 | # *lengthPtr = tstr - str + (*tstr ? 1 : 0); | |||
156 | # @echo ${::=value} # trying to set the empty variable | |||
157 | @echo ${ASSIGN::=value # missing closing brace | |||
158 | ||||
159 | mod-remember-parse: | |||
160 | @echo $@: | |||
161 | @echo ${FIB:_} # ok | |||
162 | @echo ${FIB:__} # modifier name too long | |||
163 | ||||
164 | mod-sysv-parse: | |||
165 | @echo $@: | |||
166 | @echo ${FIB:3 | |||
167 | @echo ${FIB:3= | |||
168 | @echo ${FIB:3=x3 | |||
169 | @echo ${FIB:3=x3} # ok |