| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: for.c,v 1.136 2021/01/25 19:05:39 rillig Exp $ */ | | 1 | /* $NetBSD: for.c,v 1.137 2021/01/25 19:10:57 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1992, The Regents of the University of California. | | 4 | * Copyright (c) 1992, The Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -48,75 +48,93 @@ | | | @@ -48,75 +48,93 @@ |
48 | * body is scanned for variable expressions, and those that match the variable | | 48 | * body is scanned for variable expressions, and those that match the variable |
49 | * names are replaced with expressions of the form ${:U...} or $(:U...). | | 49 | * names are replaced with expressions of the form ${:U...} or $(:U...). |
50 | * After that, the body is treated like a file from an .include directive. | | 50 | * After that, the body is treated like a file from an .include directive. |
51 | * | | 51 | * |
52 | * Interface: | | 52 | * Interface: |
53 | * For_Eval Evaluate the loop in the passed line. | | 53 | * For_Eval Evaluate the loop in the passed line. |
54 | * | | 54 | * |
55 | * For_Run Run accumulated loop | | 55 | * For_Run Run accumulated loop |
56 | */ | | 56 | */ |
57 | | | 57 | |
58 | #include "make.h" | | 58 | #include "make.h" |
59 | | | 59 | |
60 | /* "@(#)for.c 8.1 (Berkeley) 6/6/93" */ | | 60 | /* "@(#)for.c 8.1 (Berkeley) 6/6/93" */ |
61 | MAKE_RCSID("$NetBSD: for.c,v 1.136 2021/01/25 19:05:39 rillig Exp $"); | | 61 | MAKE_RCSID("$NetBSD: for.c,v 1.137 2021/01/25 19:10:57 rillig Exp $"); |
62 | | | 62 | |
63 | static int forLevel = 0; /* Nesting level */ | | | |
64 | | | 63 | |
65 | /* One of the variables to the left of the "in" in a .for loop. */ | | 64 | /* One of the variables to the left of the "in" in a .for loop. */ |
66 | typedef struct ForVar { | | 65 | typedef struct ForVar { |
67 | char *name; | | 66 | char *name; |
68 | size_t nameLen; | | 67 | size_t nameLen; |
69 | } ForVar; | | 68 | } ForVar; |
70 | | | 69 | |
71 | typedef struct ForLoop { | | 70 | typedef struct ForLoop { |
72 | Buffer body; /* Unexpanded body of the loop */ | | 71 | Buffer body; /* Unexpanded body of the loop */ |
73 | Vector /* of ForVar */ vars; /* Iteration variables */ | | 72 | Vector /* of ForVar */ vars; /* Iteration variables */ |
74 | Words items; /* Substitution items */ | | 73 | Words items; /* Substitution items */ |
75 | Buffer curBody; /* Expanded body of the current iteration */ | | 74 | Buffer curBody; /* Expanded body of the current iteration */ |
76 | /* Is any of the names 1 character long? If so, when the variable values | | 75 | /* Is any of the names 1 character long? If so, when the variable values |
77 | * are substituted, the parser must handle $V expressions as well, not | | 76 | * are substituted, the parser must handle $V expressions as well, not |
78 | * only ${V} and $(V). */ | | 77 | * only ${V} and $(V). */ |
79 | Boolean short_var; | | 78 | Boolean short_var; |
80 | unsigned int sub_next; /* Where to continue iterating */ | | 79 | unsigned int sub_next; /* Where to continue iterating */ |
81 | } ForLoop; | | 80 | } ForLoop; |
82 | | | 81 | |
| | | 82 | |
83 | static ForLoop *accumFor; /* Loop being accumulated */ | | 83 | static ForLoop *accumFor; /* Loop being accumulated */ |
| | | 84 | static int forLevel = 0; /* Nesting level */ |
84 | | | 85 | |
85 | static void | | 86 | |
86 | ForLoop_AddVar(ForLoop *f, const char *name, size_t len) | | 87 | static ForLoop * |
| | | 88 | ForLoop_New(void) |
87 | { | | 89 | { |
88 | ForVar *var = Vector_Push(&f->vars); | | 90 | ForLoop *f = bmake_malloc(sizeof *f); |
89 | var->name = bmake_strldup(name, len); | | 91 | |
90 | var->nameLen = len; | | 92 | Buf_Init(&f->body); |
| | | 93 | Vector_Init(&f->vars, sizeof(ForVar)); |
| | | 94 | f->items.words = NULL; |
| | | 95 | f->items.freeIt = NULL; |
| | | 96 | Buf_Init(&f->curBody); |
| | | 97 | f->short_var = FALSE; |
| | | 98 | f->sub_next = 0; |
| | | 99 | |
| | | 100 | return f; |
91 | } | | 101 | } |
92 | | | 102 | |
93 | static void | | 103 | static void |
94 | ForLoop_Free(ForLoop *f) | | 104 | ForLoop_Free(ForLoop *f) |
95 | { | | 105 | { |
96 | Buf_Destroy(&f->body, TRUE); | | 106 | Buf_Destroy(&f->body, TRUE); |
97 | | | 107 | |
98 | while (f->vars.len > 0) { | | 108 | while (f->vars.len > 0) { |
99 | ForVar *var = Vector_Pop(&f->vars); | | 109 | ForVar *var = Vector_Pop(&f->vars); |
100 | free(var->name); | | 110 | free(var->name); |
101 | } | | 111 | } |
102 | Vector_Done(&f->vars); | | 112 | Vector_Done(&f->vars); |
103 | | | 113 | |
104 | Words_Free(f->items); | | 114 | Words_Free(f->items); |
105 | Buf_Destroy(&f->curBody, TRUE); | | 115 | Buf_Destroy(&f->curBody, TRUE); |
106 | | | 116 | |
107 | free(f); | | 117 | free(f); |
108 | } | | 118 | } |
109 | | | 119 | |
| | | 120 | static void |
| | | 121 | ForLoop_AddVar(ForLoop *f, const char *name, size_t len) |
| | | 122 | { |
| | | 123 | ForVar *var = Vector_Push(&f->vars); |
| | | 124 | var->name = bmake_strldup(name, len); |
| | | 125 | var->nameLen = len; |
| | | 126 | } |
| | | 127 | |
110 | static Boolean | | 128 | static Boolean |
111 | IsFor(const char *p) | | 129 | IsFor(const char *p) |
112 | { | | 130 | { |
113 | return p[0] == 'f' && p[1] == 'o' && p[2] == 'r' && ch_isspace(p[3]); | | 131 | return p[0] == 'f' && p[1] == 'o' && p[2] == 'r' && ch_isspace(p[3]); |
114 | } | | 132 | } |
115 | | | 133 | |
116 | static Boolean | | 134 | static Boolean |
117 | IsEndfor(const char *p) | | 135 | IsEndfor(const char *p) |
118 | { | | 136 | { |
119 | return p[0] == 'e' && strncmp(p, "endfor", 6) == 0 && | | 137 | return p[0] == 'e' && strncmp(p, "endfor", 6) == 0 && |
120 | (p[6] == '\0' || ch_isspace(p[6])); | | 138 | (p[6] == '\0' || ch_isspace(p[6])); |
121 | } | | 139 | } |
122 | | | 140 | |
| @@ -144,34 +162,27 @@ For_Eval(const char *line) | | | @@ -144,34 +162,27 @@ For_Eval(const char *line) |
144 | if (!IsFor(p)) { | | 162 | if (!IsFor(p)) { |
145 | if (IsEndfor(p)) { | | 163 | if (IsEndfor(p)) { |
146 | Parse_Error(PARSE_FATAL, "for-less endfor"); | | 164 | Parse_Error(PARSE_FATAL, "for-less endfor"); |
147 | return -1; | | 165 | return -1; |
148 | } | | 166 | } |
149 | return 0; | | 167 | return 0; |
150 | } | | 168 | } |
151 | p += 3; | | 169 | p += 3; |
152 | | | 170 | |
153 | /* | | 171 | /* |
154 | * we found a for loop, and now we are going to parse it. | | 172 | * we found a for loop, and now we are going to parse it. |
155 | */ | | 173 | */ |
156 | | | 174 | |
157 | f = bmake_malloc(sizeof *f); | | 175 | f = ForLoop_New(); |
158 | Buf_Init(&f->body); | | | |
159 | Vector_Init(&f->vars, sizeof(ForVar)); | | | |
160 | f->items.words = NULL; | | | |
161 | f->items.freeIt = NULL; | | | |
162 | Buf_Init(&f->curBody); | | | |
163 | f->short_var = FALSE; | | | |
164 | f->sub_next = 0; | | | |
165 | | | 176 | |
166 | /* Grab the variables. Terminate on "in". */ | | 177 | /* Grab the variables. Terminate on "in". */ |
167 | for (;;) { | | 178 | for (;;) { |
168 | size_t len; | | 179 | size_t len; |
169 | | | 180 | |
170 | cpp_skip_whitespace(&p); | | 181 | cpp_skip_whitespace(&p); |
171 | if (*p == '\0') { | | 182 | if (*p == '\0') { |
172 | Parse_Error(PARSE_FATAL, "missing `in' in for"); | | 183 | Parse_Error(PARSE_FATAL, "missing `in' in for"); |
173 | ForLoop_Free(f); | | 184 | ForLoop_Free(f); |
174 | return -1; | | 185 | return -1; |
175 | } | | 186 | } |
176 | | | 187 | |
177 | /* | | 188 | /* |