home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d3xx
/
d352
/
mg.lha
/
MG
/
src.LZH
/
mg
/
alloca.c
next >
Wrap
C/C++ Source or Header
|
1990-05-23
|
5KB
|
165 lines
/*
* Note to mg porters: this is included on the off chance you don't have an
* alloca, and want to use the regexp code. I seriously recommend not using
* it if you can avoid it.
*/
/*
* alloca -- (mostly) portable public-domain implementation -- D A Gwyn
*
* This implementation of the PWB library alloca() function, which is used to
* allocate space off the run-time stack so that it is automatically
* reclaimed upon procedure exit, was inspired by discussions with J. Q.
* Johnson of Cornell.
*
* It should work under any C implementation that uses an actual procedure stack
* (as opposed to a linked list of frames). There are some preprocessor
* constants that can be defined when compiling for your specific system, for
* improved efficiency; however, the defaults should be okay.
*
* The general concept of this implementation is to keep track of all
* alloca()-allocated blocks, and reclaim any that are found to be deeper in
* the stack than the current invocation. This heuristic does not reclaim
* storage as soon as it becomes invalid, but it will do so eventually.
*
* As a special case, alloca(0) reclaims storage without allocating any. It is
* a good idea to use alloca(0) in your main control loop, etc. to force
* garbage collection.
*/
#include "regexp.h"
#ifdef REGEXP
#include "def.h" /* Get me lotsa defines */
#ifdef ANSI
#include <stdlib.h>
#endif
typedef VOID *pointer; /* generic pointer type */
/*
* Define STACK_DIRECTION if you know the direction of stack growth for your
* system; otherwise it will be automatically deduced at run-time.
*
* STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 =>
* grows toward lower addresses STACK_DIRECTION undefined => direction of
* growth unknown
*/
#ifdef STACK_DIRECTION
#define STACK_DIR STACK_DIRECTION /* known at compile-time */
#else /* STACK_DIRECTION undefined -> need to find
* it at compile time */
static int stack_dir; /* 1 or -1 once known */
#define STACK_DIR stack_dir
static VOID
find_stack_direction PROTO(( VOID ))
{
static char *addr = NULL; /* address of first `dummy', once
* known */
auto char dummy; /* to get stack address */
if (addr == NULL) { /* initial entry */
addr = &dummy;
find_stack_direction(); /* recurse once */
} else
/* second entry */ if (&dummy > addr)
stack_dir = 1; /* stack grew upward */
else
stack_dir = -1; /* stack grew downward */
}
#endif /* STACK_DIRECTION */
/*
* An "alloca header" is used to: (a) chain together all alloca()ed blocks;
* (b) keep track of stack depth.
*
* It is very important that sizeof(header) agree with malloc() alignment chunk
* size. The following default should work okay.
*/
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr {
char align[ALIGN_SIZE]; /* to force sizeof(header) */
struct {
union hdr *next; /* for chaining headers */
char *deep; /* for stack depth measure */
} h;
} header;
/*
* alloca( size ) returns a pointer to at least `size' bytes of storage which
* will be automatically reclaimed upon exit from the procedure that called
* alloca(). Originally, this space was supposed to be taken from the
* current stack frame of the caller, but that method cannot be made to work
* for some implementations of C, for example under Gould's UTX/32.
*/
static header *last_alloca_header = NULL; /* -> last alloca header */
pointer
alloca(size) /* returns pointer to storage */
unsigned size; /* # bytes to allocate */
{
auto char probe; /* probes stack depth: */
register char *depth = &probe;
#ifndef STACK_DIRECTION
if (STACK_DIR == 0) /* unknown growth direction */
find_stack_direction();
#endif
/*
* Reclaim garbage, defined as all alloca()ed storage that was
* allocated from deeper in the stack than currently.
*/
{
register header *hp; /* traverses linked list */
for (hp = last_alloca_header; hp != NULL;)
if (STACK_DIR > 0 && hp->h.deep > depth
|| STACK_DIR < 0 && hp->h.deep < depth) {
register header *np = hp->h.next;
free((pointer) hp); /* collect garbage */
hp = np; /* -> next header */
} else
break; /* rest are not deeper */
last_alloca_header = hp; /* -> last valid storage */
}
if (size == 0)
return NULL; /* no allocation required */
/* Allocate combined header + user data storage. */
{
register pointer new = malloc(sizeof(header) + size);
/* address of header */
((header *) new)->h.next = last_alloca_header;
((header *) new)->h.deep = depth;
last_alloca_header = (header *) new;
/* User storage begins just after header. */
return (pointer) ((char *) new + sizeof(header));
}
}
#else
#include "nullfile.h"
#endif