| @@ -1,415 +1,402 @@ | | | @@ -1,415 +1,402 @@ |
1 | /* $NetBSD: mem1.c,v 1.57 2021/12/25 13:51:42 rillig Exp $ */ | | 1 | /* $NetBSD: mem1.c,v 1.58 2022/02/27 06:55:13 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1994, 1995 Jochen Pohl | | 4 | * Copyright (c) 1994, 1995 Jochen Pohl |
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. |
15 | * 3. All advertising materials mentioning features or use of this software | | 15 | * 3. All advertising materials mentioning features or use of this software |
16 | * must display the following acknowledgement: | | 16 | * must display the following acknowledgement: |
17 | * This product includes software developed by Jochen Pohl for | | 17 | * This product includes software developed by Jochen Pohl for |
18 | * The NetBSD Project. | | 18 | * The NetBSD Project. |
19 | * 4. The name of the author may not be used to endorse or promote products | | 19 | * 4. The name of the author may not be used to endorse or promote products |
20 | * derived from this software without specific prior written permission. | | 20 | * derived from this software without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | #if HAVE_NBTOOL_CONFIG_H | | 34 | #if HAVE_NBTOOL_CONFIG_H |
35 | #include "nbtool_config.h" | | 35 | #include "nbtool_config.h" |
36 | #endif | | 36 | #endif |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | #if defined(__RCSID) && !defined(lint) | | 39 | #if defined(__RCSID) && !defined(lint) |
40 | __RCSID("$NetBSD: mem1.c,v 1.57 2021/12/25 13:51:42 rillig Exp $"); | | 40 | __RCSID("$NetBSD: mem1.c,v 1.58 2022/02/27 06:55:13 rillig Exp $"); |
41 | #endif | | 41 | #endif |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <stdlib.h> | | 44 | #include <stdlib.h> |
45 | #include <string.h> | | 45 | #include <string.h> |
46 | | | 46 | |
47 | #include "lint1.h" | | 47 | #include "lint1.h" |
48 | | | 48 | |
49 | /* | | 49 | /* |
50 | * Filenames allocated by record_filename are shared and have unlimited | | 50 | * Filenames allocated by record_filename are shared and have unlimited |
51 | * lifetime. | | 51 | * lifetime. |
52 | */ | | 52 | */ |
53 | struct filename { | | 53 | struct filename { |
54 | const char *fn_name; | | 54 | const char *fn_name; |
55 | size_t fn_len; | | 55 | size_t fn_len; |
56 | int fn_id; | | 56 | int fn_id; |
57 | struct filename *fn_next; | | 57 | struct filename *fn_next; |
58 | }; | | 58 | }; |
59 | | | 59 | |
60 | static struct filename *filenames; /* null-terminated array */ | | 60 | static struct filename *filenames; /* null-terminated array */ |
61 | | | 61 | |
62 | /* Find the given filename, or return NULL. */ | | 62 | /* Find the given filename, or return NULL. */ |
63 | static const struct filename * | | 63 | static const struct filename * |
64 | search_filename(const char *s, size_t len) | | 64 | search_filename(const char *s, size_t len) |
65 | { | | 65 | { |
66 | const struct filename *fn; | | 66 | const struct filename *fn; |
67 | | | 67 | |
68 | for (fn = filenames; fn != NULL; fn = fn->fn_next) { | | 68 | for (fn = filenames; fn != NULL; fn = fn->fn_next) { |
69 | if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) | | 69 | if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) |
70 | break; | | 70 | break; |
71 | } | | 71 | } |
72 | return fn; | | 72 | return fn; |
73 | } | | 73 | } |
74 | | | 74 | |
75 | struct filename_replacement { | | 75 | struct filename_replacement { |
76 | const char *orig; | | 76 | const char *orig; |
77 | size_t orig_len; | | 77 | size_t orig_len; |
78 | const char *repl; | | 78 | const char *repl; |
79 | const struct filename_replacement *next; | | 79 | const struct filename_replacement *next; |
80 | }; | | 80 | }; |
81 | | | 81 | |
82 | static struct filename_replacement *filename_replacements; | | 82 | static struct filename_replacement *filename_replacements; |
83 | | | 83 | |
84 | void | | 84 | void |
85 | add_directory_replacement(char *arg) | | 85 | add_directory_replacement(char *arg) |
86 | { | | 86 | { |
87 | struct filename_replacement *r = xmalloc(sizeof(*r)); | | 87 | struct filename_replacement *r = xmalloc(sizeof(*r)); |
88 | | | 88 | |
89 | char *sep = strchr(arg, '='); | | 89 | char *sep = strchr(arg, '='); |
90 | if (sep == NULL) | | 90 | if (sep == NULL) |
91 | err(1, "Bad replacement directory spec `%s'", arg); | | 91 | err(1, "Bad replacement directory spec `%s'", arg); |
92 | *sep = '\0'; | | 92 | *sep = '\0'; |
93 | | | 93 | |
94 | r->orig = arg; | | 94 | r->orig = arg; |
95 | r->orig_len = sep - arg; | | 95 | r->orig_len = sep - arg; |
96 | r->repl = sep + 1; | | 96 | r->repl = sep + 1; |
97 | r->next = filename_replacements; | | 97 | r->next = filename_replacements; |
98 | filename_replacements = r; | | 98 | filename_replacements = r; |
99 | } | | 99 | } |
100 | | | 100 | |
101 | const char * | | 101 | const char * |
102 | transform_filename(const char *name, size_t len) | | 102 | transform_filename(const char *name, size_t len) |
103 | { | | 103 | { |
104 | static char buf[MAXPATHLEN]; | | 104 | static char buf[MAXPATHLEN]; |
105 | const struct filename_replacement *r; | | 105 | const struct filename_replacement *r; |
106 | | | 106 | |
107 | for (r = filename_replacements; r != NULL; r = r->next) | | 107 | for (r = filename_replacements; r != NULL; r = r->next) |
108 | if (r->orig_len < len && | | 108 | if (r->orig_len < len && |
109 | memcmp(name, r->orig, r->orig_len) == 0) | | 109 | memcmp(name, r->orig, r->orig_len) == 0) |
110 | break; | | 110 | break; |
111 | if (r == NULL) | | 111 | if (r == NULL) |
112 | return name; | | 112 | return name; |
113 | (void)snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->orig_len); | | 113 | (void)snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->orig_len); |
114 | return buf; | | 114 | return buf; |
115 | } | | 115 | } |
116 | | | 116 | |
117 | static int | | 117 | static int |
118 | next_filename_id(void) | | 118 | next_filename_id(void) |
119 | { | | 119 | { |
120 | static int next_id = 0; | | 120 | static int next_id = 0; |
121 | | | 121 | |
122 | return next_id++; | | 122 | return next_id++; |
123 | } | | 123 | } |
124 | | | 124 | |
125 | /* | | 125 | /* |
126 | * Return a copy of the filename s with unlimited lifetime. | | 126 | * Return a copy of the filename s with unlimited lifetime. |
127 | * If the filename is new, write it to the output file. | | 127 | * If the filename is new, write it to the output file. |
128 | */ | | 128 | */ |
129 | const char * | | 129 | const char * |
130 | record_filename(const char *s, size_t slen) | | 130 | record_filename(const char *s, size_t slen) |
131 | { | | 131 | { |
132 | const struct filename *existing_fn; | | 132 | const struct filename *existing_fn; |
133 | struct filename *fn; | | 133 | struct filename *fn; |
134 | char *name; | | 134 | char *name; |
135 | | | 135 | |
136 | if (s == NULL) | | 136 | if (s == NULL) |
137 | return NULL; | | 137 | return NULL; |
138 | | | 138 | |
139 | if ((existing_fn = search_filename(s, slen)) != NULL) | | 139 | if ((existing_fn = search_filename(s, slen)) != NULL) |
140 | return existing_fn->fn_name; | | 140 | return existing_fn->fn_name; |
141 | | | 141 | |
142 | /* Do not use strdup() because s is not NUL-terminated.*/ | | 142 | /* Do not use strdup() because s is not NUL-terminated.*/ |
143 | name = xmalloc(slen + 1); | | 143 | name = xmalloc(slen + 1); |
144 | (void)memcpy(name, s, slen); | | 144 | (void)memcpy(name, s, slen); |
145 | name[slen] = '\0'; | | 145 | name[slen] = '\0'; |
146 | | | 146 | |
147 | fn = xmalloc(sizeof(*fn)); | | 147 | fn = xmalloc(sizeof(*fn)); |
148 | fn->fn_name = name; | | 148 | fn->fn_name = name; |
149 | fn->fn_len = slen; | | 149 | fn->fn_len = slen; |
150 | fn->fn_id = next_filename_id(); | | 150 | fn->fn_id = next_filename_id(); |
151 | fn->fn_next = filenames; | | 151 | fn->fn_next = filenames; |
152 | filenames = fn; | | 152 | filenames = fn; |
153 | | | 153 | |
154 | /* Write the ID of this filename to the output file. */ | | 154 | /* Write the ID of this filename to the output file. */ |
155 | outclr(); | | 155 | outclr(); |
156 | outint(fn->fn_id); | | 156 | outint(fn->fn_id); |
157 | outchar('s'); | | 157 | outchar('s'); |
158 | outstrg(transform_filename(fn->fn_name, fn->fn_len)); | | 158 | outstrg(transform_filename(fn->fn_name, fn->fn_len)); |
159 | | | 159 | |
160 | return fn->fn_name; | | 160 | return fn->fn_name; |
161 | } | | 161 | } |
162 | | | 162 | |
163 | /* Get the ID of a filename. */ | | 163 | /* Get the ID of a filename. */ |
164 | int | | 164 | int |
165 | get_filename_id(const char *s) | | 165 | get_filename_id(const char *s) |
166 | { | | 166 | { |
167 | const struct filename *fn; | | 167 | const struct filename *fn; |
168 | | | 168 | |
169 | if (s == NULL || (fn = search_filename(s, strlen(s))) == NULL) | | 169 | if (s == NULL || (fn = search_filename(s, strlen(s))) == NULL) |
170 | return -1; | | 170 | return -1; |
171 | return fn->fn_id; | | 171 | return fn->fn_id; |
172 | } | | 172 | } |
173 | | | 173 | |
174 | /* | | 174 | /* |
175 | * Memory for declarations and other things which must be available | | 175 | * Memory for declarations and other things which must be available |
176 | * until the end of a block (or the end of the translation unit) | | 176 | * until the end of a block (or the end of the translation unit) |
177 | * is associated with the corresponding mem_block_level, which may be 0. | | 177 | * is associated with the corresponding mem_block_level, which may be 0. |
178 | * Because this memory is allocated in large blocks associated with | | 178 | * Because this memory is allocated in large blocks associated with |
179 | * a given level it can be freed easily at the end of a block. | | 179 | * a given level it can be freed easily at the end of a block. |
180 | */ | | 180 | */ |
181 | #define ML_INC ((size_t)32) /* Increment for length of *mblks */ | | 181 | #define ML_INC ((size_t)32) /* Increment for length of *mblks */ |
182 | | | 182 | |
183 | typedef struct memory_block { | | 183 | typedef struct memory_block { |
184 | void *start; /* beginning of memory block */ | | 184 | void *start; /* beginning of memory block */ |
185 | void *first_free; /* first free byte */ | | 185 | void *first_free; /* first free byte */ |
186 | size_t nfree; /* # of free bytes */ | | 186 | size_t nfree; /* # of free bytes */ |
187 | size_t size; /* total size of memory block */ | | 187 | size_t size; /* total size of memory block */ |
188 | struct memory_block *next; | | 188 | struct memory_block *next; |
189 | } memory_block; | | 189 | } memory_block; |
190 | | | 190 | |
191 | /* | | 191 | /* |
192 | * Array of pointers to lists of memory blocks. mem_block_level is used as | | 192 | * Array of pointers to lists of memory blocks. mem_block_level is used as |
193 | * index into this array. | | 193 | * index into this array. |
194 | */ | | 194 | */ |
195 | static memory_block **mblks; | | 195 | static memory_block **mblks; |
196 | | | 196 | |
197 | /* number of elements in *mblks */ | | 197 | /* number of elements in *mblks */ |
198 | static size_t nmblks; | | 198 | static size_t nmblks; |
199 | | | 199 | |
200 | /* free list for memory blocks */ | | | |
201 | static memory_block *frmblks; | | | |
202 | | | | |
203 | /* length of new allocated memory blocks */ | | 200 | /* length of new allocated memory blocks */ |
204 | static size_t mblklen; | | 201 | static size_t mblklen; |
205 | | | 202 | |
206 | | | 203 | |
207 | static memory_block * | | 204 | static memory_block * |
208 | xnewblk(void) | | 205 | xnewblk(void) |
209 | { | | 206 | { |
210 | memory_block *mb = xmalloc(sizeof(*mb)); | | 207 | memory_block *mb = xmalloc(sizeof(*mb)); |
211 | | | 208 | |
212 | mb->start = xmalloc(mblklen); | | 209 | mb->start = xmalloc(mblklen); |
213 | mb->size = mblklen; | | 210 | mb->size = mblklen; |
214 | | | 211 | |
215 | return mb; | | 212 | return mb; |
216 | } | | 213 | } |
217 | | | 214 | |
218 | /* Allocate new memory, initialized with zero. */ | | 215 | /* Allocate new memory, initialized with zero. */ |
219 | static void * | | 216 | static void * |
220 | xgetblk(memory_block **mbp, size_t s) | | 217 | xgetblk(memory_block **mbp, size_t s) |
221 | { | | 218 | { |
222 | memory_block *mb; | | 219 | memory_block *mb; |
223 | void *p; | | 220 | void *p; |
224 | size_t t = 0; | | 221 | size_t t = 0; |
225 | | | 222 | |
226 | /* | | 223 | /* |
227 | * If the first block of the list has not enough free space, | | 224 | * If the first block of the list has not enough free space, |
228 | * or there is no first block, get a new block. The new block | | 225 | * or there is no first block, get a new block. The new block |
229 | * is taken from the free list or, if there is no block on the | | 226 | * is taken from the free list or, if there is no block on the |
230 | * free list, is allocated using xnewblk(). | | 227 | * free list, is allocated using xnewblk(). |
231 | * | | 228 | * |
232 | * If a new block is allocated it is initialized with zero. | | 229 | * If a new block is allocated it is initialized with zero. |
233 | * Blocks taken from the free list are zero'd in xfreeblk(). | | 230 | * Blocks taken from the free list are zero'd in xfreeblk(). |
234 | */ | | 231 | */ |
235 | | | 232 | |
236 | s = WORST_ALIGN(s); | | 233 | s = WORST_ALIGN(s); |
237 | if ((mb = *mbp) == NULL || mb->nfree < s) { | | 234 | if ((mb = *mbp) == NULL || mb->nfree < s) { |
238 | if ((mb = frmblks) == NULL || mb->size < s) { | | 235 | if (s > mblklen) { |
239 | if (s > mblklen) { | | 236 | t = mblklen; |
240 | t = mblklen; | | 237 | mblklen = s; |
241 | mblklen = s; | | 238 | } |
242 | } | | 239 | mb = xnewblk(); |
243 | mb = xnewblk(); | | | |
244 | #ifndef BLKDEBUG | | 240 | #ifndef BLKDEBUG |
245 | (void)memset(mb->start, 0, mb->size); | | 241 | (void)memset(mb->start, 0, mb->size); |
246 | #endif | | 242 | #endif |
247 | if (t > 0) | | 243 | if (t > 0) |
248 | mblklen = t; | | 244 | mblklen = t; |
249 | } else { | | | |
250 | frmblks = mb->next; | | | |
251 | } | | | |
252 | mb->first_free = mb->start; | | 245 | mb->first_free = mb->start; |
253 | mb->nfree = mb->size; | | 246 | mb->nfree = mb->size; |
254 | mb->next = *mbp; | | 247 | mb->next = *mbp; |
255 | *mbp = mb; | | 248 | *mbp = mb; |
256 | } | | 249 | } |
257 | p = mb->first_free; | | 250 | p = mb->first_free; |
258 | mb->first_free = (char *)mb->first_free + s; | | 251 | mb->first_free = (char *)mb->first_free + s; |
259 | mb->nfree -= s; | | 252 | mb->nfree -= s; |
260 | #ifdef BLKDEBUG | | 253 | #ifdef BLKDEBUG |
261 | (void)memset(p, 0, s); | | 254 | (void)memset(p, 0, s); |
262 | #endif | | 255 | #endif |
263 | return p; | | 256 | return p; |
264 | } | | 257 | } |
265 | | | 258 | |
266 | /* | | 259 | /* Free all blocks from list *fmbp. */ |
267 | * Move all blocks from list *fmbp to free list. For each block, set all | | | |
268 | * used memory to zero. | | | |
269 | */ | | | |
270 | static void | | 260 | static void |
271 | xfreeblk(memory_block **fmbp) | | 261 | xfreeblk(memory_block **fmbp) |
272 | { | | 262 | { |
273 | memory_block *mb; | | 263 | memory_block *mb; |
274 | | | 264 | |
275 | while ((mb = *fmbp) != NULL) { | | 265 | while ((mb = *fmbp) != NULL) { |
276 | *fmbp = mb->next; | | 266 | *fmbp = mb->next; |
277 | mb->next = frmblks; | | 267 | free(mb); |
278 | frmblks = mb; | | | |
279 | (void)memset(mb->start, INVALID_MEM_BYTE, | | | |
280 | mb->size - mb->nfree); | | | |
281 | } | | 268 | } |
282 | } | | 269 | } |
283 | | | 270 | |
284 | void | | 271 | void |
285 | initmem(void) | | 272 | initmem(void) |
286 | { | | 273 | { |
287 | | | 274 | |
288 | mblklen = mem_block_size(); | | 275 | mblklen = mem_block_size(); |
289 | mblks = xcalloc(nmblks = ML_INC, sizeof(*mblks)); | | 276 | mblks = xcalloc(nmblks = ML_INC, sizeof(*mblks)); |
290 | } | | 277 | } |
291 | | | 278 | |
292 | | | 279 | |
293 | /* Allocate memory associated with level l, initialized with zero. */ | | 280 | /* Allocate memory associated with level l, initialized with zero. */ |
294 | void * | | 281 | void * |
295 | getlblk(size_t l, size_t s) | | 282 | getlblk(size_t l, size_t s) |
296 | { | | 283 | { |
297 | | | 284 | |
298 | while (l >= nmblks) { | | 285 | while (l >= nmblks) { |
299 | mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof(*mblks)); | | 286 | mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof(*mblks)); |
300 | (void)memset(&mblks[nmblks], 0, ML_INC * sizeof(*mblks)); | | 287 | (void)memset(&mblks[nmblks], 0, ML_INC * sizeof(*mblks)); |
301 | nmblks += ML_INC; | | 288 | nmblks += ML_INC; |
302 | } | | 289 | } |
303 | return xgetblk(&mblks[l], s); | | 290 | return xgetblk(&mblks[l], s); |
304 | } | | 291 | } |
305 | | | 292 | |
306 | /* | | 293 | /* |
307 | * Return allocated memory for the current mem_block_level, initialized with | | 294 | * Return allocated memory for the current mem_block_level, initialized with |
308 | * zero. | | 295 | * zero. |
309 | */ | | 296 | */ |
310 | void * | | 297 | void * |
311 | getblk(size_t s) | | 298 | getblk(size_t s) |
312 | { | | 299 | { |
313 | | | 300 | |
314 | return getlblk(mem_block_level, s); | | 301 | return getlblk(mem_block_level, s); |
315 | } | | 302 | } |
316 | | | 303 | |
317 | /* Free all memory associated with level l. */ | | 304 | /* Free all memory associated with level l. */ |
318 | void | | 305 | void |
319 | freelblk(int l) | | 306 | freelblk(int l) |
320 | { | | 307 | { |
321 | | | 308 | |
322 | xfreeblk(&mblks[l]); | | 309 | xfreeblk(&mblks[l]); |
323 | } | | 310 | } |
324 | | | 311 | |
325 | void | | 312 | void |
326 | freeblk(void) | | 313 | freeblk(void) |
327 | { | | 314 | { |
328 | | | 315 | |
329 | freelblk(mem_block_level); | | 316 | freelblk(mem_block_level); |
330 | } | | 317 | } |
331 | | | 318 | |
332 | static memory_block *tmblk; | | 319 | static memory_block *tmblk; |
333 | | | 320 | |
334 | /* | | 321 | /* |
335 | * Return zero-initialized memory that is freed at the end of the current | | 322 | * Return zero-initialized memory that is freed at the end of the current |
336 | * expression. | | 323 | * expression. |
337 | */ | | 324 | */ |
338 | void * | | 325 | void * |
339 | expr_zalloc(size_t s) | | 326 | expr_zalloc(size_t s) |
340 | { | | 327 | { |
341 | | | 328 | |
342 | return xgetblk(&tmblk, s); | | 329 | return xgetblk(&tmblk, s); |
343 | } | | 330 | } |
344 | | | 331 | |
345 | static bool | | 332 | static bool |
346 | str_endswith(const char *haystack, const char *needle) | | 333 | str_endswith(const char *haystack, const char *needle) |
347 | { | | 334 | { |
348 | size_t hlen = strlen(haystack); | | 335 | size_t hlen = strlen(haystack); |
349 | size_t nlen = strlen(needle); | | 336 | size_t nlen = strlen(needle); |
350 | | | 337 | |
351 | return nlen <= hlen && | | 338 | return nlen <= hlen && |
352 | memcmp(haystack + hlen - nlen, needle, nlen) == 0; | | 339 | memcmp(haystack + hlen - nlen, needle, nlen) == 0; |
353 | } | | 340 | } |
354 | | | 341 | |
355 | /* | | 342 | /* |
356 | * Return a freshly allocated tree node that is freed at the end of the | | 343 | * Return a freshly allocated tree node that is freed at the end of the |
357 | * current expression. | | 344 | * current expression. |
358 | * | | 345 | * |
359 | * The node records whether it comes from a system file, which makes strict | | 346 | * The node records whether it comes from a system file, which makes strict |
360 | * bool mode less restrictive. | | 347 | * bool mode less restrictive. |
361 | */ | | 348 | */ |
362 | tnode_t * | | 349 | tnode_t * |
363 | expr_zalloc_tnode(void) | | 350 | expr_zalloc_tnode(void) |
364 | { | | 351 | { |
365 | tnode_t *tn = expr_zalloc(sizeof(*tn)); | | 352 | tnode_t *tn = expr_zalloc(sizeof(*tn)); |
366 | /* | | 353 | /* |
367 | * files named *.c that are different from the main translation unit | | 354 | * files named *.c that are different from the main translation unit |
368 | * typically contain generated code that cannot be influenced, such | | 355 | * typically contain generated code that cannot be influenced, such |
369 | * as a flex lexer or a yacc parser. | | 356 | * as a flex lexer or a yacc parser. |
370 | */ | | 357 | */ |
371 | tn->tn_sys = in_system_header || | | 358 | tn->tn_sys = in_system_header || |
372 | (curr_pos.p_file != csrc_pos.p_file && | | 359 | (curr_pos.p_file != csrc_pos.p_file && |
373 | str_endswith(curr_pos.p_file, ".c")); | | 360 | str_endswith(curr_pos.p_file, ".c")); |
374 | return tn; | | 361 | return tn; |
375 | } | | 362 | } |
376 | | | 363 | |
377 | /* Free all memory which is allocated by the current expression. */ | | 364 | /* Free all memory which is allocated by the current expression. */ |
378 | void | | 365 | void |
379 | expr_free_all(void) | | 366 | expr_free_all(void) |
380 | { | | 367 | { |
381 | | | 368 | |
382 | xfreeblk(&tmblk); | | 369 | xfreeblk(&tmblk); |
383 | } | | 370 | } |
384 | | | 371 | |
385 | /* | | 372 | /* |
386 | * Save the memory which is used by the current expression. This memory | | 373 | * Save the memory which is used by the current expression. This memory |
387 | * is not freed by the next expr_free_all() call. The pointer returned can be | | 374 | * is not freed by the next expr_free_all() call. The pointer returned can be |
388 | * used to restore the memory. | | 375 | * used to restore the memory. |
389 | */ | | 376 | */ |
390 | memory_block * | | 377 | memory_block * |
391 | expr_save_memory(void) | | 378 | expr_save_memory(void) |
392 | { | | 379 | { |
393 | memory_block *tmem; | | 380 | memory_block *tmem; |
394 | | | 381 | |
395 | tmem = tmblk; | | 382 | tmem = tmblk; |
396 | tmblk = NULL; | | 383 | tmblk = NULL; |
397 | return tmem; | | 384 | return tmem; |
398 | } | | 385 | } |
399 | | | 386 | |
400 | /* | | 387 | /* |
401 | * Free all memory used for the current expression and restore the memory used | | 388 | * Free all memory used for the current expression and restore the memory used |
402 | * by a previous expression and saved by expr_save_memory(). The next call to | | 389 | * by a previous expression and saved by expr_save_memory(). The next call to |
403 | * expr_free_all() frees the restored memory. | | 390 | * expr_free_all() frees the restored memory. |
404 | */ | | 391 | */ |
405 | void | | 392 | void |
406 | expr_restore_memory(memory_block *tmem) | | 393 | expr_restore_memory(memory_block *tmem) |
407 | { | | 394 | { |
408 | | | 395 | |
409 | expr_free_all(); | | 396 | expr_free_all(); |
410 | if (tmblk != NULL) { | | 397 | if (tmblk != NULL) { |
411 | free(tmblk->start); | | 398 | free(tmblk->start); |
412 | free(tmblk); | | 399 | free(tmblk); |
413 | } | | 400 | } |
414 | tmblk = tmem; | | 401 | tmblk = tmem; |
415 | } | | 402 | } |