Home | History | Annotate | Line # | Download | only in lint1
mem1.c revision 1.23
      1 /*	$NetBSD: mem1.c,v 1.23 2021/01/16 02:40:02 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.23 2021/01/16 02:40:02 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_next;
     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_next) {
     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 != NULL; 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_next = 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 /* Allocate new memory, initialized with zero. */
    222 static void *
    223 xgetblk(mbl_t **mbp, size_t s)
    224 {
    225 	mbl_t	*mb;
    226 	void	*p;
    227 	size_t	t = 0;
    228 
    229 	/*
    230 	 * If the first block of the list has not enough free space,
    231 	 * or there is no first block, get a new block. The new block
    232 	 * is taken from the free list or, if there is no block on the
    233 	 * free list, is allocated using xnewblk().
    234 	 *
    235 	 * If a new block is allocated it is initialized with zero.
    236 	 * Blocks taken from the free list are zero'd in xfreeblk().
    237 	 */
    238 
    239 	s = WORST_ALIGN(s);
    240 	if ((mb = *mbp) == NULL || mb->nfree < s) {
    241 		if ((mb = frmblks) == NULL || mb->size < s) {
    242 			if (s > mblklen) {
    243 				t = mblklen;
    244 				mblklen = s;
    245 			}
    246 			mb = xnewblk();
    247 #ifndef BLKDEBUG
    248 			(void)memset(mb->blk, 0, mb->size);
    249 #endif
    250 			if (t > 0)
    251 				mblklen = t;
    252 		} else {
    253 			frmblks = mb->nxt;
    254 		}
    255 		mb->ffree = mb->blk;
    256 		mb->nfree = mb->size;
    257 		mb->nxt = *mbp;
    258 		*mbp = mb;
    259 	}
    260 	p = mb->ffree;
    261 	mb->ffree = (char *)mb->ffree + s;
    262 	mb->nfree -= s;
    263 #ifdef BLKDEBUG
    264 	(void)memset(p, 0, s);
    265 #endif
    266 	return p;
    267 }
    268 
    269 /*
    270  * Move all blocks from list *fmbp to free list. For each block, set all
    271  * used memory to zero.
    272  */
    273 static void
    274 xfreeblk(mbl_t **fmbp)
    275 {
    276 	mbl_t	*mb;
    277 
    278 	while ((mb = *fmbp) != NULL) {
    279 		*fmbp = mb->nxt;
    280 		mb->nxt = frmblks;
    281 		frmblks = mb;
    282 		(void)memset(mb->blk, ZERO, mb->size - mb->nfree);
    283 	}
    284 }
    285 
    286 void
    287 initmem(void)
    288 {
    289 	int	pgsz;
    290 
    291 	pgsz = getpagesize();
    292 	mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
    293 
    294 	mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
    295 }
    296 
    297 
    298 /*
    299  * Allocate memory associated with level l.
    300  */
    301 void *
    302 getlblk(size_t l, size_t s)
    303 {
    304 
    305 	while (l >= nmblks) {
    306 		mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
    307 		(void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
    308 		nmblks += ML_INC;
    309 	}
    310 	return xgetblk(&mblks[l], s);
    311 }
    312 
    313 void *
    314 getblk(size_t s)
    315 {
    316 
    317 	return getlblk(mblklev, s);
    318 }
    319 
    320 /*
    321  * Free all memory associated with level l.
    322  */
    323 void
    324 freelblk(int l)
    325 {
    326 
    327 	xfreeblk(&mblks[l]);
    328 }
    329 
    330 void
    331 freeblk(void)
    332 {
    333 
    334 	freelblk(mblklev);
    335 }
    336 
    337 /*
    338  * tgetblk() returns memory which is associated with the current
    339  * expression.
    340  */
    341 static	mbl_t	*tmblk;
    342 
    343 void *
    344 tgetblk(size_t s)
    345 {
    346 
    347 	return xgetblk(&tmblk, s);
    348 }
    349 
    350 /*
    351  * Get memory for a new tree node.
    352  */
    353 tnode_t *
    354 getnode(void)
    355 {
    356 
    357 	return tgetblk(sizeof (tnode_t));
    358 }
    359 
    360 /*
    361  * Free all memory which is allocated by the current expression.
    362  */
    363 void
    364 tfreeblk(void)
    365 {
    366 
    367 	xfreeblk(&tmblk);
    368 }
    369 
    370 /*
    371  * Save the memory which is used by the current expression. This memory
    372  * is not freed by the next tfreeblk() call. The pointer returned can be
    373  * used to restore the memory.
    374  */
    375 mbl_t *
    376 tsave(void)
    377 {
    378 	mbl_t	*tmem;
    379 
    380 	tmem = tmblk;
    381 	tmblk = NULL;
    382 	return tmem;
    383 }
    384 
    385 /*
    386  * Free all memory used for the current expression and the memory used
    387  * be a previous expression and saved by tsave(). The next call to
    388  * tfreeblk() frees the restored memory.
    389  */
    390 void
    391 trestor(mbl_t *tmem)
    392 {
    393 
    394 	tfreeblk();
    395 	if (tmblk != NULL) {
    396 		free(tmblk->blk);
    397 		free(tmblk);
    398 	}
    399 	tmblk = tmem;
    400 }
    401