Home | History | Annotate | Line # | Download | only in ksh
alloc.c revision 1.3.6.1
      1  1.3.6.1  wrstuden /*	$NetBSD: alloc.c,v 1.3.6.1 1999/12/27 18:27:01 wrstuden Exp $	*/
      2      1.2       tls 
      3      1.1       jtc /*
      4      1.1       jtc  * area-based allocation built on malloc/free
      5      1.1       jtc  */
      6      1.1       jtc 
      7      1.1       jtc #include "sh.h"
      8  1.3.6.1  wrstuden 
      9  1.3.6.1  wrstuden #ifdef TEST_ALLOC
     10  1.3.6.1  wrstuden # define shellf	printf
     11  1.3.6.1  wrstuden # ifndef DEBUG_ALLOC
     12  1.3.6.1  wrstuden #  define DEBUG_ALLOC
     13  1.3.6.1  wrstuden # endif /* DEBUG_ALLOC */
     14  1.3.6.1  wrstuden #endif /* TEST_ALLOC */
     15  1.3.6.1  wrstuden 
     16      1.1       jtc #ifdef MEM_DEBUG
     17      1.1       jtc 
     18  1.3.6.1  wrstuden /*
     19  1.3.6.1  wrstuden  * Special versions of alloc routines if doing mem_debug
     20  1.3.6.1  wrstuden  */
     21  1.3.6.1  wrstuden Area *
     22  1.3.6.1  wrstuden _chmem_ainit(ap, file, line)
     23  1.3.6.1  wrstuden 	Area *ap;
     24  1.3.6.1  wrstuden 	const char *file;
     25  1.3.6.1  wrstuden 	int line;
     26  1.3.6.1  wrstuden {
     27  1.3.6.1  wrstuden 	ap->freelist = (struct Block *) _chmem_newpool("ainit", (char *) 0, -1,
     28  1.3.6.1  wrstuden 						file, line);
     29  1.3.6.1  wrstuden 	if (!ap->freelist)
     30  1.3.6.1  wrstuden 	    aerror(ap, "ainit failed (ie, newpool)");
     31  1.3.6.1  wrstuden 	return ap;
     32  1.3.6.1  wrstuden }
     33  1.3.6.1  wrstuden 
     34  1.3.6.1  wrstuden /* free all object in Area */
     35  1.3.6.1  wrstuden void
     36  1.3.6.1  wrstuden _chmem_afreeall(ap, file, line)
     37  1.3.6.1  wrstuden 	Area *ap;
     38  1.3.6.1  wrstuden 	const char *file;
     39  1.3.6.1  wrstuden 	int line;
     40  1.3.6.1  wrstuden {
     41  1.3.6.1  wrstuden 	_chmem_delpool((Chmem_poolp) ap->freelist, 0, file, line);
     42  1.3.6.1  wrstuden 	/* Kind of ugly, but it works */
     43  1.3.6.1  wrstuden 	_chmem_ainit(ap, file, line);
     44  1.3.6.1  wrstuden }
     45  1.3.6.1  wrstuden 
     46  1.3.6.1  wrstuden /* allocate object from Area */
     47  1.3.6.1  wrstuden void *
     48  1.3.6.1  wrstuden _chmem_alloc(size, ap, file, line)
     49  1.3.6.1  wrstuden 	size_t size;
     50  1.3.6.1  wrstuden 	Area *ap;
     51  1.3.6.1  wrstuden 	const char *file;
     52  1.3.6.1  wrstuden 	int line;
     53  1.3.6.1  wrstuden {
     54  1.3.6.1  wrstuden 	return _chmem_mallocp((Chmem_poolp) ap->freelist, size, file, line);
     55  1.3.6.1  wrstuden }
     56  1.3.6.1  wrstuden 
     57  1.3.6.1  wrstuden /* change size of object -- like realloc */
     58  1.3.6.1  wrstuden void *
     59  1.3.6.1  wrstuden _chmem_aresize(ptr, size, ap, file, line)
     60  1.3.6.1  wrstuden 	void *ptr;
     61  1.3.6.1  wrstuden 	size_t size;
     62  1.3.6.1  wrstuden 	Area *ap;
     63  1.3.6.1  wrstuden 	const char *file;
     64  1.3.6.1  wrstuden 	int line;
     65  1.3.6.1  wrstuden {
     66  1.3.6.1  wrstuden 	if (!ptr)
     67  1.3.6.1  wrstuden 		/* Done as realloc(0, size) is not portable */
     68  1.3.6.1  wrstuden 		return _chmem_mallocp((Chmem_poolp) ap->freelist, size,
     69  1.3.6.1  wrstuden 					file, line);
     70  1.3.6.1  wrstuden 	else
     71  1.3.6.1  wrstuden 		return _chmem_reallocp((Chmem_poolp) ap->freelist, ptr, size,
     72  1.3.6.1  wrstuden 					file, line);
     73  1.3.6.1  wrstuden }
     74  1.3.6.1  wrstuden 
     75  1.3.6.1  wrstuden void
     76  1.3.6.1  wrstuden _chmem_afree(ptr, ap, file, line)
     77  1.3.6.1  wrstuden 	void *ptr;
     78  1.3.6.1  wrstuden 	Area *ap;
     79  1.3.6.1  wrstuden 	const char *file;
     80  1.3.6.1  wrstuden 	int line;
     81  1.3.6.1  wrstuden {
     82  1.3.6.1  wrstuden 	return _chmem_freep((Chmem_poolp) ap->freelist, ptr, file, line);
     83  1.3.6.1  wrstuden }
     84  1.3.6.1  wrstuden 
     85  1.3.6.1  wrstuden #else /* MEM_DEBUG */
     86  1.3.6.1  wrstuden 
     87  1.3.6.1  wrstuden # if DEBUG_ALLOC
     88  1.3.6.1  wrstuden void acheck ARGS((Area *ap));
     89  1.3.6.1  wrstuden #  define ACHECK(ap)	acheck(ap)
     90  1.3.6.1  wrstuden # else /* DEBUG_ALLOC */
     91  1.3.6.1  wrstuden #  define ACHECK(ap)
     92  1.3.6.1  wrstuden # endif /* DEBUG_ALLOC */
     93  1.3.6.1  wrstuden 
     94  1.3.6.1  wrstuden #define	ICELLS	200		/* number of Cells in small Block */
     95      1.1       jtc 
     96      1.1       jtc typedef union Cell Cell;
     97      1.1       jtc typedef struct Block Block;
     98      1.1       jtc 
     99      1.1       jtc /*
    100      1.1       jtc  * The Cells in a Block are organized as a set of objects.
    101  1.3.6.1  wrstuden  * Each object (pointed to by dp) begins with the block it is in
    102  1.3.6.1  wrstuden  * (dp-2)->block, then has a size in (dp-1)->size, which is
    103      1.1       jtc  * followed with "size" data Cells.  Free objects are
    104      1.1       jtc  * linked together via dp->next.
    105      1.1       jtc  */
    106      1.1       jtc 
    107  1.3.6.1  wrstuden #define NOBJECT_FIELDS	2	/* the block and size `fields' */
    108  1.3.6.1  wrstuden 
    109      1.1       jtc union Cell {
    110      1.1       jtc 	size_t	size;
    111      1.1       jtc 	Cell   *next;
    112  1.3.6.1  wrstuden 	Block  *block;
    113      1.1       jtc 	struct {int _;} junk;	/* alignment */
    114  1.3.6.1  wrstuden 	double djunk;		/* alignment */
    115      1.1       jtc };
    116      1.1       jtc 
    117      1.1       jtc struct Block {
    118      1.1       jtc 	Block  *next;		/* list of Blocks in Area */
    119  1.3.6.1  wrstuden 	Block  *prev;		/* previous block in list */
    120      1.1       jtc 	Cell   *freelist;	/* object free list */
    121      1.1       jtc 	Cell   *last;		/* &b.cell[size] */
    122      1.1       jtc 	Cell	cell [1];	/* [size] Cells for allocation */
    123      1.1       jtc };
    124      1.1       jtc 
    125  1.3.6.1  wrstuden static Block aempty = {&aempty, &aempty, aempty.cell, aempty.cell};
    126  1.3.6.1  wrstuden 
    127  1.3.6.1  wrstuden static void ablockfree ARGS((Block *bp, Area *ap));
    128  1.3.6.1  wrstuden static void *asplit ARGS((Area *ap, Block *bp, Cell *fp, Cell *fpp, int cells));
    129      1.1       jtc 
    130      1.1       jtc /* create empty Area */
    131      1.1       jtc Area *
    132      1.1       jtc ainit(ap)
    133      1.1       jtc 	register Area *ap;
    134      1.1       jtc {
    135      1.1       jtc 	ap->freelist = &aempty;
    136  1.3.6.1  wrstuden 	ACHECK(ap);
    137      1.1       jtc 	return ap;
    138      1.1       jtc }
    139      1.1       jtc 
    140      1.1       jtc /* free all object in Area */
    141      1.1       jtc void
    142      1.1       jtc afreeall(ap)
    143      1.1       jtc 	register Area *ap;
    144      1.1       jtc {
    145      1.1       jtc 	register Block *bp;
    146      1.1       jtc 	register Block *tmp;
    147      1.1       jtc 
    148  1.3.6.1  wrstuden 	ACHECK(ap);
    149      1.1       jtc 	bp = ap->freelist;
    150      1.1       jtc 	if (bp != NULL && bp != &aempty) {
    151      1.1       jtc 		do {
    152  1.3.6.1  wrstuden 			tmp = bp;
    153  1.3.6.1  wrstuden 			bp = bp->next;
    154  1.3.6.1  wrstuden 			free((void*)tmp);
    155      1.1       jtc 		} while (bp != ap->freelist);
    156      1.1       jtc 		ap->freelist = &aempty;
    157      1.1       jtc 	}
    158  1.3.6.1  wrstuden 	ACHECK(ap);
    159      1.1       jtc }
    160      1.1       jtc 
    161      1.1       jtc /* allocate object from Area */
    162      1.1       jtc void *
    163      1.1       jtc alloc(size, ap)
    164      1.1       jtc 	size_t size;
    165      1.1       jtc 	register Area *ap;
    166      1.1       jtc {
    167  1.3.6.1  wrstuden 	int cells, acells;
    168  1.3.6.1  wrstuden 	Block *bp = 0;
    169  1.3.6.1  wrstuden 	Cell *fp = 0, *fpp = 0;
    170      1.1       jtc 
    171  1.3.6.1  wrstuden 	ACHECK(ap);
    172  1.3.6.1  wrstuden 	if (size <= 0)
    173      1.1       jtc 		aerror(ap, "allocate bad size");
    174  1.3.6.1  wrstuden 	cells = (unsigned)(size + sizeof(Cell) - 1) / sizeof(Cell);
    175      1.1       jtc 
    176  1.3.6.1  wrstuden 	/* allocate at least this many cells */
    177  1.3.6.1  wrstuden 	acells = cells + NOBJECT_FIELDS;
    178  1.3.6.1  wrstuden 
    179  1.3.6.1  wrstuden 	/*
    180  1.3.6.1  wrstuden 	 * Only attempt to track small objects - let malloc deal
    181  1.3.6.1  wrstuden 	 * with larger objects. (this way we don't have to deal with
    182  1.3.6.1  wrstuden 	 * coalescing memory, or with releasing it to the system)
    183  1.3.6.1  wrstuden 	 */
    184  1.3.6.1  wrstuden 	if (cells <= ICELLS) {
    185  1.3.6.1  wrstuden 		/* find free Cell large enough */
    186  1.3.6.1  wrstuden 		for (bp = ap->freelist; ; bp = bp->next) {
    187  1.3.6.1  wrstuden 			for (fpp = NULL, fp = bp->freelist;
    188  1.3.6.1  wrstuden 			     fp != bp->last; fpp = fp, fp = fp->next)
    189  1.3.6.1  wrstuden 			{
    190  1.3.6.1  wrstuden 				if ((fp-1)->size >= cells)
    191  1.3.6.1  wrstuden 					goto Found;
    192      1.1       jtc 			}
    193  1.3.6.1  wrstuden 			/* wrapped around Block list, create new Block */
    194  1.3.6.1  wrstuden 			if (bp->next == ap->freelist) {
    195  1.3.6.1  wrstuden 				bp = 0;
    196  1.3.6.1  wrstuden 				break;
    197      1.1       jtc 			}
    198      1.1       jtc 		}
    199  1.3.6.1  wrstuden 		/* Not much free space left?  Allocate a big object this time */
    200  1.3.6.1  wrstuden 		acells += ICELLS;
    201  1.3.6.1  wrstuden 	}
    202  1.3.6.1  wrstuden 	if (bp == 0) {
    203  1.3.6.1  wrstuden 		bp = (Block*) malloc(offsetof(Block, cell[acells]));
    204  1.3.6.1  wrstuden 		if (bp == NULL)
    205  1.3.6.1  wrstuden 			aerror(ap, "cannot allocate");
    206  1.3.6.1  wrstuden 		if (ap->freelist == &aempty) {
    207  1.3.6.1  wrstuden 			ap->freelist = bp->next = bp->prev = bp;
    208  1.3.6.1  wrstuden 		} else {
    209  1.3.6.1  wrstuden 			bp->next = ap->freelist->next;
    210  1.3.6.1  wrstuden 			ap->freelist->next->prev = bp;
    211  1.3.6.1  wrstuden 			ap->freelist->next = bp;
    212  1.3.6.1  wrstuden 			bp->prev = ap->freelist;
    213  1.3.6.1  wrstuden 		}
    214  1.3.6.1  wrstuden 		bp->last = bp->cell + acells;
    215  1.3.6.1  wrstuden 		/* initial free list */
    216  1.3.6.1  wrstuden 		fp = bp->freelist = bp->cell + NOBJECT_FIELDS;
    217  1.3.6.1  wrstuden 		(fp-1)->size = acells - NOBJECT_FIELDS;
    218  1.3.6.1  wrstuden 		(fp-2)->block = bp;
    219  1.3.6.1  wrstuden 		fp->next = bp->last;
    220  1.3.6.1  wrstuden 		fpp = NULL;
    221      1.1       jtc 	}
    222  1.3.6.1  wrstuden 
    223      1.1       jtc   Found:
    224  1.3.6.1  wrstuden 	return asplit(ap, bp, fp, fpp, cells);
    225  1.3.6.1  wrstuden }
    226  1.3.6.1  wrstuden 
    227  1.3.6.1  wrstuden /* Do the work of splitting an object into allocated and (possibly) unallocated
    228  1.3.6.1  wrstuden  * objects.  Returns the `allocated' object.
    229  1.3.6.1  wrstuden  */
    230  1.3.6.1  wrstuden static void *
    231  1.3.6.1  wrstuden asplit(ap, bp, fp, fpp, cells)
    232  1.3.6.1  wrstuden 	Area *ap;
    233  1.3.6.1  wrstuden 	Block *bp;
    234  1.3.6.1  wrstuden 	Cell *fp;
    235  1.3.6.1  wrstuden 	Cell *fpp;
    236  1.3.6.1  wrstuden 	int cells;
    237  1.3.6.1  wrstuden {
    238  1.3.6.1  wrstuden 	Cell *dp = fp;	/* allocated object */
    239  1.3.6.1  wrstuden 	int split = (fp-1)->size - cells;
    240  1.3.6.1  wrstuden 
    241  1.3.6.1  wrstuden 	ACHECK(ap);
    242      1.1       jtc 	if (split < 0)
    243      1.1       jtc 		aerror(ap, "allocated object too small");
    244  1.3.6.1  wrstuden 	if (split <= NOBJECT_FIELDS) {	/* allocate all */
    245      1.1       jtc 		fp = fp->next;
    246      1.1       jtc 	} else {		/* allocate head, free tail */
    247  1.3.6.1  wrstuden 		Cell *next = fp->next; /* needed, as cells may be 0 */
    248  1.3.6.1  wrstuden 		ap->freelist = bp; /* next time, start looking for space here */
    249      1.1       jtc 		(fp-1)->size = cells;
    250  1.3.6.1  wrstuden 		fp += cells + NOBJECT_FIELDS;
    251  1.3.6.1  wrstuden 		(fp-1)->size = split - NOBJECT_FIELDS;
    252  1.3.6.1  wrstuden 		(fp-2)->block = bp;
    253  1.3.6.1  wrstuden 		fp->next = next;
    254      1.1       jtc 	}
    255      1.1       jtc 	if (fpp == NULL)
    256      1.1       jtc 		bp->freelist = fp;
    257      1.1       jtc 	else
    258      1.1       jtc 		fpp->next = fp;
    259  1.3.6.1  wrstuden 	ACHECK(ap);
    260      1.1       jtc 	return (void*) dp;
    261      1.1       jtc }
    262      1.1       jtc 
    263      1.1       jtc /* change size of object -- like realloc */
    264      1.1       jtc void *
    265      1.1       jtc aresize(ptr, size, ap)
    266      1.1       jtc 	register void *ptr;
    267      1.1       jtc 	size_t size;
    268      1.1       jtc 	Area *ap;
    269      1.1       jtc {
    270      1.1       jtc 	int cells;
    271  1.3.6.1  wrstuden 	Cell *dp = (Cell*) ptr;
    272  1.3.6.1  wrstuden 	int oldcells = dp ? (dp-1)->size : 0;
    273      1.1       jtc 
    274  1.3.6.1  wrstuden 	ACHECK(ap);
    275  1.3.6.1  wrstuden 	if (size <= 0)
    276      1.1       jtc 		aerror(ap, "allocate bad size");
    277  1.3.6.1  wrstuden 	/* New size (in cells) */
    278      1.1       jtc 	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
    279      1.1       jtc 
    280  1.3.6.1  wrstuden 	/* Is this a large object?  If so, let malloc deal with it
    281  1.3.6.1  wrstuden 	 * directly (unless we are crossing the ICELLS border, in
    282  1.3.6.1  wrstuden 	 * which case the alloc/free below handles it - this should
    283  1.3.6.1  wrstuden 	 * cut down on fragmentation, and will also keep the code
    284  1.3.6.1  wrstuden 	 * working (as it assumes size < ICELLS means it is not
    285  1.3.6.1  wrstuden 	 * a `large object').
    286  1.3.6.1  wrstuden 	 */
    287  1.3.6.1  wrstuden 	if (oldcells > ICELLS && cells > ICELLS) {
    288  1.3.6.1  wrstuden 		Block *bp = (dp-2)->block;
    289  1.3.6.1  wrstuden 		Block *nbp;
    290  1.3.6.1  wrstuden 		/* Saved in case realloc fails.. */
    291  1.3.6.1  wrstuden 		Block *next = bp->next, *prev = bp->prev;
    292  1.3.6.1  wrstuden 
    293  1.3.6.1  wrstuden 		if (bp->freelist != bp->last)
    294  1.3.6.1  wrstuden 			aerror(ap, "allocation resizing free pointer");
    295  1.3.6.1  wrstuden 		nbp = realloc((void *) bp,
    296  1.3.6.1  wrstuden 			      offsetof(Block, cell[cells + NOBJECT_FIELDS]));
    297  1.3.6.1  wrstuden 		if (!nbp) {
    298  1.3.6.1  wrstuden 			/* Have to clean up... */
    299  1.3.6.1  wrstuden 			/* NOTE: If this code changes, similar changes may be
    300  1.3.6.1  wrstuden 			 * needed in ablockfree().
    301  1.3.6.1  wrstuden 			 */
    302  1.3.6.1  wrstuden 			if (next == bp) /* only block */
    303  1.3.6.1  wrstuden 				ap->freelist = &aempty;
    304  1.3.6.1  wrstuden 			else {
    305  1.3.6.1  wrstuden 				next->prev = prev;
    306  1.3.6.1  wrstuden 				prev->next = next;
    307  1.3.6.1  wrstuden 				if (ap->freelist == bp)
    308  1.3.6.1  wrstuden 					ap->freelist = next;
    309  1.3.6.1  wrstuden 			}
    310  1.3.6.1  wrstuden 			aerror(ap, "cannot re-allocate");
    311  1.3.6.1  wrstuden 		}
    312  1.3.6.1  wrstuden 		/* If location changed, keep pointers straight... */
    313  1.3.6.1  wrstuden 		if (nbp != bp) {
    314  1.3.6.1  wrstuden 			if (next == bp) /* only one block */
    315  1.3.6.1  wrstuden 				nbp->next = nbp->prev = nbp;
    316  1.3.6.1  wrstuden 			else {
    317  1.3.6.1  wrstuden 				next->prev = nbp;
    318  1.3.6.1  wrstuden 				prev->next = nbp;
    319  1.3.6.1  wrstuden 			}
    320  1.3.6.1  wrstuden 			if (ap->freelist == bp)
    321  1.3.6.1  wrstuden 				ap->freelist = nbp;
    322  1.3.6.1  wrstuden 			dp = nbp->cell + NOBJECT_FIELDS;
    323  1.3.6.1  wrstuden 			(dp-2)->block = nbp;
    324      1.1       jtc 		}
    325  1.3.6.1  wrstuden 		(dp-1)->size = cells;
    326  1.3.6.1  wrstuden 		nbp->last = nbp->cell + cells + NOBJECT_FIELDS;
    327  1.3.6.1  wrstuden 		nbp->freelist = nbp->last;
    328  1.3.6.1  wrstuden 
    329  1.3.6.1  wrstuden 		ACHECK(ap);
    330  1.3.6.1  wrstuden 		return (void*) dp;
    331  1.3.6.1  wrstuden 	}
    332  1.3.6.1  wrstuden 
    333  1.3.6.1  wrstuden 	/* Check if we can just grow this cell
    334  1.3.6.1  wrstuden 	 * (need to check that cells < ICELLS so we don't make an
    335  1.3.6.1  wrstuden 	 * object a `large' - that would mess everything up).
    336  1.3.6.1  wrstuden 	 */
    337  1.3.6.1  wrstuden 	if (dp && cells > oldcells && cells <= ICELLS) {
    338  1.3.6.1  wrstuden 		Cell *fp, *fpp;
    339  1.3.6.1  wrstuden 		Block *bp = (dp-2)->block;
    340  1.3.6.1  wrstuden 		int need = cells - oldcells - NOBJECT_FIELDS;
    341  1.3.6.1  wrstuden 
    342  1.3.6.1  wrstuden 		/* XXX if we had a flag in an object indicating
    343  1.3.6.1  wrstuden 		 * if the object was free/allocated, we could
    344  1.3.6.1  wrstuden 		 * avoid this loop (perhaps)
    345  1.3.6.1  wrstuden 		 */
    346  1.3.6.1  wrstuden 		for (fpp = NULL, fp = bp->freelist;
    347  1.3.6.1  wrstuden 		     fp != bp->last
    348  1.3.6.1  wrstuden 		     && dp + oldcells + NOBJECT_FIELDS <= fp
    349  1.3.6.1  wrstuden 		     ; fpp = fp, fp = fp->next)
    350  1.3.6.1  wrstuden 		{
    351  1.3.6.1  wrstuden 			if (dp + oldcells + NOBJECT_FIELDS == fp
    352  1.3.6.1  wrstuden 			    && (fp-1)->size >= need)
    353  1.3.6.1  wrstuden 			{
    354  1.3.6.1  wrstuden 				Cell *np = asplit(ap, bp, fp, fpp, need);
    355  1.3.6.1  wrstuden 				/* May get more than we need here */
    356  1.3.6.1  wrstuden 				(dp-1)->size += (np-1)->size + NOBJECT_FIELDS;
    357  1.3.6.1  wrstuden 				ACHECK(ap);
    358  1.3.6.1  wrstuden 				return ptr;
    359  1.3.6.1  wrstuden 			}
    360  1.3.6.1  wrstuden 		}
    361  1.3.6.1  wrstuden 	}
    362  1.3.6.1  wrstuden 
    363  1.3.6.1  wrstuden 	/* Check if we can just shrink this cell
    364  1.3.6.1  wrstuden 	 * (if oldcells > ICELLS, this is a large object and we leave
    365  1.3.6.1  wrstuden 	 * it to malloc...)
    366  1.3.6.1  wrstuden 	 * Note: this also handles cells == oldcells (a no-op).
    367  1.3.6.1  wrstuden 	 */
    368  1.3.6.1  wrstuden 	if (dp && cells <= oldcells && oldcells <= ICELLS) {
    369      1.1       jtc 		int split;
    370      1.1       jtc 
    371  1.3.6.1  wrstuden 		split = oldcells - cells;
    372  1.3.6.1  wrstuden 		if (split <= NOBJECT_FIELDS) /* cannot split */
    373      1.1       jtc 			;
    374      1.1       jtc 		else {		/* shrink head, free tail */
    375  1.3.6.1  wrstuden 			Block *bp = (dp-2)->block;
    376  1.3.6.1  wrstuden 
    377      1.1       jtc 			(dp-1)->size = cells;
    378  1.3.6.1  wrstuden 			dp += cells + NOBJECT_FIELDS;
    379  1.3.6.1  wrstuden 			(dp-1)->size = split - NOBJECT_FIELDS;
    380  1.3.6.1  wrstuden 			(dp-2)->block = bp;
    381      1.1       jtc 			afree((void*)dp, ap);
    382      1.1       jtc 		}
    383  1.3.6.1  wrstuden 		/* ACHECK() done in afree() */
    384  1.3.6.1  wrstuden 		return ptr;
    385      1.1       jtc 	}
    386  1.3.6.1  wrstuden 
    387  1.3.6.1  wrstuden 	/* Have to do it the hard way... */
    388  1.3.6.1  wrstuden 	ptr = alloc(size, ap);
    389  1.3.6.1  wrstuden 	if (dp != NULL) {
    390  1.3.6.1  wrstuden 		size_t s = (dp-1)->size * sizeof(Cell);
    391  1.3.6.1  wrstuden 		if (s > size)
    392  1.3.6.1  wrstuden 			s = size;
    393  1.3.6.1  wrstuden 		memcpy(ptr, dp, s);
    394  1.3.6.1  wrstuden 		afree((void *) dp, ap);
    395  1.3.6.1  wrstuden 	}
    396  1.3.6.1  wrstuden 	/* ACHECK() done in alloc()/afree() */
    397  1.3.6.1  wrstuden 	return ptr;
    398      1.1       jtc }
    399      1.1       jtc 
    400      1.1       jtc void
    401      1.1       jtc afree(ptr, ap)
    402      1.1       jtc 	void *ptr;
    403      1.1       jtc 	register Area *ap;
    404      1.1       jtc {
    405      1.1       jtc 	register Block *bp;
    406      1.1       jtc 	register Cell *fp, *fpp;
    407      1.1       jtc 	register Cell *dp = (Cell*)ptr;
    408      1.1       jtc 
    409  1.3.6.1  wrstuden 	ACHECK(ap);
    410  1.3.6.1  wrstuden 	if (ptr == 0)
    411  1.3.6.1  wrstuden 		aerror(ap, "freeing null pointer");
    412  1.3.6.1  wrstuden 	bp = (dp-2)->block;
    413  1.3.6.1  wrstuden 
    414  1.3.6.1  wrstuden 	/* If this is a large object, just free it up... */
    415  1.3.6.1  wrstuden 	/* Release object... */
    416  1.3.6.1  wrstuden 	if ((dp-1)->size > ICELLS) {
    417  1.3.6.1  wrstuden 		ablockfree(bp, ap);
    418  1.3.6.1  wrstuden 		ACHECK(ap);
    419  1.3.6.1  wrstuden 		return;
    420      1.1       jtc 	}
    421      1.1       jtc 
    422  1.3.6.1  wrstuden 	if (dp < &bp->cell[NOBJECT_FIELDS] || dp >= bp->last)
    423  1.3.6.1  wrstuden 		aerror(ap, "freeing memory outside of block (corrupted?)");
    424  1.3.6.1  wrstuden 
    425      1.1       jtc 	/* find position in free list */
    426  1.3.6.1  wrstuden 	/* XXX if we had prev/next pointers for objects, this loop could go */
    427  1.3.6.1  wrstuden 	for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fp->next)
    428      1.1       jtc 		;
    429      1.1       jtc 
    430  1.3.6.1  wrstuden 	if (fp == dp)
    431      1.1       jtc 		aerror(ap, "freeing free object");
    432      1.1       jtc 
    433      1.1       jtc 	/* join object with next */
    434  1.3.6.1  wrstuden 	if (dp + (dp-1)->size == fp-NOBJECT_FIELDS) { /* adjacent */
    435  1.3.6.1  wrstuden 		(dp-1)->size += (fp-1)->size + NOBJECT_FIELDS;
    436      1.1       jtc 		dp->next = fp->next;
    437      1.1       jtc 	} else			/* non-adjacent */
    438      1.1       jtc 		dp->next = fp;
    439      1.1       jtc 
    440      1.1       jtc 	/* join previous with object */
    441      1.1       jtc 	if (fpp == NULL)
    442      1.1       jtc 		bp->freelist = dp;
    443  1.3.6.1  wrstuden 	else if (fpp + (fpp-1)->size == dp-NOBJECT_FIELDS) { /* adjacent */
    444  1.3.6.1  wrstuden 		(fpp-1)->size += (dp-1)->size + NOBJECT_FIELDS;
    445      1.1       jtc 		fpp->next = dp->next;
    446      1.1       jtc 	} else			/* non-adjacent */
    447      1.1       jtc 		fpp->next = dp;
    448  1.3.6.1  wrstuden 
    449  1.3.6.1  wrstuden 	/* If whole block is free (and we have some other blocks
    450  1.3.6.1  wrstuden 	 * around), release this block back to the system...
    451  1.3.6.1  wrstuden 	 */
    452  1.3.6.1  wrstuden 	if (bp->next != bp && bp->freelist == bp->cell + NOBJECT_FIELDS
    453  1.3.6.1  wrstuden 	    && bp->freelist + (bp->freelist-1)->size == bp->last
    454  1.3.6.1  wrstuden 	    /* XXX and the other block has some free memory? */
    455  1.3.6.1  wrstuden 	    )
    456  1.3.6.1  wrstuden 		ablockfree(bp, ap);
    457  1.3.6.1  wrstuden 	ACHECK(ap);
    458  1.3.6.1  wrstuden }
    459  1.3.6.1  wrstuden 
    460  1.3.6.1  wrstuden static void
    461  1.3.6.1  wrstuden ablockfree(bp, ap)
    462  1.3.6.1  wrstuden 	Block *bp;
    463  1.3.6.1  wrstuden 	Area *ap;
    464  1.3.6.1  wrstuden {
    465  1.3.6.1  wrstuden 	/* NOTE: If this code changes, similar changes may be
    466  1.3.6.1  wrstuden 	 * needed in alloc() (where realloc fails).
    467  1.3.6.1  wrstuden 	 */
    468  1.3.6.1  wrstuden 
    469  1.3.6.1  wrstuden 	if (bp->next == bp) /* only block */
    470  1.3.6.1  wrstuden 		ap->freelist = &aempty;
    471  1.3.6.1  wrstuden 	else {
    472  1.3.6.1  wrstuden 		bp->next->prev = bp->prev;
    473  1.3.6.1  wrstuden 		bp->prev->next = bp->next;
    474  1.3.6.1  wrstuden 		if (ap->freelist == bp)
    475  1.3.6.1  wrstuden 			ap->freelist = bp->next;
    476  1.3.6.1  wrstuden 	}
    477  1.3.6.1  wrstuden 	free((void*) bp);
    478  1.3.6.1  wrstuden }
    479  1.3.6.1  wrstuden 
    480  1.3.6.1  wrstuden # if DEBUG_ALLOC
    481  1.3.6.1  wrstuden void
    482  1.3.6.1  wrstuden acheck(ap)
    483  1.3.6.1  wrstuden 	Area *ap;
    484  1.3.6.1  wrstuden {
    485  1.3.6.1  wrstuden 	Block *bp, *bpp;
    486  1.3.6.1  wrstuden 	Cell *dp, *dptmp, *fp;
    487  1.3.6.1  wrstuden 	int ok = 1;
    488  1.3.6.1  wrstuden 	int isfree;
    489  1.3.6.1  wrstuden 	static int disabled;
    490  1.3.6.1  wrstuden 
    491  1.3.6.1  wrstuden 	if (disabled)
    492  1.3.6.1  wrstuden 		return;
    493  1.3.6.1  wrstuden 
    494  1.3.6.1  wrstuden 	if (!ap) {
    495  1.3.6.1  wrstuden 		disabled = 1;
    496  1.3.6.1  wrstuden 		aerror(ap, "acheck: null area pointer");
    497  1.3.6.1  wrstuden 	}
    498  1.3.6.1  wrstuden 
    499  1.3.6.1  wrstuden 	bp = ap->freelist;
    500  1.3.6.1  wrstuden 	if (!bp) {
    501  1.3.6.1  wrstuden 		disabled = 1;
    502  1.3.6.1  wrstuden 		aerror(ap, "acheck: null area freelist");
    503  1.3.6.1  wrstuden 	}
    504  1.3.6.1  wrstuden 
    505  1.3.6.1  wrstuden 	/* Nothing to check... */
    506  1.3.6.1  wrstuden 	if (bp == &aempty)
    507  1.3.6.1  wrstuden 		return;
    508  1.3.6.1  wrstuden 
    509  1.3.6.1  wrstuden 	bpp = ap->freelist->prev;
    510  1.3.6.1  wrstuden 	while (1) {
    511  1.3.6.1  wrstuden 		if (bp->prev != bpp) {
    512  1.3.6.1  wrstuden 			shellf("acheck: bp->prev != previous\n");
    513  1.3.6.1  wrstuden 			ok = 0;
    514  1.3.6.1  wrstuden 		}
    515  1.3.6.1  wrstuden 		fp = bp->freelist;
    516  1.3.6.1  wrstuden 		for (dp = &bp->cell[NOBJECT_FIELDS]; dp != bp->last; ) {
    517  1.3.6.1  wrstuden 			if ((dp-2)->block != bp) {
    518  1.3.6.1  wrstuden 				shellf("acheck: fragment's block is wrong\n");
    519  1.3.6.1  wrstuden 				ok = 0;
    520  1.3.6.1  wrstuden 			}
    521  1.3.6.1  wrstuden 			isfree = dp == fp;
    522  1.3.6.1  wrstuden 			if ((dp-1)->size == 0 && isfree) {
    523  1.3.6.1  wrstuden 				shellf("acheck: 0 size frag\n");
    524  1.3.6.1  wrstuden 				ok = 0;
    525  1.3.6.1  wrstuden 			}
    526  1.3.6.1  wrstuden 			if ((dp-1)->size > ICELLS
    527  1.3.6.1  wrstuden 			    && !isfree
    528  1.3.6.1  wrstuden 			    && (dp != &bp->cell[NOBJECT_FIELDS]
    529  1.3.6.1  wrstuden 				|| dp + (dp-1)->size != bp->last))
    530  1.3.6.1  wrstuden 			{
    531  1.3.6.1  wrstuden 				shellf("acheck: big cell doesn't make up whole block\n");
    532  1.3.6.1  wrstuden 				ok = 0;
    533  1.3.6.1  wrstuden 			}
    534  1.3.6.1  wrstuden 			if (isfree) {
    535  1.3.6.1  wrstuden 				if (dp->next <= dp) {
    536  1.3.6.1  wrstuden 					shellf("acheck: free fragment's next <= self\n");
    537  1.3.6.1  wrstuden 					ok = 0;
    538  1.3.6.1  wrstuden 				}
    539  1.3.6.1  wrstuden 				if (dp->next > bp->last) {
    540  1.3.6.1  wrstuden 					shellf("acheck: free fragment's next > last\n");
    541  1.3.6.1  wrstuden 					ok = 0;
    542  1.3.6.1  wrstuden 				}
    543  1.3.6.1  wrstuden 				fp = dp->next;
    544  1.3.6.1  wrstuden 			}
    545  1.3.6.1  wrstuden 			dptmp = dp + (dp-1)->size;
    546  1.3.6.1  wrstuden 			if (dptmp > bp->last) {
    547  1.3.6.1  wrstuden 				shellf("acheck: next frag out of range\n");
    548  1.3.6.1  wrstuden 				ok = 0;
    549  1.3.6.1  wrstuden 				break;
    550  1.3.6.1  wrstuden 			} else if (dptmp != bp->last) {
    551  1.3.6.1  wrstuden 				dptmp += NOBJECT_FIELDS;
    552  1.3.6.1  wrstuden 				if (dptmp > bp->last) {
    553  1.3.6.1  wrstuden 					shellf("acheck: next frag just out of range\n");
    554  1.3.6.1  wrstuden 					ok = 0;
    555  1.3.6.1  wrstuden 					break;
    556  1.3.6.1  wrstuden 				}
    557  1.3.6.1  wrstuden 			}
    558  1.3.6.1  wrstuden 			if (isfree && dptmp == fp && dptmp != bp->last) {
    559  1.3.6.1  wrstuden 				shellf("acheck: adjacent free frags\n");
    560  1.3.6.1  wrstuden 				ok = 0;
    561  1.3.6.1  wrstuden 			} else if (dptmp > fp) {
    562  1.3.6.1  wrstuden 				shellf("acheck: free frag list messed up\n");
    563  1.3.6.1  wrstuden 				ok = 0;
    564  1.3.6.1  wrstuden 			}
    565  1.3.6.1  wrstuden 			dp = dptmp;
    566  1.3.6.1  wrstuden 		}
    567  1.3.6.1  wrstuden 		bpp = bp;
    568  1.3.6.1  wrstuden 		bp = bp->next;
    569  1.3.6.1  wrstuden 		if (bp == ap->freelist)
    570  1.3.6.1  wrstuden 			break;
    571  1.3.6.1  wrstuden 	}
    572  1.3.6.1  wrstuden 	if (!ok) {
    573  1.3.6.1  wrstuden 		disabled = 1;
    574  1.3.6.1  wrstuden 		aerror(ap, "acheck failed");
    575  1.3.6.1  wrstuden 	}
    576      1.1       jtc }
    577      1.1       jtc 
    578      1.1       jtc void
    579      1.1       jtc aprint(ap, ptr, size)
    580      1.1       jtc 	register Area *ap;
    581      1.1       jtc 	void *ptr;
    582      1.1       jtc 	size_t size;
    583      1.1       jtc {
    584      1.1       jtc 	Block *bp;
    585      1.1       jtc 
    586      1.1       jtc 	if (!ap)
    587      1.1       jtc 		shellf("aprint: null area pointer\n");
    588      1.1       jtc 	else if (!(bp = ap->freelist))
    589      1.1       jtc 		shellf("aprint: null area freelist\n");
    590      1.1       jtc 	else if (bp == &aempty)
    591      1.1       jtc 		shellf("aprint: area is empty\n");
    592      1.1       jtc 	else {
    593      1.1       jtc 		int i;
    594  1.3.6.1  wrstuden 		Cell *dp, *fp;
    595  1.3.6.1  wrstuden 		Block *bpp;
    596      1.1       jtc 
    597  1.3.6.1  wrstuden 		bpp = ap->freelist->prev;
    598  1.3.6.1  wrstuden 		for (i = 0; ; i++) {
    599      1.1       jtc 			if (ptr) {
    600      1.1       jtc 				void *eptr = (void *) (((char *) ptr) + size);
    601      1.1       jtc 				/* print block only if it overlaps ptr/size */
    602      1.1       jtc 				if (!((ptr >= (void *) bp
    603      1.1       jtc 				       && ptr <= (void *) bp->last)
    604      1.1       jtc 				      || (eptr >= (void *) bp
    605      1.1       jtc 				         && eptr <= (void *) bp->last)))
    606      1.1       jtc 					continue;
    607      1.1       jtc 				shellf("aprint: overlap of 0x%p .. 0x%p\n",
    608      1.1       jtc 					ptr, eptr);
    609      1.1       jtc 			}
    610  1.3.6.1  wrstuden 			if (bp->prev != bpp || bp->next->prev != bp)
    611  1.3.6.1  wrstuden 				shellf(
    612  1.3.6.1  wrstuden 	"aprint: BAD prev pointer: bp %p, bp->prev %p, bp->next %p, bpp=%p\n",
    613  1.3.6.1  wrstuden 					bp, bp->prev, bp->next, bpp);
    614  1.3.6.1  wrstuden 			shellf("aprint: block %2d (p=%p,%p,n=%p): 0x%p .. 0x%p (%ld)\n", i,
    615  1.3.6.1  wrstuden 				bp->prev, bp, bp->next,
    616      1.1       jtc 				bp->cell, bp->last,
    617  1.3.6.1  wrstuden 				(long) ((char *) bp->last - (char *) bp->cell));
    618  1.3.6.1  wrstuden 			fp = bp->freelist;
    619  1.3.6.1  wrstuden 			if (bp->last <= bp->cell + NOBJECT_FIELDS)
    620      1.1       jtc 				shellf(
    621  1.3.6.1  wrstuden 			"aprint: BAD bp->last too small: %p <= %p\n",
    622  1.3.6.1  wrstuden 					bp->last, bp->cell + NOBJECT_FIELDS);
    623  1.3.6.1  wrstuden 			if (bp->freelist < bp->cell + NOBJECT_FIELDS
    624  1.3.6.1  wrstuden 			    || bp->freelist > bp->last)
    625  1.3.6.1  wrstuden 				shellf(
    626  1.3.6.1  wrstuden 			"aprint: BAD bp->freelist %p out of range: %p .. %p\n",
    627  1.3.6.1  wrstuden 					bp->freelist,
    628  1.3.6.1  wrstuden 					bp->cell + NOBJECT_FIELDS, bp->last);
    629  1.3.6.1  wrstuden 			for (dp = bp->cell; dp != bp->last ; ) {
    630  1.3.6.1  wrstuden 				dp += NOBJECT_FIELDS;
    631  1.3.6.1  wrstuden 				shellf(
    632  1.3.6.1  wrstuden 				    "aprint:   0x%p .. 0x%p (%ld) %s\n",
    633  1.3.6.1  wrstuden 					(dp-NOBJECT_FIELDS),
    634  1.3.6.1  wrstuden 					(dp-NOBJECT_FIELDS) + (dp-1)->size
    635  1.3.6.1  wrstuden 						+ NOBJECT_FIELDS,
    636  1.3.6.1  wrstuden 					(long) ((dp-1)->size + NOBJECT_FIELDS)
    637  1.3.6.1  wrstuden 						* sizeof(Cell),
    638  1.3.6.1  wrstuden 					dp == fp ? "free" : "allocated");
    639  1.3.6.1  wrstuden 				if ((dp-2)->block != bp)
    640  1.3.6.1  wrstuden 					shellf(
    641  1.3.6.1  wrstuden 					"aprint: BAD dp->block %p != bp %p\n",
    642  1.3.6.1  wrstuden 						(dp-2)->block, bp);
    643  1.3.6.1  wrstuden 				if (dp > bp->last)
    644  1.3.6.1  wrstuden 					shellf(
    645  1.3.6.1  wrstuden 				"aprint: BAD dp gone past block: %p > %p\n",
    646  1.3.6.1  wrstuden 						dp, bp->last);
    647  1.3.6.1  wrstuden 				if (dp > fp)
    648  1.3.6.1  wrstuden 					shellf(
    649  1.3.6.1  wrstuden 				"aprint: BAD dp gone past free: %p > %p\n",
    650  1.3.6.1  wrstuden 						dp, fp);
    651  1.3.6.1  wrstuden 				if (dp == fp) {
    652  1.3.6.1  wrstuden 					fp = fp->next;
    653  1.3.6.1  wrstuden 					if (fp < dp || fp > bp->last)
    654  1.3.6.1  wrstuden 						shellf(
    655  1.3.6.1  wrstuden 			"aprint: BAD free object %p out of range: %p .. %p\n",
    656  1.3.6.1  wrstuden 							fp,
    657  1.3.6.1  wrstuden 							dp, bp->last);
    658  1.3.6.1  wrstuden 				}
    659  1.3.6.1  wrstuden 				dp += (dp-1)->size;
    660  1.3.6.1  wrstuden 			}
    661  1.3.6.1  wrstuden 			bpp = bp;
    662  1.3.6.1  wrstuden 			bp = bp->next;
    663  1.3.6.1  wrstuden 			if (bp == ap->freelist)
    664  1.3.6.1  wrstuden 				break;
    665      1.1       jtc 		}
    666      1.1       jtc 	}
    667      1.1       jtc }
    668  1.3.6.1  wrstuden # endif /* DEBUG_ALLOC */
    669      1.1       jtc 
    670  1.3.6.1  wrstuden # ifdef TEST_ALLOC
    671      1.1       jtc 
    672      1.1       jtc Area a;
    673  1.3.6.1  wrstuden FILE *myout;
    674      1.1       jtc 
    675  1.3.6.1  wrstuden int
    676  1.3.6.1  wrstuden main(int argc, char **argv)
    677  1.3.6.1  wrstuden {
    678  1.3.6.1  wrstuden 	char buf[1024];
    679  1.3.6.1  wrstuden 	struct info {
    680  1.3.6.1  wrstuden 		int size;
    681  1.3.6.1  wrstuden 		void *value;
    682  1.3.6.1  wrstuden 	};
    683  1.3.6.1  wrstuden 	struct info info[1024 * 2];
    684  1.3.6.1  wrstuden 	int size, ident;
    685  1.3.6.1  wrstuden 	int lineno = 0;
    686      1.1       jtc 
    687  1.3.6.1  wrstuden 	myout = stdout;
    688      1.1       jtc 	ainit(&a);
    689  1.3.6.1  wrstuden 	while (fgets(buf, sizeof(buf), stdin)) {
    690  1.3.6.1  wrstuden 		lineno++;
    691  1.3.6.1  wrstuden 		if (buf[0] == '\n' || buf[0] == '#')
    692  1.3.6.1  wrstuden 			continue;
    693  1.3.6.1  wrstuden 		if (sscanf(buf, " alloc %d = i%d", &size, &ident) == 2) {
    694  1.3.6.1  wrstuden 			if (ident < 0 || ident > NELEM(info)) {
    695  1.3.6.1  wrstuden 				fprintf(stderr, "bad ident (%d) on line %d\n",
    696  1.3.6.1  wrstuden 					ident, lineno);
    697  1.3.6.1  wrstuden 				exit(1);
    698  1.3.6.1  wrstuden 			}
    699  1.3.6.1  wrstuden 			info[ident].value = alloc(info[ident].size = size, &a);
    700  1.3.6.1  wrstuden 			printf("%p = alloc(%d) [%d,i%d]\n",
    701  1.3.6.1  wrstuden 				info[ident].value, info[ident].size,
    702  1.3.6.1  wrstuden 				lineno, ident);
    703  1.3.6.1  wrstuden 			memset(info[ident].value, 1, size);
    704  1.3.6.1  wrstuden 			continue;
    705  1.3.6.1  wrstuden 		}
    706  1.3.6.1  wrstuden 		if (sscanf(buf, " afree i%d", &ident) == 1) {
    707  1.3.6.1  wrstuden 			if (ident < 0 || ident > NELEM(info)) {
    708  1.3.6.1  wrstuden 				fprintf(stderr, "bad ident (%d) on line %d\n",
    709  1.3.6.1  wrstuden 					ident, lineno);
    710  1.3.6.1  wrstuden 				exit(1);
    711  1.3.6.1  wrstuden 			}
    712  1.3.6.1  wrstuden 			afree(info[ident].value, &a);
    713  1.3.6.1  wrstuden 			printf("afree(%p) [%d,i%d]\n", info[ident].value,
    714  1.3.6.1  wrstuden 				lineno, ident);
    715  1.3.6.1  wrstuden 			continue;
    716  1.3.6.1  wrstuden 		}
    717  1.3.6.1  wrstuden 		if (sscanf(buf, " aresize i%d , %d", &ident, &size) == 2) {
    718  1.3.6.1  wrstuden 			void *value;
    719  1.3.6.1  wrstuden 			if (ident < 0 || ident > NELEM(info)) {
    720  1.3.6.1  wrstuden 				fprintf(stderr, "bad ident (%d) on line %d\n",
    721  1.3.6.1  wrstuden 					ident, lineno);
    722  1.3.6.1  wrstuden 				exit(1);
    723  1.3.6.1  wrstuden 			}
    724  1.3.6.1  wrstuden 			value = info[ident].value;
    725  1.3.6.1  wrstuden 			info[ident].value = aresize(value,
    726  1.3.6.1  wrstuden 						    info[ident].size = size,
    727  1.3.6.1  wrstuden 						    &a);
    728  1.3.6.1  wrstuden 			printf("%p = aresize(%p, %d) [%d,i%d]\n",
    729  1.3.6.1  wrstuden 				info[ident].value, value, info[ident].size,
    730  1.3.6.1  wrstuden 				lineno, ident);
    731  1.3.6.1  wrstuden 			memset(info[ident].value, 1, size);
    732  1.3.6.1  wrstuden 			continue;
    733  1.3.6.1  wrstuden 		}
    734  1.3.6.1  wrstuden 		if (sscanf(buf, " aprint i%d , %d", &ident, &size) == 2) {
    735  1.3.6.1  wrstuden 			if (ident < 0 || ident > NELEM(info)) {
    736  1.3.6.1  wrstuden 				fprintf(stderr, "bad ident (%d) on line %d\n",
    737  1.3.6.1  wrstuden 					ident, lineno);
    738  1.3.6.1  wrstuden 				exit(1);
    739  1.3.6.1  wrstuden 			}
    740  1.3.6.1  wrstuden 			printf("aprint(%p, %d) [%d,i%d]\n",
    741  1.3.6.1  wrstuden 				info[ident].value, size, lineno, ident);
    742  1.3.6.1  wrstuden 			aprint(&a, info[ident].value, size);
    743  1.3.6.1  wrstuden 			continue;
    744  1.3.6.1  wrstuden 		}
    745  1.3.6.1  wrstuden 		if (sscanf(buf, " aprint %d", &ident) == 1) {
    746  1.3.6.1  wrstuden 			if (ident < 0 || ident > NELEM(info)) {
    747  1.3.6.1  wrstuden 				fprintf(stderr, "bad ident (%d) on line %d\n",
    748  1.3.6.1  wrstuden 					ident, lineno);
    749  1.3.6.1  wrstuden 				exit(1);
    750  1.3.6.1  wrstuden 			}
    751  1.3.6.1  wrstuden 			printf("aprint(0, 0) [%d]\n", lineno);
    752  1.3.6.1  wrstuden 			aprint(&a, 0, 0);
    753  1.3.6.1  wrstuden 			continue;
    754  1.3.6.1  wrstuden 		}
    755  1.3.6.1  wrstuden 		if (sscanf(buf, " afreeall %d", &ident) == 1) {
    756  1.3.6.1  wrstuden 			printf("afreeall() [%d]\n", lineno);
    757  1.3.6.1  wrstuden 			afreeall(&a);
    758  1.3.6.1  wrstuden 			memset(info, 0, sizeof(info));
    759  1.3.6.1  wrstuden 			continue;
    760  1.3.6.1  wrstuden 		}
    761  1.3.6.1  wrstuden 		fprintf(stderr, "unrecognized line (line %d)\n",
    762  1.3.6.1  wrstuden 			lineno);
    763  1.3.6.1  wrstuden 		exit(1);
    764  1.3.6.1  wrstuden 	}
    765      1.1       jtc 	return 0;
    766      1.1       jtc }
    767      1.1       jtc 
    768  1.3.6.1  wrstuden void
    769  1.3.6.1  wrstuden aerror(Area *ap, const char *msg)
    770  1.3.6.1  wrstuden {
    771  1.3.6.1  wrstuden 	printf("aerror: %s\n", msg);
    772  1.3.6.1  wrstuden 	fflush(stdout);
    773      1.1       jtc 	abort();
    774      1.1       jtc }
    775      1.1       jtc 
    776  1.3.6.1  wrstuden # endif /* TEST_ALLOC */
    777      1.1       jtc 
    778  1.3.6.1  wrstuden #endif /* MEM_DEBUG */
    779