7c688e84bf8e86b2ce669296f6f5790b5d2e43d5
[dragonfly.git] / usr.bin / xlint / lint1 / mem1.c
1 /*      $NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd 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  * $NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $
34  */
35
36 #include <sys/types.h>
37 #include <sys/mman.h>
38 #include <sys/param.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <err.h>
43
44 #include "lint1.h"
45
46 /*
47  * Filenames allocated by fnalloc() and fnnalloc() are shared.
48  */
49 typedef struct fn {
50         char    *fn_name;
51         size_t  fn_len;
52         int     fn_id;
53         struct  fn *fn_nxt;
54 } fn_t;
55
56 static  fn_t    *fnames;
57
58 static  fn_t    *srchfn __P((const char *, size_t));
59
60 /*
61  * Look for a Filename of length l.
62  */
63 static fn_t *
64 srchfn(s, len)
65         const   char *s;
66         size_t  len;
67 {
68         fn_t    *fn;
69
70         for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
71                 if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
72                         break;
73         }
74         return (fn);
75 }
76
77 /*
78  * Return a shared string for filename s.
79  */
80 const char *
81 fnalloc(s)
82         const   char *s;
83 {
84         return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
85 }
86
87 const char *
88 fnnalloc(s, len)
89         const   char *s;
90         size_t  len;
91 {
92         fn_t    *fn;
93
94         static  int     nxt_id = 0;
95
96         if (s == NULL)
97                 return (NULL);
98
99         if ((fn = srchfn(s, len)) == NULL) {
100                 fn = xmalloc(sizeof (fn_t));
101                 /* Do not used strdup() because string is not NUL-terminated.*/
102                 fn->fn_name = xmalloc(len + 1);
103                 (void)memcpy(fn->fn_name, s, len);
104                 fn->fn_name[len] = '\0';
105                 fn->fn_len = len;
106                 fn->fn_id = nxt_id++;
107                 fn->fn_nxt = fnames;
108                 fnames = fn;
109                 /* Write id of this filename to the output file. */
110                 outclr();
111                 outint(fn->fn_id);
112                 outchar('s');
113                 outstrg(fn->fn_name);
114         }
115         return (fn->fn_name);
116 }
117
118 /*
119  * Get id of a filename.
120  */
121 int
122 getfnid(s)
123         const   char *s;
124 {
125         fn_t    *fn;
126
127         if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
128                 return (-1);
129         return (fn->fn_id);
130 }
131
132 /*
133  * Memory for declarations and other things which must be available
134  * until the end of a block (or the end of the translation unit)
135  * are assoziated with the level (mblklev) of the block (or wiht 0).
136  * Because these memory is allocated in large blocks associated with
137  * a given level it can be freed easily at the end of a block.
138  */
139 #define ML_INC  ((size_t)32)            /* Increment for length of *mblks */
140
141 typedef struct mbl {
142         void    *blk;                   /* beginning of memory block */
143         void    *ffree;                 /* first free byte */
144         size_t  nfree;                  /* # of free bytes */
145         size_t  size;                   /* total size of memory block */
146         struct  mbl *nxt;               /* next block */
147 } mbl_t;
148
149 /*
150  * Array of pointers to lists of memory blocks. mblklev is used as
151  * index into this array.
152  */
153 static  mbl_t   **mblks;
154
155 /* number of elements in *mblks */
156 static  size_t  nmblks;
157
158 /* free list for memory blocks */
159 static  mbl_t   *frmblks;
160
161 /* length of new allocated memory blocks */
162 static  size_t  mblklen;
163
164 static  void    *xgetblk __P((mbl_t **, size_t));
165 static  void    xfreeblk __P((mbl_t **));
166 static  mbl_t   *xnewblk __P((void));
167
168 static mbl_t *
169 xnewblk()
170 {
171         mbl_t   *mb;
172         int     prot, flags;
173
174         mb = xmalloc(sizeof (mbl_t));
175
176         /* use mmap instead of malloc to avoid malloc's size overhead */
177
178         prot = PROT_READ | PROT_WRITE;
179         flags = MAP_ANON | MAP_PRIVATE;
180         mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
181         if (mb->blk == (void *)MAP_FAILED)
182                 err(1, "can't map memory");
183         if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
184                 errx(1, "mapped address is not aligned");
185
186         mb->size = mblklen;
187
188         return (mb);
189 }
190
191 /*
192  * Allocate new memory. If the first block of the list has not enough
193  * free space, or there is no first block, get a new block. The new
194  * block is taken from the free list or, if there is no block on the
195  * free list, is allocated using xnewblk(). If a new block is allocated
196  * it is initialized with zero. Blocks taken from the free list are
197  * zero'd in xfreeblk().
198  */
199 static void *
200 xgetblk(mbp, s)
201         mbl_t   **mbp;
202         size_t  s;
203 {
204         mbl_t   *mb;
205         void    *p;
206
207         s = ALIGN(s);
208         if ((mb = *mbp) == NULL || mb->nfree < s) {
209                 if ((mb = frmblks) == NULL) {
210                         mb = xnewblk();
211                         (void)memset(mb->blk, 0, mb->size);
212                 } else {
213                         frmblks = mb->nxt;
214                 }
215                 mb->ffree = mb->blk;
216                 mb->nfree = mb->size;;
217                 mb->nxt = *mbp;
218                 *mbp = mb;
219         }
220         p = mb->ffree;
221         mb->ffree = (char *)mb->ffree + s;
222         mb->nfree -= s;
223         return (p);
224 }
225
226 /*
227  * Move all blocks from list *fmbp to free list. For each block, set all
228  * used memory to zero.
229  */
230 static void
231 xfreeblk(fmbp)
232         mbl_t   **fmbp;
233 {
234         mbl_t   *mb;
235
236         while ((mb = *fmbp) != NULL) {
237                 *fmbp = mb->nxt;
238                 mb->nxt = frmblks;
239                 frmblks = mb;
240                 (void)memset(mb->blk, 0, mb->size - mb->nfree);
241         }
242 }
243
244 void
245 initmem()
246 {
247         int     pgsz;
248
249         pgsz = getpagesize();
250         mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
251
252         mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
253 }
254
255         
256 /*
257  * Allocate memory associated with level l.
258  */
259 void *
260 getlblk(l, s)
261         int     l;
262         size_t  s;
263 {
264         while (l >= nmblks) {
265                 mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
266                 (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
267                 nmblks += ML_INC;
268         }
269         return (xgetblk(&mblks[l], s));
270 }
271
272 void *
273 getblk(s)
274         size_t  s;
275 {
276         return (getlblk(mblklev, s));
277 }
278
279 /*
280  * Free all memory associated with level l.
281  */
282 void
283 freelblk(l)
284         int     l;
285 {
286         xfreeblk(&mblks[l]);
287 }
288
289 void
290 freeblk()
291 {
292         freelblk(mblklev);
293 }
294
295 /*
296  * tgetblk() returns memory which is associated with the current
297  * expression.
298  */
299 static  mbl_t   *tmblk;
300
301 void *
302 tgetblk(s)
303         size_t  s;
304 {
305         return (xgetblk(&tmblk, s));
306 }
307
308 /*
309  * Get memory for a new tree node.
310  */
311 tnode_t *
312 getnode()
313 {
314         return (tgetblk(sizeof (tnode_t)));
315 }
316
317 /*
318  * Free all memory which is allocated by the the current expression.
319  */
320 void
321 tfreeblk()
322 {
323         xfreeblk(&tmblk);
324 }
325
326 /*
327  * Save the memory which is used by the current expression. This memory
328  * is not freed by the next tfreeblk() call. The pointer returned can be
329  * used to restore the memory.
330  */
331 mbl_t *
332 tsave()
333 {
334         mbl_t   *tmem;
335
336         tmem = tmblk;
337         tmblk = NULL;
338         return (tmem);
339 }
340
341 /*
342  * Free all memory used for the current expression and the memory used
343  * be a previous expression and saved by tsave(). The next call to
344  * tfreeblk() frees the restored memory.
345  */
346 void
347 trestor(tmem)
348         mbl_t   *tmem;
349 {
350         tfreeblk();
351         if (tmblk != NULL) {
352                 free(tmblk->blk);
353                 free(tmblk);
354         }
355         tmblk = tmem;
356 }