947 lines
19 KiB
C
947 lines
19 KiB
C
|
|
/*
|
|
* ide_alloc.c: ide memory allocation routines
|
|
*
|
|
* All memory is allocated from static pools.
|
|
*
|
|
*/
|
|
|
|
#ident "$Revision: 1.39 $"
|
|
|
|
#include <sys/sbd.h>
|
|
#include <ide_msg.h>
|
|
#include "libsc.h"
|
|
#include "uif.h"
|
|
#include "ide.h"
|
|
|
|
static void destroyexpr(node_t *);
|
|
static void destroyif(node_t *);
|
|
static void destroyfor(node_t *);
|
|
static void destroyrepeat(node_t *);
|
|
static void destroycmd(node_t *);
|
|
static void destroyswitch(node_t *);
|
|
static void destroycaselist(node_t *);
|
|
static void destroywhile(node_t *);
|
|
|
|
|
|
/*
|
|
* talloc allocates memory from one of five pools, containing
|
|
* strings of 16, 32, 64, 128, and 256 bytes.
|
|
*
|
|
* The larger size memory-pools result in an IDE executable
|
|
* that bothers the ARCS-prom loader. Everest prom doesn't
|
|
* mind (and needs more symbols for MP tests anyway).
|
|
*/
|
|
#if !defined(EVEREST)
|
|
|
|
#if (defined(IP22) || defined(IP28) || defined(IP30))
|
|
#define NEWSYMC 3000 /* total number of symbol records */
|
|
#define NEWNODEC 9800 /* total number of node records */
|
|
#define NSTR1 1024 /* size of 16 character string pool */
|
|
#define NSTR2 512 /* size of 32 character string pool */
|
|
#define NSTR3 256 /* size of 64 character string pool */
|
|
#else
|
|
#define NEWSYMC 1280 /* total number of symbol records */
|
|
#define NEWNODEC 4096 /* total number of node records */
|
|
#define NSTR1 256 /* size of 16 character string pool */
|
|
#define NSTR2 256 /* size of 32 character string pool */
|
|
#define NSTR3 128 /* size of 64 character string pool */
|
|
#endif
|
|
#define NSTR4 128 /* size of 128 character string pool */
|
|
#define NSTR5 64 /* size of 256 character string pool */
|
|
#else
|
|
#define NEWSYMC 4096 /* total number of symbol records */
|
|
#define NEWNODEC 16384 /* total number of node records */
|
|
|
|
#define NSTR1 2048 /* size of 16 character string pool */
|
|
#define NSTR2 1024 /* size of 32 character string pool */
|
|
#define NSTR3 256 /* size of 64 character string pool */
|
|
#define NSTR4 256 /* size of 128 character string pool */
|
|
#define NSTR5 256 /* size of 256 character string pool */
|
|
#endif /* !EVEREST */
|
|
|
|
#define TOTALSTRS (NSTR1 + NSTR2 + NSTR3 + NSTR4 + NSTR5)
|
|
|
|
sym_t *freesym; /* list of freed symbol records */
|
|
sym_t new__sym[NEWSYMC];/* symbol record pool */
|
|
int new__symc; /* index into newsym */
|
|
|
|
node_t *freenode; /* list of freed node records */
|
|
node_t new__node[NEWNODEC];/* node record pool */
|
|
int new__nodec; /* index into newnode */
|
|
|
|
/*
|
|
* The following arrays are used for string allocation.
|
|
* Strings are allocated on a best fit of a fixed length
|
|
* storage block. A null byte in the first position of an
|
|
* allocation string indicates that the string is free.
|
|
*/
|
|
char string1[NSTR1][STR1LEN];
|
|
char string2[NSTR2][STR2LEN];
|
|
char string3[NSTR3][STR3LEN];
|
|
char string4[NSTR4][STR4LEN];
|
|
char string5[NSTR5][STR5LEN];
|
|
|
|
int last1; /* last string allocated from string1 */
|
|
int last2; /* " " " " string2 */
|
|
int last3; /* " " " " string3 */
|
|
int last4; /* " " " " string4 */
|
|
int last5; /* " " " " string5 */
|
|
int _total_strs = TOTALSTRS;
|
|
|
|
|
|
/*
|
|
* keep stats on string-, symbol-, and node-pools
|
|
*/
|
|
|
|
/* allocate an extra slot (index 0) for combined totals */
|
|
#define NUMSTRSTATS (NUMSTRPOOLS+1)
|
|
|
|
typedef struct alloc_info {
|
|
int used;
|
|
int builtins;
|
|
int perm;
|
|
int prev_used;
|
|
} alloc_info_t;
|
|
|
|
alloc_info_t _nodes;
|
|
alloc_info_t _syms;
|
|
alloc_info_t strstats[NUMSTRSTATS];
|
|
|
|
int _sympoolsize=0;
|
|
|
|
#define nnodes _nodes.used
|
|
#define nsyms _syms.used
|
|
#define STRTOTS 0 /* slot 0 for totals of all 5 strlen pools */
|
|
#define STR1SLOT 1
|
|
#define STR2SLOT 2
|
|
#define STR3SLOT 3
|
|
#define STR4SLOT 4
|
|
#define STR5SLOT 5
|
|
|
|
#define nstrs strstats[STRTOTS].used
|
|
#define nstr1 strstats[STR1SLOT].used
|
|
#define nstr2 strstats[STR2SLOT].used
|
|
#define nstr3 strstats[STR3SLOT].used
|
|
#define nstr4 strstats[STR4SLOT].used
|
|
#define nstr5 strstats[STR5SLOT].used
|
|
|
|
|
|
#define FREE_ZERO 0xBAD
|
|
#define ALLOC_ZERO 0xDAB
|
|
|
|
extern int inrawcmd; /* parsing diag cmd that doesn't want parsed args */
|
|
extern int _do_dumphtab(int, char **);
|
|
|
|
static void zero_sym(sym_t *, int);
|
|
static void zero_node(node_t *);
|
|
static int pool_idx(char *);
|
|
|
|
|
|
int
|
|
_initsyms(void)
|
|
{
|
|
int i;
|
|
|
|
ASSERT(!_sympoolsize);
|
|
|
|
for (i = 0; i < NEWSYMC; i++) {
|
|
zero_sym(&new__sym[i], FREE_ZERO);
|
|
}
|
|
_sympoolsize = i;
|
|
|
|
return(i);
|
|
}
|
|
|
|
/*
|
|
* ide_init() calls initmstats() after filling the hash table with all
|
|
* the builtins from awk-created .c files. initmstats() snaps the
|
|
* counts to save a record of the resources required by the builtins
|
|
* symbols. After '_ide_initialized' is true, addsym() bumps the counts
|
|
* when new permanent symbols are created.
|
|
*/
|
|
int
|
|
initmstats()
|
|
{
|
|
int i;
|
|
alloc_info_t *ap;
|
|
|
|
_nodes.perm = _nodes.builtins = _nodes.prev_used = _nodes.used;
|
|
_syms.perm = _syms.builtins = _syms.prev_used = _syms.used;
|
|
|
|
for (i = 0; i < NUMSTRSTATS; i++) {
|
|
ap = &strstats[i];
|
|
ap->perm=ap->builtins=ap->prev_used = ap->used;
|
|
}
|
|
if (Reportlevel > INFO) {
|
|
msg_printf(JUST_DOIT, " Initial memory-allocation stats:\n");
|
|
(void)showmstats(0, 0);
|
|
}
|
|
|
|
if (_Verbose >= 3)
|
|
dump_symdefs();
|
|
|
|
if (_Verbose >= 2)
|
|
_do_dumphtab(0, (char **)0);
|
|
|
|
return(0);
|
|
|
|
} /* initmstats */
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
showmstats(int argc, sym_t *argv[])
|
|
{
|
|
register int i;
|
|
|
|
msg_printf(JUST_DOIT, "\n NODES: %d of %d used (prev %d): %d free\n",
|
|
nnodes, NEWNODEC, _nodes.prev_used, NEWNODEC-nnodes);
|
|
msg_printf(JUST_DOIT," SYMBOLS: %d of %d used (prev %d): %d free\n",
|
|
nsyms, NEWSYMC, _syms.prev_used, NEWSYMC-nsyms);
|
|
msg_printf(JUST_DOIT," STRINGS: %d of %d used (prev %d): %d free\n",
|
|
nstrs, _total_strs, strstats[STRTOTS].prev_used,
|
|
(_total_strs-nstrs));
|
|
msg_printf(JUST_DOIT,
|
|
" --> %d(prev %d) x %d, %d(%d) x %d, %d(%d) x %d\n",
|
|
nstr1, strstats[1].prev_used, STR1LEN,
|
|
nstr2, strstats[2].prev_used, STR2LEN,
|
|
nstr3, strstats[3].prev_used, STR3LEN);
|
|
msg_printf(JUST_DOIT,
|
|
" %d (%d) x %d, %d (%d) x %d\n\n",
|
|
nstr4, strstats[4].prev_used, STR4LEN,
|
|
nstr5, strstats[5].prev_used, STR5LEN);
|
|
|
|
_nodes.prev_used = nnodes;
|
|
_syms.prev_used = nsyms;
|
|
for (i = 0; i < NUMSTRSTATS; i++) {
|
|
strstats[i].prev_used = strstats[i].used;
|
|
}
|
|
|
|
/* optional info */
|
|
msg_printf(VDBG,
|
|
" Builtins required %d symbols and %d strings (%d nodes)\n\n",
|
|
_syms.builtins, strstats[0].builtins, _nodes.builtins);
|
|
|
|
/* VERY optional info */
|
|
msg_printf(VDBG+1,
|
|
" freesym 0x%x, new_symc %d; freenode 0x%x, new_nodec %d\n\n",
|
|
freesym, new__symc, freenode, new__nodec);
|
|
|
|
return 0;
|
|
} /* showmstats */
|
|
|
|
int
|
|
bumpmstats(sym_t *psym)
|
|
{
|
|
int idx;
|
|
int _error=0;
|
|
|
|
msg_printf(DBG, " <bumpmstats: psym 0x%x>\n", psym);
|
|
|
|
if (!_ide_initialized) {
|
|
msg_printf(IDE_ERR,
|
|
"!!--> bad bumpmstats() call (!ide_initialized)\n");
|
|
return(-1);
|
|
}
|
|
ASSERT(psym);
|
|
|
|
/*
|
|
* bump `perm' and `prev_used' counts to keep everything consistent.
|
|
* (talloc() and makesym() already adjusted the `temp' fields).
|
|
*/
|
|
_syms.perm++;
|
|
_syms.prev_used++;
|
|
|
|
if (psym->sym_name) {
|
|
|
|
#ifndef IP21
|
|
ASSERT(_ITSAPTR(psym->sym_name));
|
|
#endif
|
|
if (idx = pool_idx(psym->sym_name)) { /* can't be 0 */
|
|
strstats[idx].perm++;
|
|
strstats[idx].prev_used++;
|
|
strstats[STRTOTS].perm++;
|
|
strstats[STRTOTS].prev_used++;
|
|
} else {
|
|
msg_printf(IDE_ERR,
|
|
" !!namestr (0x%x) not from pool; idx %d\n",
|
|
psym->sym_name, idx);
|
|
_error--;
|
|
}
|
|
}
|
|
if (psym->sym_basetype==SYMB_STR || psym->sym_basetype==SYMB_SETSTR) {
|
|
#ifndef IP21
|
|
ASSERT(_ITSAPTR(psym->sym_s));
|
|
#endif
|
|
if (idx = pool_idx(psym->sym_s)) {
|
|
strstats[idx].perm++;
|
|
strstats[idx].prev_used++;
|
|
strstats[STRTOTS].perm++;
|
|
strstats[STRTOTS].prev_used++;
|
|
} else {
|
|
msg_printf(IDE_ERR,
|
|
" !!sym_s (0x%x) not from pool; idx %d\n",
|
|
psym->sym_s, idx);
|
|
_error--;
|
|
}
|
|
}
|
|
return(_error);
|
|
|
|
} /* bumpmstats */
|
|
|
|
static int
|
|
pool_idx(char *s)
|
|
{
|
|
ASSERT(s);
|
|
|
|
switch(*(s-1)) {
|
|
|
|
case '1':
|
|
return(1);
|
|
case '2':
|
|
return(2);
|
|
case '3':
|
|
return(3);
|
|
case '4':
|
|
return(4);
|
|
case '5':
|
|
return(5);
|
|
default:
|
|
return(0);
|
|
}
|
|
/*NOTREACHED*/
|
|
|
|
} /* pool_idx */
|
|
|
|
|
|
/*
|
|
* descend a parse tree freeing each node
|
|
*
|
|
* The descent path must match the tree pattern created in ide_gram.y
|
|
*
|
|
*/
|
|
void
|
|
destroytree(node_t *pnode)
|
|
{
|
|
if ( ! pnode )
|
|
return;
|
|
|
|
switch ( pnode->node_type ) {
|
|
case OP_STMT:
|
|
destroytree( pnode->node_right);
|
|
destroytree( pnode->node_left);
|
|
break;
|
|
case OP_PRINT:
|
|
destroyexpr(pnode->node_left);
|
|
destroynode(pnode);
|
|
break;
|
|
case OP_IF:
|
|
destroyif(pnode);
|
|
break;
|
|
case OP_WHILE:
|
|
destroywhile(pnode);
|
|
break;
|
|
case OP_FOR:
|
|
destroyfor(pnode);
|
|
break;
|
|
case OP_RETURN:
|
|
destroynode(pnode);
|
|
break;
|
|
case OP_BREAK:
|
|
destroynode(pnode);
|
|
break;
|
|
case OP_CONTINUE:
|
|
destroynode(pnode);
|
|
break;
|
|
case OP_DO:
|
|
destroywhile(pnode);
|
|
break;
|
|
case OP_SWITCH:
|
|
destroyswitch(pnode);
|
|
break;
|
|
case OP_CMD:
|
|
destroycmd(pnode);
|
|
break;
|
|
case OP_REPEAT:
|
|
destroyrepeat(pnode);
|
|
break;
|
|
default:
|
|
destroyexpr(pnode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
destroyrepeat(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
destroytree(pnode->node_right);
|
|
destroysym(pnode->node_psym);
|
|
destroynode(pnode);
|
|
}
|
|
static
|
|
void
|
|
destroycmd(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
destroyargv(pnode->node_right);
|
|
destroynode(pnode);
|
|
}
|
|
|
|
void
|
|
destroyargv(node_t *pnode)
|
|
{
|
|
if ( ! pnode )
|
|
return;
|
|
|
|
destroyargv(pnode->node_right);
|
|
destroyexpr(pnode->node_left);
|
|
destroynode(pnode);
|
|
}
|
|
|
|
static
|
|
void
|
|
destroyswitch(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
destroysym(pnode->node_psym);
|
|
destroycaselist(pnode->node_right);
|
|
destroynode(pnode);
|
|
|
|
}
|
|
|
|
static
|
|
void
|
|
destroycaselist(node_t *pnode)
|
|
{
|
|
if ( ! pnode )
|
|
return;
|
|
|
|
if ( pnode->node_type == OP_CASELIST ) {
|
|
destroycaselist( pnode->node_right );
|
|
pnode = pnode->node_left;
|
|
}
|
|
|
|
if ( pnode->node_psym )
|
|
destroysym(pnode->node_psym);
|
|
|
|
destroytree( pnode->node_right );
|
|
}
|
|
|
|
static
|
|
void
|
|
destroyif(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
destroyexpr(pnode->node_left);
|
|
if ( pnode->node_right->node_type == OP_ELSE ) {
|
|
destroytree(pnode->node_right->node_left);
|
|
destroytree(pnode->node_right->node_right);
|
|
}
|
|
|
|
destroynode(pnode->node_right);
|
|
destroynode(pnode);
|
|
}
|
|
|
|
static
|
|
void
|
|
destroyfor(node_t *pnode)
|
|
{
|
|
node_t *n1,*n2,*n3,*n4;
|
|
|
|
ASSERT(pnode);
|
|
n1 = pnode->node_left->node_left;
|
|
n2 = pnode->node_left->node_right;
|
|
n3 = pnode->node_right->node_left;
|
|
n4 = pnode->node_right->node_right;
|
|
|
|
if (n1) destroyexpr(n1);
|
|
if (n2) destroyexpr(n2);
|
|
if (n3) destroyexpr(n3);
|
|
destroytree(n4);
|
|
|
|
destroynode(pnode->node_left);
|
|
destroynode(pnode->node_right);
|
|
destroynode(pnode);
|
|
}
|
|
|
|
static
|
|
void
|
|
destroywhile(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
destroyexpr(pnode->node_left);
|
|
destroytree(pnode->node_right);
|
|
destroynode(pnode);
|
|
}
|
|
|
|
void
|
|
destroyexpr(node_t *pnode)
|
|
{
|
|
if ( ! pnode )
|
|
return;
|
|
|
|
switch(pnode->node_type) {
|
|
case OP_SHL: case OP_SHR:
|
|
case OP_ADD: case OP_SUB:
|
|
case OP_MUL: case OP_DIV:
|
|
case OP_MOD: case OP_LT: case OP_LE:
|
|
case OP_GT: case OP_GE: case OP_EQ: case OP_NE:
|
|
case OP_OR: case OP_AND: case OP_ANDAND: case OP_OROR:
|
|
destroyexpr(pnode->node_right);
|
|
destroyexpr(pnode->node_left);
|
|
break;
|
|
case OP_ASSIGN:
|
|
case OP_ADDASS: case OP_SUBASS:
|
|
case OP_MULASS: case OP_DIVASS: case OP_MODASS:
|
|
case OP_SHLASS: case OP_SHRASS:
|
|
case OP_ANDASS: case OP_ORASS:
|
|
destroyexpr(pnode->node_right);
|
|
/* Assignments are only made to things in the
|
|
symbol table so
|
|
destroysym(pnode->node_psym); is not necessary */
|
|
break;
|
|
case OP_UMINUS:
|
|
case OP_COM:
|
|
case OP_NOT:
|
|
destroyexpr(pnode->node_right);
|
|
break;
|
|
case OP_PRED:
|
|
case OP_PREI:
|
|
case OP_POSTD:
|
|
case OP_POSTI:
|
|
break;
|
|
case OP_VAR:
|
|
destroysym(pnode->node_psym);
|
|
break;
|
|
case OP_FCALL:
|
|
case OP_ARGLIST:
|
|
break;
|
|
}
|
|
|
|
destroynode(pnode);
|
|
}
|
|
|
|
/*
|
|
* destroyed nodes are put at the head of the free list
|
|
*
|
|
*/
|
|
void
|
|
destroynode(node_t *pnode)
|
|
{
|
|
ASSERT(pnode);
|
|
|
|
nnodes--;
|
|
zero_node(pnode);
|
|
pnode->node_right = freenode;
|
|
freenode = pnode;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* destroyed symbols are put at the head of the free list
|
|
*
|
|
*/
|
|
void
|
|
destroysym(sym_t *psym)
|
|
{
|
|
|
|
ASSERT(psym);
|
|
|
|
/* symbols with names are permanent */
|
|
if ( psym->sym_flags & SYM_INTABLE ) {
|
|
return;
|
|
}
|
|
|
|
#if defined(noSET_DEBUG)
|
|
if (psym->sym_basetype == SYMB_SET) {
|
|
char setbuffer[SETBUFSIZ];
|
|
|
|
sprintf_cset(setbuffer, psym->sym_set);
|
|
msg_printf(INFO,
|
|
" destroysym: %s set '%s': type %d flags 0x%x: %s",
|
|
(psym->sym_flags & SYM_INTABLE? "PERM" : "TMP"),
|
|
_SAFESTR(psym->sym_name), psym->sym_type, psym->sym_flags,
|
|
setbuffer);
|
|
}
|
|
#endif
|
|
|
|
nsyms--;
|
|
|
|
if ((psym->sym_basetype == SYMB_STR) ||
|
|
(psym->sym_basetype == SYMB_SETSTR)) {
|
|
destroystr(psym->sym_s);
|
|
psym->sym_s = NULL;
|
|
}
|
|
zero_sym(psym, FREE_ZERO);
|
|
|
|
psym->sym_hlink = freesym;
|
|
freesym = psym;
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* free a string by setting its string table allocation byte
|
|
* to null.
|
|
*/
|
|
void
|
|
destroystr(char *s)
|
|
{
|
|
|
|
if ( ! s ) {
|
|
#if IDEBUG
|
|
msg_printf(DBG+1, " ->destroystr: NULL string ptr (s)\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if ( *(s-1) == '1' )
|
|
nstr1--;
|
|
else
|
|
if ( *(s-1) == '2' )
|
|
nstr2--;
|
|
else
|
|
if ( *(s-1) == '3' )
|
|
nstr3--;
|
|
else
|
|
if ( *(s-1) == '4' )
|
|
nstr4--;
|
|
else
|
|
if ( *(s-1) == '5' )
|
|
nstr5--;
|
|
else {
|
|
char panicbuf[128];
|
|
|
|
sprintf(panicbuf, "Bad call to destroystr, string addr 0x%x",
|
|
s);
|
|
ide_panic(panicbuf);
|
|
}
|
|
|
|
*(s-1) = '\0';
|
|
nstrs--;
|
|
|
|
}
|
|
|
|
/*
|
|
* create a new symbol record by either taking one off of the free list
|
|
* or getting another one out of the pool.
|
|
*
|
|
*/
|
|
sym_t *
|
|
makesym(void)
|
|
{
|
|
sym_t *tmp;
|
|
|
|
nsyms++;
|
|
|
|
if ( freesym ) {
|
|
tmp = freesym;
|
|
freesym = tmp->sym_hlink;
|
|
zero_sym(tmp, ALLOC_ZERO);
|
|
return tmp;
|
|
}
|
|
|
|
if ( new__symc < NEWSYMC ) {
|
|
tmp = &new__sym[new__symc++];
|
|
zero_sym(tmp, ALLOC_ZERO); /* just to be sure... */
|
|
return(tmp);
|
|
}
|
|
|
|
/* err, bad thing */
|
|
printf("!!! makesym() fails, out of symbols. Dump stats:\n");
|
|
showmstats(0, 0);
|
|
ide_panic("Out of symbols\n");
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
zero_sym(sym_t *psym, int how)
|
|
{
|
|
ASSERT(psym);
|
|
|
|
psym->sym_hlink = 0;
|
|
psym->sym_basetype = (short)SYMB_FREE;
|
|
psym->sym_type = (short)SYM_FREE;
|
|
psym->sym_logidx = FREE_LOGIDX;
|
|
psym->sym_reserved = (short)0;
|
|
psym->sym_flags = 0;
|
|
psym->sym_set = 0; /* gets both hi and low ints! */
|
|
|
|
if (how == ALLOC_ZERO) { /* so _dumpsym will know whether it's valid */
|
|
psym->sym_basetype = SYMB_BADVAL;
|
|
psym->sym_type = SYM_UNDEFINED;
|
|
psym->sym_logidx = ALLOC_LOGIDX;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* same algorithm as above for nodes
|
|
*/
|
|
node_t *
|
|
makenode(void)
|
|
{
|
|
node_t *tmp;
|
|
|
|
nnodes++;
|
|
|
|
if ( freenode ) {
|
|
tmp = freenode;
|
|
freenode = tmp->node_right;
|
|
zero_node(tmp);
|
|
return tmp;
|
|
}
|
|
|
|
if ( new__nodec < NEWNODEC ) {
|
|
tmp = &new__node[new__nodec++];
|
|
zero_node(tmp);
|
|
return tmp;
|
|
}
|
|
else
|
|
|
|
printf("!!! makenode() fails, out of nodes. Dump stats:\n");
|
|
showmstats(0, 0);
|
|
ide_panic("Out of nodes\n");
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
zero_node(node_t *tmp)
|
|
{
|
|
ASSERT(tmp);
|
|
tmp->node_type = 0;
|
|
tmp->node_right = 0;
|
|
tmp->node_left = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* allocate space for string
|
|
*
|
|
* A best fit out of 5 possible pools algorithm is used. The
|
|
* -1 position of the string stores a status byte, null indicates
|
|
* that the string is free.
|
|
*
|
|
*/
|
|
char *
|
|
talloc(size_t len)
|
|
{
|
|
char *t;
|
|
int i;
|
|
|
|
#if IDEBUG
|
|
if ((len == 0) && (Reportlevel >= VDBG))
|
|
printf(" talloc: 0 'len' arg!!!\n");
|
|
#endif
|
|
len += 1;
|
|
if ( len <= STR1LEN )
|
|
for ( i = last1; i < last1+NSTR1; i++ )
|
|
if ( string1[i % NSTR1][0] == '\0' ) {
|
|
last1 = i % NSTR1;
|
|
t = &string1[last1][1];
|
|
string1[last1][0] = '1';
|
|
nstr1++;
|
|
return t;
|
|
}
|
|
|
|
if ( len <= STR2LEN )
|
|
for ( i = last2; i < last2+NSTR2; i++ )
|
|
if ( string2[i % NSTR2][0] == '\0' ) {
|
|
last2 = i % NSTR2;
|
|
t = &string2[last2][1];
|
|
string2[last2][0] = '2';
|
|
nstr2++;
|
|
return t;
|
|
}
|
|
|
|
if ( len <= STR3LEN )
|
|
for ( i = last3; i < last3+NSTR3; i++ )
|
|
if ( string3[i % NSTR3][0] == '\0' ) {
|
|
last3 = i % NSTR3;
|
|
t = &string3[last3][1];
|
|
string3[last3][0] = '3';
|
|
nstr3++;
|
|
return t;
|
|
}
|
|
|
|
if ( len <= STR4LEN )
|
|
for ( i = last4; i < last4+NSTR4; i++ )
|
|
if ( string4[i % NSTR4][0] == '\0' ) {
|
|
last4 = i % NSTR4;
|
|
t = &string4[last4][1];
|
|
string4[last4][0] = '4';
|
|
nstr4++;
|
|
return t;
|
|
}
|
|
|
|
if ( len <= STR5LEN )
|
|
for ( i = last5; i < last5+NSTR5; i++ )
|
|
if ( string5[i % NSTR5][0] == '\0' ) {
|
|
last5 = i % NSTR5;
|
|
t = &string5[last5][1];
|
|
string5[last5][0] = '5';
|
|
nstr5++;
|
|
return t;
|
|
}
|
|
|
|
printf("!!! talloc(%d) fails, out of string space\n", len);
|
|
showmstats(0, 0);
|
|
ide_panic("talloc out of string space");
|
|
return NULL;
|
|
}
|
|
/*
|
|
* get space for a string and copy into it
|
|
*/
|
|
char *
|
|
makestr(char *s)
|
|
{
|
|
size_t len;
|
|
char *t;
|
|
|
|
nstrs++;
|
|
|
|
if (s == 0) {
|
|
len = 0;
|
|
} else
|
|
len = strlen(s);
|
|
|
|
t = talloc((int)len+1);
|
|
if (t == 0) {
|
|
msg_printf(IDE_ERR, "makestr's talloc(len %d) returned NULL\n",
|
|
len);
|
|
ide_panic("makestr: talloc");
|
|
}
|
|
|
|
if (len == 0) /* return a string of length 0 */
|
|
*t = '\0';
|
|
else
|
|
strcpy(t, s);
|
|
|
|
return t;
|
|
}
|
|
|
|
/*
|
|
* make a symbol out of an integer
|
|
*/
|
|
sym_t *
|
|
makeisym(int i)
|
|
{
|
|
sym_t *tmp = makesym();
|
|
|
|
ASSERT(tmp != 0);
|
|
|
|
tmp->sym_basetype = SYMB_INT;
|
|
tmp->sym_type = SYM_CON;
|
|
tmp->sym_i = i;
|
|
|
|
return tmp;
|
|
} /* makeisym */
|
|
|
|
|
|
/*
|
|
* make a symbol out of a string
|
|
*/
|
|
sym_t *
|
|
makessym(char *s)
|
|
{
|
|
sym_t *psym, *tsym;
|
|
|
|
ASSERT(s != NULL);
|
|
|
|
psym = makesym();
|
|
ASSERT(psym);
|
|
|
|
if (_SHOWIT(EVAL_DBG|DBG+4))
|
|
msg_printf(JUST_DOIT," makessym, %s: instring \"%s\", (len %d): ",
|
|
(inrawcmd ? "*RAW*" : "*COOKED*"), _SAFESTR(s),
|
|
(_SAFESTR(s) ? strlen(s) : -1));
|
|
|
|
if (!inrawcmd) { /* make a string constant */
|
|
psym->sym_type = SYM_CON;
|
|
psym->sym_basetype = SYMB_STR;
|
|
psym->sym_s = s;
|
|
msg_printf((EVAL_DBG|DBG+4),"STR CONST and return!\n");
|
|
return(psym);
|
|
}
|
|
|
|
/*
|
|
* all remaining cases are raw (functions taking char* arg format)
|
|
*/
|
|
if (s[0] != '$') { /* must be string const, eg. "123" */
|
|
|
|
psym->sym_type = SYM_CON;
|
|
psym->sym_basetype = SYMB_STR;
|
|
psym->sym_s = s;
|
|
msg_printf((EVAL_DBG|DBG+4)," non-dollar STR CONST; strlen %d\n",
|
|
strlen(psym->sym_s));
|
|
return(psym);
|
|
}
|
|
|
|
/*
|
|
* now they all begin with '$': as in "$<blah>"
|
|
*/
|
|
msg_printf((EVAL_DBG|DBG+4)," ->$");
|
|
|
|
if (isdigit(s[1])) { /* $n == formal parameter */
|
|
psym->sym_type = SYM_PARAM;
|
|
psym->sym_indx = (int)(s[1] - '0');
|
|
psym->sym_s = s;
|
|
if (_SHOWIT(EVAL_DBG|DBG+4)) {
|
|
msg_printf(JUST_DOIT, "formal param $%d, strlen %d\n",
|
|
psym->sym_indx, strlen(psym->sym_s));
|
|
_dumpsym(psym);
|
|
}
|
|
return(psym);
|
|
} else { /* $xyz: named-identifier used as argument */
|
|
char *tmpp = &s[1];
|
|
|
|
msg_printf((EVAL_DBG|DBG+4)," ->$xyz!");
|
|
if (!(tsym = findsym(tmpp))) { /* temp sym (declared inside a block) */
|
|
psym->sym_basetype = SYMB_STR;
|
|
psym->sym_type = SYM_VAR;
|
|
psym->sym_s = s;
|
|
if (_SHOWIT(EVAL_DBG|DBG+4)) {
|
|
msg_printf(JUST_DOIT, " temp. VAR symbol!\n ");
|
|
_dumpsym(psym);
|
|
}
|
|
return(psym);
|
|
}
|
|
|
|
destroysym(psym);
|
|
/*
|
|
* rawcmds need the variable's value promoted to string
|
|
* and placed in psym->sym_s.
|
|
*/
|
|
if (_SHOWIT(EVAL_DBG|DBG+4)) {
|
|
msg_printf(JUST_DOIT, " symbol before pro_str:\n ");
|
|
_dumpsym(tsym);
|
|
}
|
|
|
|
tsym = pro_str(tsym);
|
|
if (_SHOWIT(EVAL_DBG|DBG+4)) {
|
|
msg_printf(JUST_DOIT, " result symbol (after pro_str):\n ");
|
|
_dumpsym(tsym);
|
|
}
|
|
return(tsym);
|
|
}
|
|
} /* makessym */
|
|
|
|
/* Returns a chunk of free memory for a diag to use over it's life. Other
|
|
* diags may claim this space, so it should only be over the life of a diag.
|
|
*
|
|
* **** Cannot be mixed with ide_malloc! ****
|
|
*
|
|
* Still in ide_alloc.c to ensure ide_malloc.c is linked correctly.
|
|
*/
|
|
void *
|
|
get_chunk(int size)
|
|
{
|
|
if (init_ide_malloc(size) == 0)
|
|
return 0;
|
|
|
|
return ide_malloc(size);
|
|
}
|