mem1.c revision 1.19 1 /* $NetBSD: mem1.c,v 1.19 2020/12/28 12:52:45 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Jochen Pohl
5 * All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jochen Pohl for
18 * The NetBSD Project.
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.
21 *
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
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #if HAVE_NBTOOL_CONFIG_H
35 #include "nbtool_config.h"
36 #endif
37
38 #include <sys/cdefs.h>
39 #if defined(__RCSID) && !defined(lint)
40 __RCSID("$NetBSD: mem1.c,v 1.19 2020/12/28 12:52:45 rillig Exp $");
41 #endif
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include "lint1.h"
50
51 /*
52 * Filenames allocated by fnalloc() and fnnalloc() are shared.
53 */
54 typedef struct fn {
55 char *fn_name;
56 size_t fn_len;
57 int fn_id;
58 struct fn *fn_nxt;
59 } fn_t;
60
61 static fn_t *fnames;
62
63 static fn_t *srchfn(const char *, size_t);
64
65 /*
66 * Look for a Filename of length l.
67 */
68 static fn_t *
69 srchfn(const char *s, size_t len)
70 {
71 fn_t *fn;
72
73 for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
74 if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
75 break;
76 }
77 return (fn);
78 }
79
80 /*
81 * Return a shared string for filename s.
82 */
83 const char *
84 fnalloc(const char *s)
85 {
86
87 return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
88 }
89
90 struct repl {
91 char *orig;
92 char *repl;
93 size_t len;
94 struct repl *next;
95 };
96
97 struct repl *replist;
98
99 void
100 fnaddreplsrcdir(char *arg)
101 {
102 struct repl *r = xmalloc(sizeof(*r));
103
104 r->orig = arg;
105 if ((r->repl = strchr(arg, '=')) == NULL)
106 err(1, "Bad replacement directory spec `%s'", arg);
107 r->len = r->repl - r->orig;
108 *(r->repl)++ = '\0';
109 if (replist == NULL) {
110 r->next = NULL;
111 } else
112 r->next = replist;
113 replist = r;
114 }
115
116 const char *
117 fnxform(const char *name, size_t len)
118 {
119 static char buf[MAXPATHLEN];
120 struct repl *r;
121
122 for (r = replist; r; r = r->next)
123 if (r->len < len && memcmp(name, r->orig, r->len) == 0)
124 break;
125 if (r == NULL)
126 return name;
127 snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->len);
128 return buf;
129 }
130
131 const char *
132 fnnalloc(const char *s, size_t len)
133 {
134 fn_t *fn;
135
136 static int nxt_id = 0;
137
138 if (s == NULL)
139 return (NULL);
140
141 if ((fn = srchfn(s, len)) == NULL) {
142 fn = xmalloc(sizeof (fn_t));
143 /* Do not used strdup() because string is not NUL-terminated.*/
144 fn->fn_name = xmalloc(len + 1);
145 (void)memcpy(fn->fn_name, s, len);
146 fn->fn_name[len] = '\0';
147 fn->fn_len = len;
148 fn->fn_id = nxt_id++;
149 fn->fn_nxt = fnames;
150 fnames = fn;
151 /* Write id of this filename to the output file. */
152 outclr();
153 outint(fn->fn_id);
154 outchar('s');
155 outstrg(fnxform(fn->fn_name, fn->fn_len));
156 }
157 return (fn->fn_name);
158 }
159
160 /*
161 * Get id of a filename.
162 */
163 int
164 getfnid(const char *s)
165 {
166 fn_t *fn;
167
168 if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
169 return (-1);
170 return (fn->fn_id);
171 }
172
173 /*
174 * Memory for declarations and other things which must be available
175 * until the end of a block (or the end of the translation unit)
176 * are associated with the level (mblklev) of the block (or with 0).
177 * Because this memory is allocated in large blocks associated with
178 * a given level it can be freed easily at the end of a block.
179 */
180 #define ML_INC ((size_t)32) /* Increment for length of *mblks */
181
182 typedef struct mbl {
183 void *blk; /* beginning of memory block */
184 void *ffree; /* first free byte */
185 size_t nfree; /* # of free bytes */
186 size_t size; /* total size of memory block */
187 struct mbl *nxt; /* next block */
188 } mbl_t;
189
190 /*
191 * Array of pointers to lists of memory blocks. mblklev is used as
192 * index into this array.
193 */
194 static mbl_t **mblks;
195
196 /* number of elements in *mblks */
197 static size_t nmblks;
198
199 /* free list for memory blocks */
200 static mbl_t *frmblks;
201
202 /* length of new allocated memory blocks */
203 static size_t mblklen;
204
205 static void *xgetblk(mbl_t **, size_t);
206 static void xfreeblk(mbl_t **);
207 static mbl_t *xnewblk(void);
208
209 static mbl_t *
210 xnewblk(void)
211 {
212 mbl_t *mb = xmalloc(sizeof (mbl_t));
213
214 /* use mmap instead of malloc to avoid malloc's size overhead */
215 mb->blk = xmapalloc(mblklen);
216 mb->size = mblklen;
217
218 return (mb);
219 }
220
221 /*
222 * Allocate new memory. If the first block of the list has not enough
223 * free space, or there is no first block, get a new block. The new
224 * block is taken from the free list or, if there is no block on the
225 * free list, is allocated using xnewblk(). If a new block is allocated
226 * it is initialized with zero. Blocks taken from the free list are
227 * zero'd in xfreeblk().
228 */
229 static void *
230 xgetblk(mbl_t **mbp, size_t s)
231 {
232 mbl_t *mb;
233 void *p;
234 size_t t = 0;
235
236 s = WORST_ALIGN(s);
237 if ((mb = *mbp) == NULL || mb->nfree < s) {
238 if ((mb = frmblks) == NULL || mb->size < s) {
239 if (s > mblklen) {
240 t = mblklen;
241 mblklen = s;
242 }
243 mb = xnewblk();
244 #ifndef BLKDEBUG
245 (void)memset(mb->blk, 0, mb->size);
246 #endif
247 if (t)
248 mblklen = t;
249 } else {
250 frmblks = mb->nxt;
251 }
252 mb->ffree = mb->blk;
253 mb->nfree = mb->size;
254 mb->nxt = *mbp;
255 *mbp = mb;
256 }
257 p = mb->ffree;
258 mb->ffree = (char *)mb->ffree + s;
259 mb->nfree -= s;
260 #ifdef BLKDEBUG
261 (void)memset(p, 0, s);
262 #endif
263 return (p);
264 }
265
266 /*
267 * Move all blocks from list *fmbp to free list. For each block, set all
268 * used memory to zero.
269 */
270 static void
271 xfreeblk(mbl_t **fmbp)
272 {
273 mbl_t *mb;
274
275 while ((mb = *fmbp) != NULL) {
276 *fmbp = mb->nxt;
277 mb->nxt = frmblks;
278 frmblks = mb;
279 (void)memset(mb->blk, ZERO, mb->size - mb->nfree);
280 }
281 }
282
283 void
284 initmem(void)
285 {
286 int pgsz;
287
288 pgsz = getpagesize();
289 mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
290
291 mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
292 }
293
294
295 /*
296 * Allocate memory associated with level l.
297 */
298 void *
299 getlblk(size_t l, size_t s)
300 {
301
302 while (l >= nmblks) {
303 mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
304 (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
305 nmblks += ML_INC;
306 }
307 return (xgetblk(&mblks[l], s));
308 }
309
310 void *
311 getblk(size_t s)
312 {
313
314 return (getlblk(mblklev, s));
315 }
316
317 /*
318 * Free all memory associated with level l.
319 */
320 void
321 freelblk(int l)
322 {
323
324 xfreeblk(&mblks[l]);
325 }
326
327 void
328 freeblk(void)
329 {
330
331 freelblk(mblklev);
332 }
333
334 /*
335 * tgetblk() returns memory which is associated with the current
336 * expression.
337 */
338 static mbl_t *tmblk;
339
340 void *
341 tgetblk(size_t s)
342 {
343
344 return (xgetblk(&tmblk, s));
345 }
346
347 /*
348 * Get memory for a new tree node.
349 */
350 tnode_t *
351 getnode(void)
352 {
353
354 return (tgetblk(sizeof (tnode_t)));
355 }
356
357 /*
358 * Free all memory which is allocated by the current expression.
359 */
360 void
361 tfreeblk(void)
362 {
363
364 xfreeblk(&tmblk);
365 }
366
367 /*
368 * Save the memory which is used by the current expression. This memory
369 * is not freed by the next tfreeblk() call. The pointer returned can be
370 * used to restore the memory.
371 */
372 mbl_t *
373 tsave(void)
374 {
375 mbl_t *tmem;
376
377 tmem = tmblk;
378 tmblk = NULL;
379 return (tmem);
380 }
381
382 /*
383 * Free all memory used for the current expression and the memory used
384 * be a previous expression and saved by tsave(). The next call to
385 * tfreeblk() frees the restored memory.
386 */
387 void
388 trestor(mbl_t *tmem)
389 {
390
391 tfreeblk();
392 if (tmblk != NULL) {
393 free(tmblk->blk);
394 free(tmblk);
395 }
396 tmblk = tmem;
397 }
398