Home | History | Annotate | Line # | Download | only in lint1
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