| @@ -1,386 +1,392 @@ | | | @@ -1,386 +1,392 @@ |
1 | /* $NetBSD: mem1.c,v 1.38 2021/04/02 09:39:25 rillig Exp $ */ | | 1 | /* $NetBSD: mem1.c,v 1.39 2021/04/02 09:45:55 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.38 2021/04/02 09:39:25 rillig Exp $"); | | 40 | __RCSID("$NetBSD: mem1.c,v 1.39 2021/04/02 09:45:55 rillig Exp $"); |
41 | #endif | | 41 | #endif |
42 | | | 42 | |
43 | #include <sys/types.h> | | 43 | #include <sys/types.h> |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <stdlib.h> | | 45 | #include <stdlib.h> |
46 | #include <string.h> | | 46 | #include <string.h> |
47 | #include <unistd.h> | | 47 | #include <unistd.h> |
48 | | | 48 | |
49 | #include "lint1.h" | | 49 | #include "lint1.h" |
50 | | | 50 | |
51 | /* | | 51 | /* |
52 | * Filenames allocated by record_filename are shared. | | 52 | * Filenames allocated by record_filename are shared. |
53 | */ | | 53 | */ |
54 | struct filename { | | 54 | struct filename { |
55 | char *fn_name; | | 55 | char *fn_name; |
56 | size_t fn_len; | | 56 | size_t fn_len; |
57 | int fn_id; | | 57 | int fn_id; |
58 | struct filename *fn_next; | | 58 | struct filename *fn_next; |
59 | }; | | 59 | }; |
60 | | | 60 | |
61 | static struct filename *filenames; /* null-terminated array */ | | 61 | static struct filename *filenames; /* null-terminated array */ |
62 | | | 62 | |
63 | /* Find the given filename, or return NULL. */ | | 63 | /* Find the given filename, or return NULL. */ |
64 | static const struct filename * | | 64 | static const struct filename * |
65 | search_filename(const char *s, size_t len) | | 65 | search_filename(const char *s, size_t len) |
66 | { | | 66 | { |
67 | const struct filename *fn; | | 67 | const struct filename *fn; |
68 | | | 68 | |
69 | for (fn = filenames; fn != NULL; fn = fn->fn_next) { | | 69 | for (fn = filenames; fn != NULL; fn = fn->fn_next) { |
70 | if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) | | 70 | if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) |
71 | break; | | 71 | break; |
72 | } | | 72 | } |
73 | return fn; | | 73 | return fn; |
74 | } | | 74 | } |
75 | | | 75 | |
76 | struct filename_replacement { | | 76 | struct filename_replacement { |
77 | char *orig; | | 77 | char *orig; |
78 | size_t orig_len; | | 78 | size_t orig_len; |
79 | char *repl; | | 79 | char *repl; |
80 | struct filename_replacement *next; | | 80 | struct filename_replacement *next; |
81 | }; | | 81 | }; |
82 | | | 82 | |
83 | static struct filename_replacement *filename_replacements; | | 83 | static struct filename_replacement *filename_replacements; |
84 | | | 84 | |
85 | void | | 85 | void |
86 | add_directory_replacement(char *arg) | | 86 | add_directory_replacement(char *arg) |
87 | { | | 87 | { |
88 | struct filename_replacement *r = xmalloc(sizeof *r); | | 88 | struct filename_replacement *r = xmalloc(sizeof *r); |
89 | | | 89 | |
90 | char *sep = strchr(arg, '='); | | 90 | char *sep = strchr(arg, '='); |
91 | if (sep == NULL) | | 91 | if (sep == NULL) |
92 | err(1, "Bad replacement directory spec `%s'", arg); | | 92 | err(1, "Bad replacement directory spec `%s'", arg); |
93 | *sep = '\0'; | | 93 | *sep = '\0'; |
94 | | | 94 | |
95 | r->orig = arg; | | 95 | r->orig = arg; |
96 | r->orig_len = sep - arg; | | 96 | r->orig_len = sep - arg; |
97 | r->repl = sep + 1; | | 97 | r->repl = sep + 1; |
98 | r->next = filename_replacements; | | 98 | r->next = filename_replacements; |
99 | filename_replacements = r; | | 99 | filename_replacements = r; |
100 | } | | 100 | } |
101 | | | 101 | |
102 | const char * | | 102 | const char * |
103 | transform_filename(const char *name, size_t len) | | 103 | transform_filename(const char *name, size_t len) |
104 | { | | 104 | { |
105 | static char buf[MAXPATHLEN]; | | 105 | static char buf[MAXPATHLEN]; |
106 | const struct filename_replacement *r; | | 106 | const struct filename_replacement *r; |
107 | | | 107 | |
108 | for (r = filename_replacements; r != NULL; r = r->next) | | 108 | for (r = filename_replacements; r != NULL; r = r->next) |
109 | if (r->orig_len < len && | | 109 | if (r->orig_len < len && |
110 | memcmp(name, r->orig, r->orig_len) == 0) | | 110 | memcmp(name, r->orig, r->orig_len) == 0) |
111 | break; | | 111 | break; |
112 | if (r == NULL) | | 112 | if (r == NULL) |
113 | return name; | | 113 | return name; |
114 | snprintf(buf, sizeof buf, "%s%s", r->repl, name + r->orig_len); | | 114 | snprintf(buf, sizeof buf, "%s%s", r->repl, name + r->orig_len); |
115 | return buf; | | 115 | return buf; |
116 | } | | 116 | } |
117 | | | 117 | |
| | | 118 | static int |
| | | 119 | next_filename_id(void) |
| | | 120 | { |
| | | 121 | static int next_id = 0; |
| | | 122 | |
| | | 123 | return next_id++; |
| | | 124 | } |
| | | 125 | |
118 | /* | | 126 | /* |
119 | * Return a copy of the filename s with unlimited lifetime. | | 127 | * Return a copy of the filename s with unlimited lifetime. |
120 | * If the filename is new, write it to the output file. | | 128 | * If the filename is new, write it to the output file. |
121 | */ | | 129 | */ |
122 | const char * | | 130 | const char * |
123 | record_filename(const char *s, size_t slen) | | 131 | record_filename(const char *s, size_t slen) |
124 | { | | 132 | { |
125 | const struct filename *existing_fn; | | 133 | const struct filename *existing_fn; |
126 | struct filename *fn; | | 134 | struct filename *fn; |
127 | | | 135 | |
128 | static int nxt_id = 0; | | | |
129 | | | | |
130 | if (s == NULL) | | 136 | if (s == NULL) |
131 | return NULL; | | 137 | return NULL; |
132 | | | 138 | |
133 | if ((existing_fn = search_filename(s, slen)) != NULL) | | 139 | if ((existing_fn = search_filename(s, slen)) != NULL) |
134 | return existing_fn->fn_name; | | 140 | return existing_fn->fn_name; |
135 | | | 141 | |
136 | fn = xmalloc(sizeof(*fn)); | | 142 | fn = xmalloc(sizeof(*fn)); |
137 | /* Do not use strdup() because s is not NUL-terminated.*/ | | 143 | /* Do not use strdup() because s is not NUL-terminated.*/ |
138 | fn->fn_name = xmalloc(slen + 1); | | 144 | fn->fn_name = xmalloc(slen + 1); |
139 | (void)memcpy(fn->fn_name, s, slen); | | 145 | (void)memcpy(fn->fn_name, s, slen); |
140 | fn->fn_name[slen] = '\0'; | | 146 | fn->fn_name[slen] = '\0'; |
141 | fn->fn_len = slen; | | 147 | fn->fn_len = slen; |
142 | fn->fn_id = nxt_id++; | | 148 | fn->fn_id = next_filename_id(); |
143 | fn->fn_next = filenames; | | 149 | fn->fn_next = filenames; |
144 | filenames = fn; | | 150 | filenames = fn; |
145 | | | 151 | |
146 | /* Write the ID of this filename to the output file. */ | | 152 | /* Write the ID of this filename to the output file. */ |
147 | outclr(); | | 153 | outclr(); |
148 | outint(fn->fn_id); | | 154 | outint(fn->fn_id); |
149 | outchar('s'); | | 155 | outchar('s'); |
150 | outstrg(transform_filename(fn->fn_name, fn->fn_len)); | | 156 | outstrg(transform_filename(fn->fn_name, fn->fn_len)); |
151 | | | 157 | |
152 | return fn->fn_name; | | 158 | return fn->fn_name; |
153 | } | | 159 | } |
154 | | | 160 | |
155 | /* Get the ID of a filename. */ | | 161 | /* Get the ID of a filename. */ |
156 | int | | 162 | int |
157 | get_filename_id(const char *s) | | 163 | get_filename_id(const char *s) |
158 | { | | 164 | { |
159 | const struct filename *fn; | | 165 | const struct filename *fn; |
160 | | | 166 | |
161 | if (s == NULL || (fn = search_filename(s, strlen(s))) == NULL) | | 167 | if (s == NULL || (fn = search_filename(s, strlen(s))) == NULL) |
162 | return -1; | | 168 | return -1; |
163 | return fn->fn_id; | | 169 | return fn->fn_id; |
164 | } | | 170 | } |
165 | | | 171 | |
166 | /* | | 172 | /* |
167 | * Memory for declarations and other things which must be available | | 173 | * Memory for declarations and other things which must be available |
168 | * until the end of a block (or the end of the translation unit) | | 174 | * until the end of a block (or the end of the translation unit) |
169 | * are associated with the level (mem_block_level) of the block (or with 0). | | 175 | * are associated with the level (mem_block_level) of the block (or with 0). |
170 | * Because this memory is allocated in large blocks associated with | | 176 | * Because this memory is allocated in large blocks associated with |
171 | * a given level it can be freed easily at the end of a block. | | 177 | * a given level it can be freed easily at the end of a block. |
172 | */ | | 178 | */ |
173 | #define ML_INC ((size_t)32) /* Increment for length of *mblks */ | | 179 | #define ML_INC ((size_t)32) /* Increment for length of *mblks */ |
174 | | | 180 | |
175 | typedef struct memory_block { | | 181 | typedef struct memory_block { |
176 | void *blk; /* beginning of memory block */ | | 182 | void *blk; /* beginning of memory block */ |
177 | void *ffree; /* first free byte */ | | 183 | void *ffree; /* first free byte */ |
178 | size_t nfree; /* # of free bytes */ | | 184 | size_t nfree; /* # of free bytes */ |
179 | size_t size; /* total size of memory block */ | | 185 | size_t size; /* total size of memory block */ |
180 | struct memory_block *nxt; /* next block */ | | 186 | struct memory_block *nxt; /* next block */ |
181 | } memory_block; | | 187 | } memory_block; |
182 | | | 188 | |
183 | /* | | 189 | /* |
184 | * Array of pointers to lists of memory blocks. mem_block_level is used as | | 190 | * Array of pointers to lists of memory blocks. mem_block_level is used as |
185 | * index into this array. | | 191 | * index into this array. |
186 | */ | | 192 | */ |
187 | static memory_block **mblks; | | 193 | static memory_block **mblks; |
188 | | | 194 | |
189 | /* number of elements in *mblks */ | | 195 | /* number of elements in *mblks */ |
190 | static size_t nmblks; | | 196 | static size_t nmblks; |
191 | | | 197 | |
192 | /* free list for memory blocks */ | | 198 | /* free list for memory blocks */ |
193 | static memory_block *frmblks; | | 199 | static memory_block *frmblks; |
194 | | | 200 | |
195 | /* length of new allocated memory blocks */ | | 201 | /* length of new allocated memory blocks */ |
196 | static size_t mblklen; | | 202 | static size_t mblklen; |
197 | | | 203 | |
198 | static void *xgetblk(memory_block **, size_t); | | 204 | static void *xgetblk(memory_block **, size_t); |
199 | static void xfreeblk(memory_block **); | | 205 | static void xfreeblk(memory_block **); |
200 | static memory_block *xnewblk(void); | | 206 | static memory_block *xnewblk(void); |
201 | | | 207 | |
202 | static memory_block * | | 208 | static memory_block * |
203 | xnewblk(void) | | 209 | xnewblk(void) |
204 | { | | 210 | { |
205 | memory_block *mb = xmalloc(sizeof *mb); | | 211 | memory_block *mb = xmalloc(sizeof *mb); |
206 | | | 212 | |
207 | /* use mmap instead of malloc to avoid malloc's size overhead */ | | 213 | /* use mmap instead of malloc to avoid malloc's size overhead */ |
208 | mb->blk = xmapalloc(mblklen); | | 214 | mb->blk = xmapalloc(mblklen); |
209 | mb->size = mblklen; | | 215 | mb->size = mblklen; |
210 | | | 216 | |
211 | return mb; | | 217 | return mb; |
212 | } | | 218 | } |
213 | | | 219 | |
214 | /* Allocate new memory, initialized with zero. */ | | 220 | /* Allocate new memory, initialized with zero. */ |
215 | static void * | | 221 | static void * |
216 | xgetblk(memory_block **mbp, size_t s) | | 222 | xgetblk(memory_block **mbp, size_t s) |
217 | { | | 223 | { |
218 | memory_block *mb; | | 224 | memory_block *mb; |
219 | void *p; | | 225 | void *p; |
220 | size_t t = 0; | | 226 | size_t t = 0; |
221 | | | 227 | |
222 | /* | | 228 | /* |
223 | * If the first block of the list has not enough free space, | | 229 | * If the first block of the list has not enough free space, |
224 | * or there is no first block, get a new block. The new block | | 230 | * or there is no first block, get a new block. The new block |
225 | * is taken from the free list or, if there is no block on the | | 231 | * is taken from the free list or, if there is no block on the |
226 | * free list, is allocated using xnewblk(). | | 232 | * free list, is allocated using xnewblk(). |
227 | * | | 233 | * |
228 | * If a new block is allocated it is initialized with zero. | | 234 | * If a new block is allocated it is initialized with zero. |
229 | * Blocks taken from the free list are zero'd in xfreeblk(). | | 235 | * Blocks taken from the free list are zero'd in xfreeblk(). |
230 | */ | | 236 | */ |
231 | | | 237 | |
232 | s = WORST_ALIGN(s); | | 238 | s = WORST_ALIGN(s); |
233 | if ((mb = *mbp) == NULL || mb->nfree < s) { | | 239 | if ((mb = *mbp) == NULL || mb->nfree < s) { |
234 | if ((mb = frmblks) == NULL || mb->size < s) { | | 240 | if ((mb = frmblks) == NULL || mb->size < s) { |
235 | if (s > mblklen) { | | 241 | if (s > mblklen) { |
236 | t = mblklen; | | 242 | t = mblklen; |
237 | mblklen = s; | | 243 | mblklen = s; |
238 | } | | 244 | } |
239 | mb = xnewblk(); | | 245 | mb = xnewblk(); |
240 | #ifndef BLKDEBUG | | 246 | #ifndef BLKDEBUG |
241 | (void)memset(mb->blk, 0, mb->size); | | 247 | (void)memset(mb->blk, 0, mb->size); |
242 | #endif | | 248 | #endif |
243 | if (t > 0) | | 249 | if (t > 0) |
244 | mblklen = t; | | 250 | mblklen = t; |
245 | } else { | | 251 | } else { |
246 | frmblks = mb->nxt; | | 252 | frmblks = mb->nxt; |
247 | } | | 253 | } |
248 | mb->ffree = mb->blk; | | 254 | mb->ffree = mb->blk; |
249 | mb->nfree = mb->size; | | 255 | mb->nfree = mb->size; |
250 | mb->nxt = *mbp; | | 256 | mb->nxt = *mbp; |
251 | *mbp = mb; | | 257 | *mbp = mb; |
252 | } | | 258 | } |
253 | p = mb->ffree; | | 259 | p = mb->ffree; |
254 | mb->ffree = (char *)mb->ffree + s; | | 260 | mb->ffree = (char *)mb->ffree + s; |
255 | mb->nfree -= s; | | 261 | mb->nfree -= s; |
256 | #ifdef BLKDEBUG | | 262 | #ifdef BLKDEBUG |
257 | (void)memset(p, 0, s); | | 263 | (void)memset(p, 0, s); |
258 | #endif | | 264 | #endif |
259 | return p; | | 265 | return p; |
260 | } | | 266 | } |
261 | | | 267 | |
262 | /* | | 268 | /* |
263 | * Move all blocks from list *fmbp to free list. For each block, set all | | 269 | * Move all blocks from list *fmbp to free list. For each block, set all |
264 | * used memory to zero. | | 270 | * used memory to zero. |
265 | */ | | 271 | */ |
266 | static void | | 272 | static void |
267 | xfreeblk(memory_block **fmbp) | | 273 | xfreeblk(memory_block **fmbp) |
268 | { | | 274 | { |
269 | memory_block *mb; | | 275 | memory_block *mb; |
270 | | | 276 | |
271 | while ((mb = *fmbp) != NULL) { | | 277 | while ((mb = *fmbp) != NULL) { |
272 | *fmbp = mb->nxt; | | 278 | *fmbp = mb->nxt; |
273 | mb->nxt = frmblks; | | 279 | mb->nxt = frmblks; |
274 | frmblks = mb; | | 280 | frmblks = mb; |
275 | (void)memset(mb->blk, ZERO, mb->size - mb->nfree); | | 281 | (void)memset(mb->blk, ZERO, mb->size - mb->nfree); |
276 | } | | 282 | } |
277 | } | | 283 | } |
278 | | | 284 | |
279 | void | | 285 | void |
280 | initmem(void) | | 286 | initmem(void) |
281 | { | | 287 | { |
282 | int pgsz; | | 288 | int pgsz; |
283 | | | 289 | |
284 | pgsz = getpagesize(); | | 290 | pgsz = getpagesize(); |
285 | mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz; | | 291 | mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz; |
286 | | | 292 | |
287 | mblks = xcalloc(nmblks = ML_INC, sizeof *mblks); | | 293 | mblks = xcalloc(nmblks = ML_INC, sizeof *mblks); |
288 | } | | 294 | } |
289 | | | 295 | |
290 | | | 296 | |
291 | /* Allocate memory associated with level l. */ | | 297 | /* Allocate memory associated with level l. */ |
292 | void * | | 298 | void * |
293 | getlblk(size_t l, size_t s) | | 299 | getlblk(size_t l, size_t s) |
294 | { | | 300 | { |
295 | | | 301 | |
296 | while (l >= nmblks) { | | 302 | while (l >= nmblks) { |
297 | mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof *mblks); | | 303 | mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof *mblks); |
298 | (void)memset(&mblks[nmblks], 0, ML_INC * sizeof *mblks); | | 304 | (void)memset(&mblks[nmblks], 0, ML_INC * sizeof *mblks); |
299 | nmblks += ML_INC; | | 305 | nmblks += ML_INC; |
300 | } | | 306 | } |
301 | return xgetblk(&mblks[l], s); | | 307 | return xgetblk(&mblks[l], s); |
302 | } | | 308 | } |
303 | | | 309 | |
304 | void * | | 310 | void * |
305 | getblk(size_t s) | | 311 | getblk(size_t s) |
306 | { | | 312 | { |
307 | | | 313 | |
308 | return getlblk(mem_block_level, s); | | 314 | return getlblk(mem_block_level, s); |
309 | } | | 315 | } |
310 | | | 316 | |
311 | /* Free all memory associated with level l. */ | | 317 | /* Free all memory associated with level l. */ |
312 | void | | 318 | void |
313 | freelblk(int l) | | 319 | freelblk(int l) |
314 | { | | 320 | { |
315 | | | 321 | |
316 | xfreeblk(&mblks[l]); | | 322 | xfreeblk(&mblks[l]); |
317 | } | | 323 | } |
318 | | | 324 | |
319 | void | | 325 | void |
320 | freeblk(void) | | 326 | freeblk(void) |
321 | { | | 327 | { |
322 | | | 328 | |
323 | freelblk(mem_block_level); | | 329 | freelblk(mem_block_level); |
324 | } | | 330 | } |
325 | | | 331 | |
326 | static memory_block *tmblk; | | 332 | static memory_block *tmblk; |
327 | | | 333 | |
328 | /* | | 334 | /* |
329 | * Return zero-initialized memory that is freed at the end of the current | | 335 | * Return zero-initialized memory that is freed at the end of the current |
330 | * expression. | | 336 | * expression. |
331 | */ | | 337 | */ |
332 | void * | | 338 | void * |
333 | tgetblk(size_t s) | | 339 | tgetblk(size_t s) |
334 | { | | 340 | { |
335 | | | 341 | |
336 | return xgetblk(&tmblk, s); | | 342 | return xgetblk(&tmblk, s); |
337 | } | | 343 | } |
338 | | | 344 | |
339 | /* Return a freshly allocated tree node. */ | | 345 | /* Return a freshly allocated tree node. */ |
340 | tnode_t * | | 346 | tnode_t * |
341 | getnode(void) | | 347 | getnode(void) |
342 | { | | 348 | { |
343 | tnode_t *tn = tgetblk(sizeof *tn); | | 349 | tnode_t *tn = tgetblk(sizeof *tn); |
344 | tn->tn_from_system_header = in_system_header; | | 350 | tn->tn_from_system_header = in_system_header; |
345 | return tn; | | 351 | return tn; |
346 | } | | 352 | } |
347 | | | 353 | |
348 | /* Free all memory which is allocated by the current expression. */ | | 354 | /* Free all memory which is allocated by the current expression. */ |
349 | void | | 355 | void |
350 | tfreeblk(void) | | 356 | tfreeblk(void) |
351 | { | | 357 | { |
352 | | | 358 | |
353 | xfreeblk(&tmblk); | | 359 | xfreeblk(&tmblk); |
354 | } | | 360 | } |
355 | | | 361 | |
356 | /* | | 362 | /* |
357 | * Save the memory which is used by the current expression. This memory | | 363 | * Save the memory which is used by the current expression. This memory |
358 | * is not freed by the next tfreeblk() call. The pointer returned can be | | 364 | * is not freed by the next tfreeblk() call. The pointer returned can be |
359 | * used to restore the memory. | | 365 | * used to restore the memory. |
360 | */ | | 366 | */ |
361 | memory_block * | | 367 | memory_block * |
362 | tsave(void) | | 368 | tsave(void) |
363 | { | | 369 | { |
364 | memory_block *tmem; | | 370 | memory_block *tmem; |
365 | | | 371 | |
366 | tmem = tmblk; | | 372 | tmem = tmblk; |
367 | tmblk = NULL; | | 373 | tmblk = NULL; |
368 | return tmem; | | 374 | return tmem; |
369 | } | | 375 | } |
370 | | | 376 | |
371 | /* | | 377 | /* |
372 | * Free all memory used for the current expression and the memory used | | 378 | * Free all memory used for the current expression and the memory used |
373 | * be a previous expression and saved by tsave(). The next call to | | 379 | * be a previous expression and saved by tsave(). The next call to |
374 | * tfreeblk() frees the restored memory. | | 380 | * tfreeblk() frees the restored memory. |
375 | */ | | 381 | */ |
376 | void | | 382 | void |
377 | trestor(memory_block *tmem) | | 383 | trestor(memory_block *tmem) |
378 | { | | 384 | { |
379 | | | 385 | |
380 | tfreeblk(); | | 386 | tfreeblk(); |
381 | if (tmblk != NULL) { | | 387 | if (tmblk != NULL) { |
382 | free(tmblk->blk); | | 388 | free(tmblk->blk); |
383 | free(tmblk); | | 389 | free(tmblk); |
384 | } | | 390 | } |
385 | tmblk = tmem; | | 391 | tmblk = tmem; |
386 | } | | 392 | } |