Пример #1
0
static void
set_main_to_stdin(void)
{
    cell_destroy(FILENAME);
    FILENAME->type = C_STRING;
    FILENAME->ptr = (PTR) new_STRING("-");
    cell_destroy(FNR);
    FNR->type = C_DOUBLE;
    FNR->dval = 0.0;
    rt_fnr = 0;
    main_fin = FINdopen(0, 1);
}
Пример #2
0
void
slow_cell_assign(CELL * target, CELL * source)
{
    if (

#ifdef MSDOS			/* the dreaded segment nonsense */
	   SAMESEG(target, field) &&
#endif
	   target >= field && target <= LAST_PFIELD)
	field_assign(target, source);
    else {
	CELL **p = fbank + 1;

	while (*p) {
	    if (
#ifdef  MSDOS
		   SAMESEG(target, *p) &&
#endif
		   target >= *p && target < *p + FBANK_SZ) {
		field_assign(target, source);
		return;
	    }
	    p++;
	}
	/* its not a field */
	cell_destroy(target);
	cellcpy(target, source);
    }
}
Пример #3
0
static void
load_field_ov(void)
{
    register SPLIT_OV *p;	/* walks split_ov_list */
    register CELL *cp;		/* target of copy */
    int j;			/* current fbank[] */
    CELL *cp_limit;		/* change fbank[] */
    SPLIT_OV *q;		/* trails p */

    /* make sure the fields are allocated */
    slow_field_ptr(nf);

    p = split_ov_list;
    split_ov_list = (SPLIT_OV *) 0;
    j = 1;
    cp = fbank[j];
    cp_limit = cp + FBANK_SZ;
    while (p) {
	cell_destroy(cp);
	cp->type = C_MBSTRN;
	cp->ptr = (PTR) p->sval;

	if (++cp == cp_limit) {
	    cp = fbank[++j];
	    cp_limit = cp + FBANK_SZ;
	}

	q = p;
	p = p->link;
	ZFREE(q);
    }
}
Пример #4
0
CELL *
bi_printf(CELL *sp)
{
    register int k;
    register CELL *p;
    FILE *fp;

    TRACE_FUNC("bi_printf", sp);

    k = sp->type;
    if (k < 0) {
    /* k has redirection */
    if ((--sp)->type < C_STRING)
        cast1_to_s(sp);
    fp = (FILE *) file_find(string(sp), k);
    free_STRING(string(sp));
    k = (--sp)->type;
    /* k is now number of args including format */
    } else
    fp = stdout;

    sp -= k;            /* sp points at the format string */
    k--;

    if (sp->type < C_STRING)
    cast1_to_s(sp);
    do_printf(fp, string(sp)->str, (unsigned) k, sp + 1);
    free_STRING(string(sp));

    /* cleanup arguments on eval stack */
    for (p = sp + 1; k; k--, p++)
    cell_destroy(p);
    return --sp;
}
Пример #5
0
void
free_cell_data(CELL * cp)
{
    switch (cp->type) {
    case C_RE:
	TRACE(("\t... C_RE\n"));
	re_destroy(cp->ptr);
	zfree(cp, sizeof(CELL));
	break;
    case C_REPL:
	TRACE(("\t... C_REPL\n"));
	repl_destroy(cp);
	zfree(cp, sizeof(CELL));
	break;
    case C_REPLV:
	TRACE(("\t... C_REPLV\n"));
	repl_destroy(cp);
	zfree(cp, sizeof(CELL));
	break;
    case C_MBSTRN:
    case C_STRING:
    case C_STRNUM:
	if (cp >= (field + (nf < 1 ? 1 : nf)) || (cp < field)) {
	    cell_destroy(cp);
	}
	break;
    }
}
Пример #6
0
CELL *
bi_print(
        CELL *sp)        /* stack ptr passed in */
{
    register CELL *p;
    register int k;
    FILE *fp;

    k = sp->type;
    if (k < 0) {
    /* k holds redirection */
    if ((--sp)->type < C_STRING)
        cast1_to_s(sp);
    fp = (FILE *) file_find(string(sp), k);
    free_STRING(string(sp));
    k = (--sp)->type;
    /* k now has number of arguments */
    } else
    fp = stdout;

    if (k) {
    p = sp - k;        /* clear k variables off the stack */
    sp = p - 1;
    k--;

    while (k > 0) {
        print_cell(p, fp);
        print_cell(OFS, fp);
        cell_destroy(p);
        p++;
        k--;
    }

    print_cell(p, fp);
    cell_destroy(p);
    } else {            /* print $0 */
    sp--;
    print_cell(&field[0], fp);
    }

    print_cell(ORS, fp);
    if (ferror(fp))
    write_error();
    return sp;
}
Пример #7
0
CELL *
bi_srand(CELL * sp)
{
    CELL c;

    if (sp->type == 0)		/* seed off clock */
    {
	time_t secs = time((time_t *) 0);
	cellcpy(sp, &cseed);
	cell_destroy(&cseed);
	cseed.type = C_DOUBLE;
	cseed.dval = (double) secs;
    } else {			/* user seed */
	sp--;
	/* swap cseed and *sp ; don't need to adjust ref_cnts */
	c = *sp;
	*sp = cseed;
	cseed = c;
    }

    /* The old seed is now in *sp ; move the value in cseed to
       seed in range [1,M) */

    cellcpy(&c, &cseed);
    if (c.type == C_NOINIT)
	cast1_to_d(&c);

    seed = ((c.type == C_DOUBLE)
	    ? (long) (d_to_i(c.dval) & M) % M + 1
	    : (long) hash(string(&c)->str) % M + 1);
    if (seed == M)
	seed = M - 1;

    cell_destroy(&c);

    /* crank it once so close seeds don't give a close
       first result  */
    crank(seed);

    return sp;
}
Пример #8
0
struct cell *
cell_new(lua_State *L, const char * mainfile) {
	hive_getenv(L, "cell_map");
	int cell_map = lua_absindex(L,-1);	// cell_map
	luaL_requiref(L, "cell.c", cell_lib, 0);	// cell_map cell_lib
	struct cell * c = cell_create();
	c->L = L;
	cell_touserdata(L, cell_map, c);	// cell_map cell_lib cell_ud

	lua_setfield(L, -2, "self");	// cell_map cell_lib

	hive_getenv(L, "system_pointer");
	struct cell * sys = lua_touserdata(L, -1);	// cell_map cell_lib system_cell
	lua_pop(L, 1);	
	if (sys) {
		cell_touserdata(L, cell_map, sys);
		lua_setfield(L, -2, "system");
	}

	lua_pop(L,2);
	lua_pushlightuserdata(L, c);
	hive_setenv(L, "cell_pointer");
	
	int err = luaL_loadfile(L, mainfile);
	if (err) {
		printf("%d : %s\n", err, lua_tostring(L,-1));
		lua_pop(L,1);
		goto _error;
	}

	err = lua_pcall(L, 0, 0, 0);
	if (err) {
		printf("%d : %s\n", err, lua_tostring(L,-1));
		lua_pop(L,1);
		goto _error;
	}
	lua_pushcfunction(L, traceback);	// upvalue 1
	lua_pushcfunction(L, data_unpack); // upvalue 2
	hive_getenv(L, "dispatcher");	// upvalue 3
	if (!lua_isfunction(L, -1)) {
		printf("set dispatcher first\n");
		goto _error;
	}
	hive_getenv(L, "cell_map");	// upvalue 4
	lua_pushcclosure(L, lcallback, 4);
	return c;
_error:
	scheduler_deletetask(L);
	c->L = NULL;
	cell_destroy(c);

	return NULL;
}
Пример #9
0
void
set_binmode(int x)
{
    CELL c;
    int change = ((x & 4) == 0);

    /* set RS */
    c.type = C_STRING;
    c.ptr = (PTR) new_STRING((change && (x & 1)) ? "\r\n" : "\n");
    field_assign(RS, &c);
    free_STRING(string(&c));

    /* set ORS */
    cell_destroy(ORS);
    ORS->type = C_STRING;
    ORS->ptr = (PTR) new_STRING((change && (x & 2)) ? "\r\n" : "\n");

    cell_destroy(BINMODE);
    BINMODE->type = C_DOUBLE;
    BINMODE->dval = (double) x;
}
Пример #10
0
CELL *
bi_match(CELL *sp)
{
    char *p;
    size_t length;

    TRACE_FUNC("bi_match", sp);

    if (sp->type != C_RE)
	cast_to_RE(sp);
    if ((--sp)->type < C_STRING)
	cast1_to_s(sp);

    cell_destroy(RSTART);
    cell_destroy(RLENGTH);
    RSTART->type = C_DOUBLE;
    RLENGTH->type = C_DOUBLE;

    p = REmatch(string(sp)->str,
		string(sp)->len,
		cast_to_re((sp + 1)->ptr),
		&length,
		0);

    if (p) {
	sp->dval = (double) (p - string(sp)->str + 1);
	RLENGTH->dval = (double) length;
    } else {
	sp->dval = 0.0;
	RLENGTH->dval = -1.0;	/* posix */
    }

    free_STRING(string(sp));
    sp->type = C_DOUBLE;

    RSTART->dval = sp->dval;

    return_CELL("bi_match", sp);
}
Пример #11
0
void array_clear(ARRAY A)
{
    unsigned i ;
    ANODE *p, *q ;
    if (A->type == AY_SPLIT) {
        for(i = 0; i < A->size; i++)
            cell_destroy((CELL*)A->ptr+i) ;
        zfree(A->ptr, A->limit * sizeof(CELL)) ;
    }
    else if (A->type & AY_STR) {
        DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
        for(i=0; (unsigned) i <= A->hmask; i++) {
            p = table[i].slink ;
            while(p) {
                q = p ;
                p = q->slink ;
                free_STRING(q->sval) ;
                cell_destroy(&q->cell) ;
                ZFREE(q) ;
            }
        }
        zfree(A->ptr, (A->hmask+1)*sizeof(DUAL_LINK)) ;
    }
    else if (A->type & AY_INT) {
        DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
        for(i=0; (unsigned) i <= A->hmask; i++) {
            p = table[i].ilink ;
            while(p) {
                q = p ;
                p = q->ilink ;
                cell_destroy(&q->cell) ;
                ZFREE(q) ;
            }
        }
        zfree(A->ptr, (A->hmask+1)*sizeof(DUAL_LINK)) ;
    }
    memset(A, 0, sizeof(*A)) ;
}
Пример #12
0
void
field_leaks(void)
{
    int n;

    free_STRING(string(CONVFMT));
    free_STRING(string(FS));
    free_STRING(string(OFMT));
    free_STRING(string(RS));
    cell_destroy(&field[0]);

    for (n = 1; n <= nf; ++n) {
	cell_destroy(&field[n]);
    }

    switch (fs_shadow.type) {
    case C_RE:
	re_destroy(fs_shadow.ptr);
	break;
    case C_STRING:
    case C_STRNUM:
    case C_MBSTRN:
	cell_destroy(&fs_shadow);
	break;
    default:
	break;
    }

    switch (rs_shadow.type) {
    case SEP_STR:
	free_STRING(((STRING *) (&rs_shadow.ptr)));
	break;
    case SEP_RE:
	re_destroy(rs_shadow.ptr);
	break;
    }
}
Пример #13
0
void
set_field0(char *s, size_t len)
{
    cell_destroy(&field[0]);
    nf = -1;

    if (len) {
	field[0].type = C_MBSTRN;
	field[0].ptr = (PTR) new_STRING0(len);
	memcpy(string(&field[0])->str, s, len);
    } else {
	field[0].type = C_STRING;
	field[0].ptr = (PTR) & null_str;
	null_str.ref_cnt++;
    }
}
Пример #14
0
 void cell_list_destroy(void)
{
	struct likewise_cell *p = _lw_cell_list;

	while (p) {
		struct likewise_cell *q = p->next;

		cell_destroy(p);

		p = q;
	}

	_lw_cell_list = NULL;

	return;
}
Пример #15
0
/* Destroys 'table' and frees all associated storage.  (However, the client
 * owns the 'type' members pointed to by cells, so these are not destroyed.) */
void
table_destroy(struct table *table)
{
    if (table) {
        size_t i;

        for (i = 0; i < table->n_columns; i++) {
            free(table->columns[i].heading);
        }
        free(table->columns);

        for (i = 0; i < table->n_columns * table->n_rows; i++) {
            cell_destroy(&table->cells[i]);
        }
        free(table->cells);

        free(table->caption);
    }
}
Пример #16
0
/*  mktime(datespec)
    Turns datespec into a time stamp of the same form as returned by systime().
    The datespec is a string of the form
        YYYY MM DD HH MM SS [DST].
*/
CELL *
bi_mktime(CELL *sp)
{
    time_t result;
    struct tm my_tm;
    STRING *sval = string(sp);
    int error = 0;

    TRACE_FUNC("bi_mktime", sp);

    memset(&my_tm, 0, sizeof(my_tm));
    switch (sscanf(sval->str, "%d %d %d %d %d %d %d",
		   &my_tm.tm_year,
		   &my_tm.tm_mon,
		   &my_tm.tm_mday,
		   &my_tm.tm_hour,
		   &my_tm.tm_min,
		   &my_tm.tm_sec,
		   &my_tm.tm_isdst)) {
    case 7:
	break;
    case 6:
	my_tm.tm_isdst = -1;	/* ask mktime to get timezone */
	break;
    default:
	error = 1;		/* not enough data */
	break;
    }

    if (error) {
	result = -1;
    } else {
	my_tm.tm_year -= 1900;
	my_tm.tm_mon -= 1;
	result = mktime(&my_tm);
    }
    TRACE(("...bi_mktime(%s) ->%s", sval->str, ctime(&result)));

    cell_destroy(sp);
    sp->type = C_DOUBLE;
    sp->dval = (double) result;
    return_CELL("bi_mktime", sp);
}
Пример #17
0
static int cell_management(int argc, char *argv[])
{
	int err;

	if (argc < 3) {
		help(argv[0]);
		exit(1);
	}

	if (strcmp(argv[2], "create") == 0)
		err = cell_create(argc, argv);
	else if (strcmp(argv[2], "destroy") == 0)
		err = cell_destroy(argc, argv);
	else {
		help(argv[0]);
		exit(1);
	}

	return err;
}
Пример #18
0
void array_load(
    ARRAY A,
    size_t cnt)
{
    CELL *cells ; /* storage for A[1..cnt] */
    size_t i ;  /* index into cells[] */
    if (A->type != AY_SPLIT || A->limit < (unsigned) cnt) {
        array_clear(A) ;
        A->limit = (unsigned) ( (cnt & (size_t) ~3) + 4 ) ;
        A->ptr = zmalloc(A->limit*sizeof(CELL)) ;
        A->type = AY_SPLIT ;
    }
    else
    {
        for(i=0; (unsigned) i < A->size; i++)
            cell_destroy((CELL*)A->ptr + i) ;
    }

    cells = (CELL*) A->ptr ;
    A->size = cnt ;
    if (cnt > MAX_SPLIT) {
        SPLIT_OV *p = split_ov_list ;
        SPLIT_OV *q ;
        split_ov_list = (SPLIT_OV*) 0 ;
        i = MAX_SPLIT ;
        while( p ) {
            cells[i].type = C_MBSTRN ;
            cells[i].ptr = (PTR) p->sval ;
            q = p ;
            p = q->link ;
            ZFREE(q) ;
            i++ ;
        }
        cnt = MAX_SPLIT ;
    }

    for(i=0; i < cnt; i++) {
        cells[i].type = C_MBSTRN ;
        cells[i].ptr = split_buff[i] ;
    }
}
Пример #19
0
int 
cell_dispatch_message(struct cell *c) {
	cell_lock(c);
	if (c->quit) {
		cell_destroy(c);
		return CELL_QUIT;
	}
	struct message m;
	int empty = mq_pop(&c->mq, &m);
	if (empty || c->L == NULL) {
		cell_unlock(c);
		return CELL_EMPTY;
	} 
	cell_grab(c);
	cell_unlock(c);
	lua_pushvalue(c->L, 1);	// dup callback
	lua_pushinteger(c->L, m.port);
	lua_pushlightuserdata(c->L, m.buffer);
	lua_call(c->L, 2, 0);
	cell_release(c);

	return CELL_MESSAGE;
}
Пример #20
0
CELL *
bi_sprintf(CELL *sp)
{
    CELL *p;
    int argcnt = sp->type;
    STRING *sval;

    TRACE_FUNC("bi_sprintf", sp);

    sp -= argcnt;        /* sp points at the format string */
    argcnt--;

    if (sp->type != C_STRING)
    cast1_to_s(sp);
    sval = do_printf((FILE *) 0, string(sp)->str, (unsigned) argcnt, sp + 1);
    free_STRING(string(sp));
    sp->ptr = (PTR) sval;

    /* cleanup */
    for (p = sp + 1; argcnt; argcnt--, p++)
    cell_destroy(p);

    return sp;
}
Пример #21
0
void
execute(INST * cdp,		/* code ptr, start execution here */
	CELL *sp,		/* eval_stack pointer */
	CELL *fp)		/* frame ptr into eval_stack for
				   user defined functions */
{
    /* some useful temporaries */
    CELL *cp;
    int t;
    unsigned tu;

    /* save state for array loops via a stack */
    ALOOP_STATE *aloop_state = (ALOOP_STATE *) 0;

    /* for moving the eval stack on deep recursion */
    CELL *old_stack_base = 0;
    CELL *old_sp = 0;

#ifdef	DEBUG
    CELL *entry_sp = sp;
#endif
    int force_exit = (end_start == 0);

    if (fp) {
	/* we are a function call, check for deep recursion */
	if (sp > stack_danger) {	/* change stacks */
	    old_stack_base = stack_base;
	    old_sp = sp;
	    stack_base = (CELL *) zmalloc(sizeof(CELL) * EVAL_STACK_SIZE);
	    stack_danger = stack_base + DANGER;
	    sp = stack_base;
	    /* waste 1 slot for ANSI, actually large model msdos breaks in
	       RET if we don't */
#ifdef	DEBUG
	    entry_sp = sp;
#endif
	} else
	    old_stack_base = (CELL *) 0;
    }

    while (1) {

	TRACE(("execute %s sp(%ld:%s)\n",
	       da_op_name(cdp),
	       (long) (sp - stack_base),
	       da_type_name(sp)));

	switch ((cdp++)->op) {

/* HALT only used by the disassemble now ; this remains
   so compilers don't offset the jump table */
	case _HALT:

	case _STOP:		/* only for range patterns */
#ifdef	DEBUG
	    if (sp != entry_sp + 1)
		bozo("stop0");
#endif
	    return;

	case _PUSHC:
	    inc_sp();
	    cellcpy(sp, (cdp++)->ptr);
	    break;

	case _PUSHD:
	    inc_sp();
	    sp->type = C_DOUBLE;
	    sp->dval = *(double *) (cdp++)->ptr;
	    break;

	case _PUSHS:
	    inc_sp();
	    sp->type = C_STRING;
	    sp->ptr = (cdp++)->ptr;
	    string(sp)->ref_cnt++;
	    break;

	case F_PUSHA:
	    cp = (CELL *) cdp->ptr;
	    if (cp != field) {
		if (nf < 0)
		    split_field0();

		if (!(cp >= NF && cp <= LAST_PFIELD)) {
		    /* it is a real field $1, $2 ...
		       If it is greater than $NF, we have to
		       make sure it is set to ""  so that
		       (++|--) and g?sub() work right
		     */
		    t = field_addr_to_index(cp);
		    if (t > nf) {
			cp->type = C_STRING;
			cp->ptr = (PTR) & null_str;
			null_str.ref_cnt++;
		    }
		}
	    }
	    /* fall thru */

	case _PUSHA:
	case A_PUSHA:
	    inc_sp();
	    sp->ptr = (cdp++)->ptr;
	    break;

	case _PUSHI:
	    /* put contents of next address on stack */
	    inc_sp();
	    cellcpy(sp, (cdp++)->ptr);
	    break;

	case L_PUSHI:
	    /* put the contents of a local var on stack,
	       cdp->op holds the offset from the frame pointer */
	    inc_sp();
	    cellcpy(sp, fp + (cdp++)->op);
	    break;

	case L_PUSHA:
	    /* put a local address on eval stack */
	    inc_sp();
	    sp->ptr = (PTR) (fp + (cdp++)->op);
	    break;

	case F_PUSHI:

	    /* push contents of $i
	       cdp[0] holds & $i , cdp[1] holds i */

	    inc_sp();
	    if (nf < 0)
		split_field0();
	    cp = (CELL *) cdp->ptr;
	    t = (cdp + 1)->op;
	    cdp += 2;

	    if (t <= nf)
		cellcpy(sp, cp);
	    else {		/* an unset field */
		sp->type = C_STRING;
		sp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }
	    break;

	case NF_PUSHI:

	    inc_sp();
	    if (nf < 0)
		split_field0();
	    cellcpy(sp, NF);
	    break;

	case FE_PUSHA:

	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);

	    tu = d_to_index(sp->dval);
	    if (tu && nf < 0)
		split_field0();
	    sp->ptr = (PTR) field_ptr((int) tu);
	    if ((int) tu > nf) {
		/* make sure it is set to "" */
		cp = (CELL *) sp->ptr;
		cell_destroy(cp);
		cp->type = C_STRING;
		cp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }
	    break;

	case FE_PUSHI:

	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);

	    tu = d_to_index(sp->dval);

	    if (nf < 0)
		split_field0();
	    if ((int) tu <= nf) {
		cellcpy(sp, field_ptr((int) tu));
	    } else {
		sp->type = C_STRING;
		sp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }
	    break;

	case AE_PUSHA:
	    /* top of stack has an expr, cdp->ptr points at an
	       array, replace the expr with the cell address inside
	       the array */

	    cp = array_find((ARRAY) (cdp++)->ptr, sp, CREATE);
	    cell_destroy(sp);
	    sp->ptr = (PTR) cp;
	    break;

	case AE_PUSHI:
	    /* top of stack has an expr, cdp->ptr points at an
	       array, replace the expr with the contents of the
	       cell inside the array */

	    cp = array_find((ARRAY) (cdp++)->ptr, sp, CREATE);
	    cell_destroy(sp);
	    cellcpy(sp, cp);
	    break;

	case LAE_PUSHI:
	    /*  sp[0] is an expression
	       cdp->op is offset from frame pointer of a CELL which
	       has an ARRAY in the ptr field, replace expr
	       with  array[expr]
	     */
	    if (fp != 0) {
		cp = array_find((ARRAY) fp[(cdp++)->op].ptr, sp, CREATE);
		cell_destroy(sp);
		cellcpy(sp, cp);
	    }
	    break;

	case LAE_PUSHA:
	    /*  sp[0] is an expression
	       cdp->op is offset from frame pointer of a CELL which
	       has an ARRAY in the ptr field, replace expr
	       with  & array[expr]
	     */
	    if (fp != 0) {
		cp = array_find((ARRAY) fp[(cdp++)->op].ptr, sp, CREATE);
		cell_destroy(sp);
		sp->ptr = (PTR) cp;
	    }
	    break;

	case LA_PUSHA:
	    /*  cdp->op is offset from frame pointer of a CELL which
	       has an ARRAY in the ptr field. Push this ARRAY
	       on the eval stack
	     */
	    if (fp != 0) {
		inc_sp();
		sp->ptr = fp[(cdp++)->op].ptr;
	    }
	    break;

	case SET_ALOOP:
	    {
		ALOOP_STATE *ap = ZMALLOC(ALOOP_STATE);
		size_t vector_size;

		ap->var = (CELL *) sp[-1].ptr;
		ap->base = ap->ptr = array_loop_vector((ARRAY) sp->ptr, &vector_size);
		ap->limit = ap->base + vector_size;
		sp -= 2;

		/* push onto aloop stack */
		ap->link = aloop_state;
		aloop_state = ap;
		cdp += cdp->op;
	    }
	    break;

	case ALOOP:
	    {
		ALOOP_STATE *ap = aloop_state;
		if (ap != 0 && (ap->ptr < ap->limit)) {
		    cell_destroy(ap->var);
		    ap->var->type = C_STRING;
		    ap->var->ptr = (PTR) * ap->ptr++;
		    cdp += cdp->op;
		} else {
		    cdp++;
		}
	    }
	    break;

	case POP_AL:
	    {
		/* finish up an array loop */
		ALOOP_STATE *ap = aloop_state;
		if (ap != 0) {
		    aloop_state = ap->link;
		    while (ap->ptr < ap->limit) {
			free_STRING(*ap->ptr);
			ap->ptr++;
		    }
		    if (ap->base < ap->limit) {
			zfree(ap->base,
			      ((unsigned) (ap->limit - ap->base)
			       * sizeof(STRING *)));
		    }
		    ZFREE(ap);
		}
	    }
	    break;

	case _POP:
	    cell_destroy(sp);
	    sp--;
	    break;

	case _ASSIGN:
	    /* top of stack has an expr, next down is an
	       address, put the expression in *address and
	       replace the address with the expression */

	    /* don't propagate type C_MBSTRN */
	    if (sp->type == C_MBSTRN)
		check_strnum(sp);
	    sp--;
	    cell_destroy(((CELL *) sp->ptr));
	    cellcpy(sp, cellcpy(sp->ptr, sp + 1));
	    cell_destroy(sp + 1);
	    break;

	case F_ASSIGN:
	    /* assign to a field  */
	    if (sp->type == C_MBSTRN)
		check_strnum(sp);
	    sp--;
	    field_assign((CELL *) sp->ptr, sp + 1);
	    cell_destroy(sp + 1);
	    cellcpy(sp, (CELL *) sp->ptr);
	    break;

	case _ADD_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);

#ifdef SW_FP_CHECK		/* specific to V7 and XNX23A */
	    clrerr();
#endif
	    cp->dval += (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	case _SUB_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    cp->dval -= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	case _MUL_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    cp->dval *= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	case _DIV_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp->dval);
#endif

#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    cp->dval /= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	case _MOD_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp->dval);
#endif

	    cp->dval = fmod(cp->dval, (sp--)->dval);
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	case _POW_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
	    cp->dval = pow(cp->dval, (sp--)->dval);
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    break;

	    /* will anyone ever use these ? */

	case F_ADD_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    tc.dval += (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case F_SUB_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    tc.dval -= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case F_MUL_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    tc.dval *= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case F_DIV_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp->dval);
#endif

#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    tc.dval /= (sp--)->dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case F_MOD_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp->dval);
#endif

	    tc.dval = fmod(tc.dval, (sp--)->dval);
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case F_POW_ASG:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    cp = (CELL *) (sp - 1)->ptr;
	    cast1_to_d(cellcpy(&tc, cp));
	    tc.dval = pow(tc.dval, (sp--)->dval);
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    field_assign(cp, &tc);
	    break;

	case _ADD:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    sp[0].dval += sp[1].dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    break;

	case _SUB:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    sp[0].dval -= sp[1].dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    break;

	case _MUL:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);
#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    sp[0].dval *= sp[1].dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    break;

	case _DIV:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp[1].dval);
#endif

#ifdef SW_FP_CHECK
	    clrerr();
#endif
	    sp[0].dval /= sp[1].dval;
#ifdef SW_FP_CHECK
	    fpcheck();
#endif
	    break;

	case _MOD:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);

#ifdef  NOINFO_SIGFPE
	    CHECK_DIVZERO(sp[1].dval);
#endif

	    sp[0].dval = fmod(sp[0].dval, sp[1].dval);
	    break;

	case _POW:
	    sp--;
	    if (TEST2(sp) != TWO_DOUBLES)
		cast2_to_d(sp);
	    sp[0].dval = pow(sp[0].dval, sp[1].dval);
	    break;

	case _NOT:
	    /* evaluates to 0.0 or 1.0 */
	  reswitch_1:
	    switch (sp->type) {
	    case C_NOINIT:
		sp->dval = 1.0;
		break;
	    case C_DOUBLE:
		sp->dval = sp->dval != 0.0 ? 0.0 : 1.0;
		break;
	    case C_FIELDWIDTHS:
	    case C_STRING:
		sp->dval = string(sp)->len ? 0.0 : 1.0;
		free_STRING(string(sp));
		break;
	    case C_STRNUM:	/* test as a number */
		sp->dval = sp->dval != 0.0 ? 0.0 : 1.0;
		free_STRING(string(sp));
		break;
	    case C_MBSTRN:
		check_strnum(sp);
		goto reswitch_1;
	    default:
		bozo("bad type on eval stack");
	    }
	    sp->type = C_DOUBLE;
	    break;

	case _TEST:
	    /* evaluates to 0.0 or 1.0 */
	  reswitch_2:
	    switch (sp->type) {
	    case C_NOINIT:
		sp->dval = 0.0;
		break;
	    case C_DOUBLE:
		sp->dval = sp->dval != 0.0 ? 1.0 : 0.0;
		break;
	    case C_FIELDWIDTHS:
	    case C_STRING:
		sp->dval = string(sp)->len ? 1.0 : 0.0;
		free_STRING(string(sp));
		break;
	    case C_STRNUM:	/* test as a number */
		sp->dval = sp->dval != 0.0 ? 1.0 : 0.0;
		free_STRING(string(sp));
		break;
	    case C_MBSTRN:
		check_strnum(sp);
		goto reswitch_2;
	    default:
		bozo("bad type on eval stack");
	    }
	    sp->type = C_DOUBLE;
	    break;

	case _UMINUS:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    sp->dval = -sp->dval;
	    break;

	case _UPLUS:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    break;

	case _CAT:
	    {
		size_t len1, len2;
		char *str1, *str2;
		STRING *b;

		sp--;
		if (TEST2(sp) != TWO_STRINGS)
		    cast2_to_s(sp);
		str1 = string(sp)->str;
		len1 = string(sp)->len;
		str2 = string(sp + 1)->str;
		len2 = string(sp + 1)->len;

		b = new_STRING0(len1 + len2);
		memcpy(b->str, str1, len1);
		memcpy(b->str + len1, str2, len2);
		free_STRING(string(sp));
		free_STRING(string(sp + 1));

		sp->ptr = (PTR) b;
		break;
	    }

	case _PUSHINT:
	    inc_sp();
	    sp->type = (short) (cdp++)->op;
	    break;

	case _BUILTIN:
	case _PRINT:
	    sp = (*(PF_CP) (cdp++)->ptr) (sp);
	    break;

	case _POST_INC:
	    cp = (CELL *) sp->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    cp->dval += 1.0;
	    break;

	case _POST_DEC:
	    cp = (CELL *) sp->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
	    sp->type = C_DOUBLE;
	    sp->dval = cp->dval;
	    cp->dval -= 1.0;
	    break;

	case _PRE_INC:
	    cp = (CELL *) sp->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
	    sp->dval = cp->dval += 1.0;
	    sp->type = C_DOUBLE;
	    break;

	case _PRE_DEC:
	    cp = (CELL *) sp->ptr;
	    if (cp->type != C_DOUBLE)
		cast1_to_d(cp);
	    sp->dval = cp->dval -= 1.0;
	    sp->type = C_DOUBLE;
	    break;

	case F_POST_INC:
	    cp = (CELL *) sp->ptr;
	    cellcpy(&tc, cp);
	    cast1_to_d(&tc);
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    tc.dval += 1.0;
	    field_assign(cp, &tc);
	    break;

	case F_POST_DEC:
	    cp = (CELL *) sp->ptr;
	    cellcpy(&tc, cp);
	    cast1_to_d(&tc);
	    sp->type = C_DOUBLE;
	    sp->dval = tc.dval;
	    tc.dval -= 1.0;
	    field_assign(cp, &tc);
	    break;

	case F_PRE_INC:
	    cp = (CELL *) sp->ptr;
	    cast1_to_d(cellcpy(sp, cp));
	    sp->dval += 1.0;
	    field_assign(cp, sp);
	    break;

	case F_PRE_DEC:
	    cp = (CELL *) sp->ptr;
	    cast1_to_d(cellcpy(sp, cp));
	    sp->dval -= 1.0;
	    field_assign(cp, sp);
	    break;

	case _JMP:
	    cdp += cdp->op;
	    break;

	case _JNZ:
	    /* jmp if top of stack is non-zero and pop stack */
	    if (test(sp))
		cdp += cdp->op;
	    else
		cdp++;
	    cell_destroy(sp);
	    sp--;
	    break;

	case _JZ:
	    /* jmp if top of stack is zero and pop stack */
	    if (!test(sp))
		cdp += cdp->op;
	    else
		cdp++;
	    cell_destroy(sp);
	    sp--;
	    break;

	case _LJZ:
	    /* special jump for logical and */
	    /* this is always preceded by _TEST */
	    if (sp->dval == 0.0) {
		/* take jump, but don't pop stack */
		cdp += cdp->op;
	    } else {
		/* pop and don't jump */
		sp--;
		cdp++;
	    }
	    break;

	case _LJNZ:
	    /* special jump for logical or */
	    /* this is always preceded by _TEST */
	    if (sp->dval != 0.0) {
		/* take jump, but don't pop stack */
		cdp += cdp->op;
	    } else {
		/* pop and don't jump */
		sp--;
		cdp++;
	    }
	    break;

	    /*  the relation operations */
	    /*  compare() makes sure string ref counts are OK */
	case _EQ:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t == 0 ? 1.0 : 0.0;
	    break;

	case _NEQ:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t ? 1.0 : 0.0;
	    break;

	case _LT:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t < 0 ? 1.0 : 0.0;
	    break;

	case _LTE:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t <= 0 ? 1.0 : 0.0;
	    break;

	case _GT:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t > 0 ? 1.0 : 0.0;
	    break;

	case _GTE:
	    t = compare(--sp);
	    sp->type = C_DOUBLE;
	    sp->dval = t >= 0 ? 1.0 : 0.0;
	    break;

	case _MATCH0:
	    /* does $0 match, the RE at cdp? */

	    inc_sp();
	    if (field->type >= C_STRING) {
		sp->type = C_DOUBLE;
		sp->dval = (REtest(string(field)->str,
				   string(field)->len,
				   cast_to_re((cdp++)->ptr))
			    ? 1.0
			    : 0.0);

		break /* the case */ ;
	    } else {
		cellcpy(sp, field);
		/* and FALL THRU */
	    }

	case _MATCH1:
	    /* does expr at sp[0] match RE at cdp */
	    if (sp->type < C_STRING)
		cast1_to_s(sp);
	    t = REtest(string(sp)->str,
		       string(sp)->len,
		       cast_to_re((cdp++)->ptr));
	    free_STRING(string(sp));
	    sp->type = C_DOUBLE;
	    sp->dval = t ? 1.0 : 0.0;
	    break;

	case _MATCH2:
	    /* does sp[-1] match sp[0] as re */
	    cast_to_RE(sp);

	    if ((--sp)->type < C_STRING)
		cast1_to_s(sp);
	    t = REtest(string(sp)->str,
		       string(sp)->len,
		       cast_to_re((sp + 1)->ptr));

	    free_STRING(string(sp));
	    no_leaks_re_ptr((sp + 1)->ptr);
	    sp->type = C_DOUBLE;
	    sp->dval = t ? 1.0 : 0.0;
	    break;

	case A_LENGTH:
	    sp--;
	    sp->type = C_DOUBLE;
	    sp->dval = (double) (((ARRAY) ((sp + 0)->ptr))->size);
	    break;

	case A_TEST:
	    /* entry :  sp[0].ptr-> an array
	       sp[-1]  is an expression

	       we compute       (expression in array)  */
	    sp--;
	    cp = array_find((sp + 1)->ptr, sp, NO_CREATE);
	    cell_destroy(sp);
	    sp->type = C_DOUBLE;
	    sp->dval = (cp != (CELL *) 0) ? 1.0 : 0.0;
	    break;

	case A_DEL:
	    /* sp[0].ptr ->  array
	       sp[-1] is an expr
	       delete  array[expr]      */

	    array_delete(sp->ptr, sp - 1);
	    cell_destroy(sp - 1);
	    sp -= 2;
	    break;

	case DEL_A:
	    /* free all the array at once */
	    array_clear(sp->ptr);
	    sp--;
	    break;

	    /* form a multiple array index */
	case A_CAT:
	    sp = array_cat(sp, (cdp++)->op);
	    break;

	case _EXIT:
	    if (sp->type != C_DOUBLE)
		cast1_to_d(sp);
	    exit_code = d_to_i(sp->dval);
	    sp--;
	    /* fall thru */

	case _EXIT0:

	    if (force_exit)
		mawk_exit(exit_code);

	    cdp = end_start;
	    force_exit = 1;	/* makes sure next exit exits */

	    if (begin_start) {
		free_codes("BEGIN", begin_start, begin_size);
		begin_start = 0;
		begin_size = 0;
	    }
	    if (main_start) {
		free_codes("MAIN", main_start, main_size);
		main_start = 0;
		main_size = 0;
	    }
	    sp = eval_stack - 1;	/* might be in user function */
	    CLEAR_ALOOP_STACK();	/* ditto */
	    break;

	case _JMAIN:		/* go from BEGIN code to MAIN code */
	    free_codes("BEGIN", begin_start, begin_size);
	    begin_start = 0;
	    begin_size = 0;
	    cdp = main_start;
	    break;

	case _OMAIN:
	    if (!main_fin)
		open_main();
	    restart_label = cdp;
	    cdp = next_label;
	    break;

	case _NEXT:
	    /* next might be inside an aloop -- clear stack */
	    CLEAR_ALOOP_STACK();
	    cdp = next_label;
	    break;

	case _NEXTFILE:
	    /* nextfile might be inside an aloop -- clear stack */
	    CLEAR_ALOOP_STACK();
	    FINsemi_close(main_fin);
	    cdp = next_label;
	    break;

	case OL_GL:
	    {
		char *p;
		size_t len;

		if (!(p = FINgets(main_fin, &len))) {
		    if (force_exit)
			mawk_exit(0);

		    cdp = end_start;
		    zfree(main_start, main_size);
		    main_start = (INST *) 0;
		    force_exit = 1;
		} else {
		    set_field0(p, len);
		    cdp = restart_label;
		    rt_nr++;
		    rt_fnr++;
		}
	    }
	    break;

	    /* two kinds of OL_GL is a historical stupidity from working on
	       a machine with very slow floating point emulation */
	case OL_GL_NR:
	    {
		char *p;
		size_t len;

		if (!(p = FINgets(main_fin, &len))) {
		    if (force_exit)
			mawk_exit(0);

		    cdp = end_start;
		    zfree(main_start, main_size);
		    main_start = (INST *) 0;
		    force_exit = 1;
		} else {
		    set_field0(p, len);
		    cdp = restart_label;

		    if (TEST2(NR) != TWO_DOUBLES)
			cast2_to_d(NR);

		    NR->dval += 1.0;
		    rt_nr++;
		    FNR->dval += 1.0;
		    rt_fnr++;
		}
	    }
	    break;

	case _RANGE:
/* test a range pattern:  pat1, pat2 { action }
   entry :
       cdp[0].op -- a flag, test pat1 if on else pat2
       cdp[1].op -- offset of pat2 code from cdp
       cdp[2].op -- offset of action code from cdp
       cdp[3].op -- offset of code after the action from cdp
       cdp[4] -- start of pat1 code
*/

#define FLAG      cdp[0].op
#define PAT2      cdp[1].op
#define ACTION    cdp[2].op
#define FOLLOW    cdp[3].op
#define PAT1      4

	    if (FLAG)		/* test against pat1 */
	    {
		execute(cdp + PAT1, sp, fp);
		t = test(sp + 1);
		cell_destroy(sp + 1);
		if (t)
		    FLAG = 0;
		else {
		    cdp += FOLLOW;
		    break;	/* break the switch */
		}
	    }

	    /* test against pat2 and then perform the action */
	    execute(cdp + PAT2, sp, fp);
	    FLAG = test(sp + 1);
	    cell_destroy(sp + 1);
	    cdp += ACTION;
	    break;

/* function calls  */

	case _RET0:
	    inc_sp();
	    sp->type = C_NOINIT;
	    /* fall thru */

	case _RET:

#ifdef	DEBUG
	    if (sp != entry_sp + 1)
		bozo("ret");
#endif
	    if (old_stack_base)	/* reset stack */
	    {
		/* move the return value */
		cellcpy(old_sp + 1, sp);
		cell_destroy(sp);
		zfree(stack_base, sizeof(CELL) * EVAL_STACK_SIZE);
		stack_base = old_stack_base;
		stack_danger = old_stack_base + DANGER;
	    }

	    /* return might be inside an aloop -- clear stack */
	    CLEAR_ALOOP_STACK();

	    return;

	case _CALL:

	    /*  cdp[0] holds ptr to "function block"
	       cdp[1] holds number of input arguments
	     */

	    {
		FBLOCK *fbp = (FBLOCK *) (cdp++)->ptr;
		int a_args = (cdp++)->op;	/* actual number of args */
		CELL *nfp = sp - a_args + 1;	/* new fp for callee */
		CELL *local_p = sp + 1;		/* first local argument on stack */
		char *type_p = 0;	/* pts to type of an argument */

		if (fbp->nargs)
		    type_p = fbp->typev + a_args - 1;

		/* create space for locals */
		t = fbp->nargs - a_args;	/* t is number of locals */
		while (t > 0) {
		    t--;
		    sp++;
		    type_p++;
		    sp->type = C_NOINIT;
		    if ((type_p) != 0 && (*type_p == ST_LOCAL_ARRAY))
			sp->ptr = (PTR) new_ARRAY();
		}

		execute(fbp->code, sp, nfp);

		/* cleanup the callee's arguments */
		/* putting return value at top of eval stack */
		if ((type_p != 0) && (sp >= nfp)) {
		    cp = sp + 1;	/* cp -> the function return */

		    do {
			if (*type_p == ST_LOCAL_ARRAY) {
			    if (sp >= local_p) {
				array_clear(sp->ptr);
				ZFREE((ARRAY) sp->ptr);
			    }
			} else {
			    cell_destroy(sp);
			}

			type_p--;
			sp--;

		    }
		    while (sp >= nfp);

		    cellcpy(++sp, cp);
		    cell_destroy(cp);
		} else
		    sp++;	/* no arguments passed */
	    }
	    break;

	default:
	    bozo("bad opcode");
	}
    }
}
Пример #22
0
void array_delete(
    ARRAY A,
    CELL *cp)
{
    ANODE *ap ;
    int redid ;
    if (A->size == 0) return ;
    switch(cp->type) {
    case C_DOUBLE :
    {
        double d = cp->dval ;
        Int ival = d_to_I(d) ;
        if ((double)ival == d) {
            if (A->type == AY_SPLIT)
            {
                if (ival >=1 && ival <= (int) A->size)
                    convert_split_array_to_table(A) ;
                else return ; /* ival not in range */
            }
            ap = find_by_ival(A, ival, NO_CREATE, &redid) ;
            if (ap) { /* remove from the front of the ilist */
                DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
                table[(unsigned) ap->ival & A->hmask].ilink = ap->ilink ;
                if (ap->sval) {
                    ANODE *p, *q = 0 ;
                    unsigned indx = (unsigned) ap->hval & A->hmask ;
                    p = table[indx].slink ;
                    while(p != ap) {
                        q = p ;
                        p = q->slink ;
                    }
                    if (q) q->slink = p->slink ;
                    else table[indx].slink = p->slink ;
                    free_STRING(ap->sval) ;
                }

                cell_destroy(&ap->cell) ;
                ZFREE(ap) ;
                if (--A->size == 0) array_clear(A) ;


            }
            return ;
        }

        else { /* get the string value */
            char buff[260] ;
            STRING *sval ;
            sprintf(buff, string(CONVFMT)->str, d) ;
            sval = new_STRING(buff) ;
            ap = find_by_sval(A, sval, NO_CREATE, &redid) ;
            free_STRING(sval) ;
        }
    }
    break ;
    case C_NOINIT :
        ap = find_by_sval(A, &null_str, NO_CREATE, &redid) ;
        break ;
    default :
        ap = find_by_sval(A, string(cp), NO_CREATE, &redid) ;
        break ;
    }
    if (ap) { /* remove from the front of the slist */
        DUAL_LINK *table = (DUAL_LINK*) A->ptr ;
        table[ap->hval & A->hmask].slink = ap->slink ;
        if (ap->ival != NOT_AN_IVALUE) {
            ANODE *p, *q = 0 ;
            unsigned indx = (unsigned) ap->ival & A->hmask ;
            p = table[indx].ilink ;
            while(p != ap) {
                q = p ;
                p = q->ilink ;
            }
            if (q) q->ilink = p->ilink ;
            else table[indx].ilink = p->ilink ;
        }

        free_STRING(ap->sval) ;
        cell_destroy(&ap->cell) ;
        ZFREE(ap) ;
        if (--A->size == 0) array_clear(A) ;


    }
}
Пример #23
0
void
field_assign(CELL * fp, CELL * cp)
{
    CELL c;
    int i, j;

    /* the most common case first */
    if (fp == field) {
	cell_destroy(field);
	cellcpy(fp, cp);
	nf = -1;
	return;
    }

    /* its not important to do any of this fast */

    if (nf < 0)
	split_field0();

#ifdef  MSDOS
    if (!SAMESEG(fp, field)) {
	i = -1;
	goto lm_dos_label;
    }
#endif

    switch (i = (int) (fp - field)) {

    case NF_field:

	cell_destroy(NF);
	cellcpy(NF, cellcpy(&c, cp));
	if (c.type != C_DOUBLE)
	    cast1_to_d(&c);

	if ((j = d_to_i(c.dval)) < 0)
	    rt_error("negative value assigned to NF");

	if (j > nf)
	    for (i = nf + 1; i <= j; i++) {
		cp = field_ptr(i);
		cell_destroy(cp);
		cp->type = C_STRING;
		cp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }

	nf = j;
	build_field0();
	break;

    case RS_field:
	cell_destroy(RS);
	cellcpy(RS, cp);
	set_rs_shadow();
	break;

    case FS_field:
	cell_destroy(FS);
	cast_for_split(cellcpy(&fs_shadow, cellcpy(FS, cp)));
	break;

    case OFMT_field:
    case CONVFMT_field:
	/* If the user does something stupid with OFMT or CONVFMT,
	   we could crash.
	   We'll make an attempt to protect ourselves here.  This is
	   why OFMT and CONVFMT are pseudo fields.

	   The ptrs of OFMT and CONVFMT always have a valid STRING,
	   even if assigned a DOUBLE or NOINIT
	 */

	free_STRING(string(fp));
	cellcpy(fp, cp);
	if (fp->type < C_STRING)	/* !! */
	    fp->ptr = (PTR) new_STRING("%.6g");
	else if (fp == CONVFMT) {
	    /* It's a string, but if it's really goofy and CONVFMT,
	       it could still damage us. Test it .
	     */
	    char xbuff[512];

	    xbuff[256] = 0;
	    sprintf(xbuff, string(fp)->str, 3.1459);
	    if (xbuff[256])
		rt_error("CONVFMT assigned unusable value");
	}
	break;

#ifdef MSDOS
      lm_dos_label:
#endif

    default:			/* $1 or $2 or ... */

	cell_destroy(fp);
	cellcpy(fp, cp);

	if (i < 0 || i > MAX_SPLIT)
	    i = field_addr_to_index(fp);

	if (i > nf) {
	    for (j = nf + 1; j < i; j++) {
		cp = field_ptr(j);
		cell_destroy(cp);
		cp->type = C_STRING;
		cp->ptr = (PTR) & null_str;
		null_str.ref_cnt++;
	    }
	    nf = i;
	    cell_destroy(NF);
	    NF->type = C_DOUBLE;
	    NF->dval = (double) i;
	}

	build_field0();

    }
}
Пример #24
0
static void
build_field0(void)
{

#ifdef DEBUG
    if (nf < 0)
	bozo("nf <0 in build_field0");
#endif

    cell_destroy(field + 0);

    if (nf == 0) {
	field[0].type = C_STRING;
	field[0].ptr = (PTR) & null_str;
	null_str.ref_cnt++;
    } else if (nf == 1) {
	cellcpy(field, field + 1);
    } else {
	CELL c;
	STRING *ofs, *tail;
	size_t len;
	register CELL *cp;
	register char *p, *q;
	int cnt;
	CELL **fbp, *cp_limit;

	cast1_to_s(cellcpy(&c, OFS));
	ofs = (STRING *) c.ptr;
	cast1_to_s(cellcpy(&c, field_ptr(nf)));
	tail = (STRING *) c.ptr;
	cnt = nf - 1;

	len = ((size_t) cnt) * ofs->len + tail->len;

	fbp = fbank;
	cp_limit = field + FBANK_SZ;
	cp = field + 1;

	while (cnt-- > 0) {
	    if (cp->type < C_STRING) {	/* use the string field temporarily */
		if (cp->type == C_NOINIT) {
		    cp->ptr = (PTR) & null_str;
		    null_str.ref_cnt++;
		} else {	/* its a double */
		    Int ival;
		    char xbuff[260];

		    ival = d_to_I(cp->dval);
		    if (ival == cp->dval)
			sprintf(xbuff, INT_FMT, ival);
		    else
			sprintf(xbuff, string(CONVFMT)->str, cp->dval);

		    cp->ptr = (PTR) new_STRING(xbuff);
		}
	    }

	    len += string(cp)->len;

	    if (++cp == cp_limit) {
		cp = *++fbp;
		cp_limit = cp + FBANK_SZ;
	    }

	}

	field[0].type = C_STRING;
	field[0].ptr = (PTR) new_STRING0(len);

	p = string(field)->str;

	/* walk it again , putting things together */
	cnt = nf - 1;
	fbp = fbank;
	cp = field + 1;
	cp_limit = field + FBANK_SZ;
	while (cnt-- > 0) {
	    memcpy(p, string(cp)->str, string(cp)->len);
	    p += string(cp)->len;
	    /* if not really string, free temp use of ptr */
	    if (cp->type < C_STRING) {
		free_STRING(string(cp));
	    }
	    if (++cp == cp_limit) {
		cp = *++fbp;
		cp_limit = cp + FBANK_SZ;
	    }
	    /* add the separator */
	    q = ofs->str;
	    while (*q)
		*p++ = *q++;
	}
	/* tack tail on the end */
	memcpy(p, tail->str, tail->len);

	/* cleanup */
	free_STRING(tail);
	free_STRING(ofs);
    }
}
Пример #25
0
CELL *
bi_substr(CELL *sp)
{
    int n_args, len;
    register int i, n;
    STRING *sval;		/* substr(sval->str, i, n) */

    TRACE_FUNC("bi_substr", sp);

    n_args = sp->type;
    sp -= n_args;
    if (sp->type != C_STRING)
	cast1_to_s(sp);
    /* don't use < C_STRING shortcut */
    sval = string(sp);

    if ((len = (int) sval->len) == 0)	/* substr on null string */
    {
	if (n_args == 3) {
	    cell_destroy(sp + 2);
	}
	cell_destroy(sp + 1);
	return_CELL("bi_substr", sp);
    }

    if (n_args == 2) {
	n = len;
	if (sp[1].type != C_DOUBLE) {
	    cast1_to_d(sp + 1);
	}
    } else {
	if (TEST2(sp + 1) != TWO_DOUBLES)
	    cast2_to_d(sp + 1);
	n = d_to_i(sp[2].dval);
    }
    i = d_to_i(sp[1].dval) - 1;	/* i now indexes into string */

    /*
     * If the starting index is past the end of the string, there is nothing
     * to extract other than an empty string.
     */
    if (i > len) {
	n = 0;
    }

    /*
     * Workaround in case someone's written a script that does substr(0,last-1)
     * by transforming it into substr(1,last).
     */
    if (i < 0) {
	n -= i + 1;
	i = 0;
    }

    /*
     * Keep 'n' from extending past the end of the string.
     */
    if (n > len - i) {
	n = len - i;
    }

    if (n <= 0)			/* the null string */
    {
	sp->ptr = (PTR) & null_str;
	null_str.ref_cnt++;
    } else {			/* got something */
	sp->ptr = (PTR) new_STRING0((size_t) n);
	memcpy(string(sp)->str, sval->str + i, (size_t) n);
    }

    free_STRING(sval);
    return_CELL("bi_substr", sp);
}
Пример #26
0
static void
process_cmdline(int argc, char **argv)
{
    int i, j, nextarg;
    char *optArg;
    char *optNext;
    PFILE dummy;		/* starts linked list of filenames */
    PFILE *tail = &dummy;
    size_t length;

    if (argc <= 1)
	usage();

    for (i = 1; i < argc && argv[i][0] == '-'; i = nextarg) {
	if (argv[i][1] == 0)	/* -  alone */
	{
	    if (!pfile_name)
		no_program();
	    break;		/* the for loop */
	}
	/* safe to look at argv[i][2] */

	/*
	 * Check for "long" options and decide how to handle them.
	 */
	if (strlen(argv[i]) > 2 && !strncmp(argv[i], "--", (size_t) 2)) {
	    if (!allow_long_options(argv[i])) {
		nextarg = i + 1;
		continue;
	    }
	}

	if (argv[i][2] == 0) {
	    if (i == argc - 1 && argv[i][1] != '-') {
		if (strchr("WFvf", argv[i][1])) {
		    errmsg(0, "option %s lacks argument", argv[i]);
		    mawk_exit(2);
		}
		bad_option(argv[i]);
	    }

	    optArg = argv[i + 1];
	    nextarg = i + 2;
	} else {		/* argument glued to option */
	    optArg = &argv[i][2];
	    nextarg = i + 1;
	}

	switch (argv[i][1]) {

	case 'W':
	    for (j = 0; j < (int) strlen(optArg); j = (int) (optNext - optArg)) {
		switch (parse_w_opt(optArg + j, &optNext)) {
		case W_VERSION:
		    print_version();
		    break;
#if USE_BINMODE
		case W_BINMODE:
		    if (haveValue(optNext)) {
			set_binmode(atoi(optNext + 1));
			optNext = skipValue(optNext);
		    } else {
			errmsg(0, "missing value for -W binmode");
			mawk_exit(2);
		    }
		    break;
#endif
		case W_DUMP:
		    dump_code_flag = 1;
		    break;

		case W_EXEC:
		    if (pfile_name) {
			errmsg(0, "-W exec is incompatible with -f");
			mawk_exit(2);
		    } else if (nextarg == argc) {
			no_program();
		    }
		    if (haveValue(optNext)) {
			pfile_name = optNext + 1;
			i = nextarg;
		    } else {
			pfile_name = argv[nextarg];
			i = nextarg + 1;
		    }
		    goto no_more_opts;

		case W_INTERACTIVE:
		    interactive_flag = 1;
		    setbuf(stdout, (char *) 0);
		    break;

		case W_POSIX_SPACE:
		    posix_space_flag = 1;
		    break;

		case W_RANDOM:
		    if (haveValue(optNext)) {
			int x = atoi(optNext + 1);
			CELL c[2];

			memset(c, 0, sizeof(c));
			c[1].type = C_DOUBLE;
			c[1].dval = (double) x;
			/* c[1] is input, c[0] is output */
			bi_srand(c + 1);
			optNext = skipValue(optNext);
		    } else {
			errmsg(0, "missing value for -W random");
			mawk_exit(2);
		    }
		    break;

		case W_SPRINTF:
		    if (haveValue(optNext)) {
			int x = atoi(optNext + 1);

			if (x > (int) sizeof(string_buff)) {
			    if (sprintf_buff != string_buff &&
				sprintf_buff != 0) {
				zfree(sprintf_buff,
				      (size_t) (sprintf_limit - sprintf_buff));
			    }
			    sprintf_buff = (char *) zmalloc((size_t) x);
			    sprintf_limit = sprintf_buff + x;
			}
			optNext = skipValue(optNext);
		    } else {
			errmsg(0, "missing value for -W sprintf");
			mawk_exit(2);
		    }
		    break;

		case W_HELP:
		    /* FALLTHRU */
		case W_USAGE:
		    usage();
		    /* NOTREACHED */
		    break;
		case W_UNKNOWN:
		    errmsg(0, "vacuous option: -W %s", optArg + j);
		    break;
		}
		while (*optNext == '=') {
		    errmsg(0, "unexpected option value %s", optArg + j);
		    optNext = skipValue(optNext);
		}
	    }
	    break;

	case 'v':
	    if (!is_cmdline_assign(optArg)) {
		errmsg(0, "improper assignment: -v %s", optArg);
		mawk_exit(2);
	    }
	    break;

	case 'F':

	    rm_escape(optArg, &length);		/* recognize escape sequences */
	    cell_destroy(FS);
	    FS->type = C_STRING;
	    FS->ptr = (PTR) new_STRING1(optArg, length);
	    cast_for_split(cellcpy(&fs_shadow, FS));
	    break;

	case '-':
	    if (argv[i][2] != 0) {
		bad_option(argv[i]);
	    }
	    i++;
	    goto no_more_opts;

	case 'f':
	    /* first file goes in pfile_name ; any more go
	       on a list */
	    if (!pfile_name)
		pfile_name = optArg;
	    else {
		tail = tail->link = ZMALLOC(PFILE);
		tail->fname = optArg;
	    }
	    break;

	default:
	    bad_option(argv[i]);
	}
    }

  no_more_opts:

    tail->link = (PFILE *) 0;
    pfile_list = dummy.link;

    if (pfile_name) {
	set_ARGV(argc, argv, i);
	scan_init((char *) 0);
    } else {			/* program on command line */
	if (i == argc)
	    no_program();
	set_ARGV(argc, argv, i + 1);

#if  defined(MSDOS) && ! HAVE_REARGV	/* reversed quotes */
	{
	    char *p;

	    for (p = argv[i]; *p; p++)
		if (*p == '\'')
		    *p = '\"';
	}
#endif
	scan_init(argv[i]);
/* #endif  */
    }
}
Пример #27
0
CELL *
bi_strftime(CELL *sp)
{
    const char *format = "%c";
    time_t rawtime;
    struct tm *ptm;
    int n_args;
    int utc;
    STRING *sval = 0;		/* strftime(sval->str, timestamp, utc) */
    char buff[128];
    size_t result;

    TRACE_FUNC("bi_strftime", sp);

    n_args = sp->type;
    sp -= n_args;

    if (n_args > 0) {
	if (sp->type != C_STRING)
	    cast1_to_s(sp);
	/* don't use < C_STRING shortcut */
	sval = string(sp);

	if ((int) sval->len != 0)	/* strftime on valid format */
	    format = sval->str;
    } else {
	sp->type = C_STRING;
    }

    if (n_args > 1) {
	if (sp[1].type != C_DOUBLE)
	    cast1_to_d(sp + 1);
	rawtime = d_to_i(sp[1].dval);
    } else {
	time(&rawtime);
    }

    if (n_args > 2) {
	if (sp[2].type != C_DOUBLE)
	    cast1_to_d(sp + 2);
	utc = d_to_i(sp[2].dval);
    } else {
	utc = 0;
    }

    if (utc != 0)
	ptm = gmtime(&rawtime);
    else
	ptm = localtime(&rawtime);

    result = strftime(buff, sizeof(buff) / sizeof(buff[0]), format, ptm);
    TRACE(("...bi_strftime (%s, \"%d.%d.%d %d.%d.%d %d\", %d) ->%s\n",
	   format,
	   ptm->tm_year,
	   ptm->tm_mon,
	   ptm->tm_mday,
	   ptm->tm_hour,
	   ptm->tm_min,
	   ptm->tm_sec,
	   ptm->tm_isdst,
	   utc,
	   buff));

    if (sval)
	free_STRING(sval);

    sp->ptr = (PTR) new_STRING1(buff, result);

    while (n_args > 1) {
	n_args--;
	cell_destroy(sp + n_args);
    }
    return_CELL("bi_strftime", sp);
}
Пример #28
0
int
is_cmdline_assign(char *s)
{
    register char *p;
    int c;
    SYMTAB *stp;
    CELL *cp = 0;
    size_t len;
    CELL cell;			/* used if command line assign to pseudo field */
    CELL *fp = (CELL *) 0;	/* ditto */
    size_t length;

    if (scan_code[*(unsigned char *) s] != SC_IDCHAR)
	return 0;

    p = s + 1;
    while ((c = scan_code[*(unsigned char *) p]) == SC_IDCHAR
	   || c == SC_DIGIT)
	p++;

    if (*p != '=')
	return 0;

    *p = 0;
    stp = find(s);

    switch (stp->type) {
    case ST_NONE:
	stp->type = ST_VAR;
	stp->stval.cp = cp = ZMALLOC(CELL);
	break;

    case ST_VAR:
    case ST_NR:		/* !! no one will do this */
	cp = stp->stval.cp;
	cell_destroy(cp);
	break;

    case ST_FIELD:
	/* must be pseudo field */
	fp = stp->stval.cp;
	cp = &cell;
	break;

    default:
	rt_error(
		    "cannot command line assign to %s\n\ttype clash or keyword"
		    ,s);
    }

    /* we need to keep ARGV[i] intact */
    *p++ = '=';
    len = strlen(p) + 1;
    /* posix says escape sequences are on from command line */
    p = rm_escape(strcpy((char *) zmalloc(len), p), &length);
    cp->ptr = (PTR) new_STRING1(p, length);
    zfree(p, len);
    check_strnum(cp);		/* sets cp->type */
    if (fp)			/* move it from cell to pfield[] */
    {
	field_assign(fp, cp);
	free_STRING(string(cp));
    }
    return 1;
}
Пример #29
0
/* get the next command line file open */
static FIN *
next_main(int open_flag)	/* called by open_main() if on */
{
    register CELL *cp;
    CELL *cp0;
    CELL argc;			/* copy of ARGC */
    CELL c_argi;		/* cell copy of argi */
    CELL argval;		/* copy of ARGV[c_argi] */
    int failed = 1;

    argval.type = C_NOINIT;
    c_argi.type = C_DOUBLE;

    if (main_fin) {
	FINclose(main_fin);
	main_fin = 0;
    }
    /* FILENAME and FNR don't change unless we really open
       a new file */

    /* make a copy of ARGC to avoid side effect */
    if (cellcpy(&argc, ARGC)->type != C_DOUBLE)
	cast1_to_d(&argc);

    while (argi < argc.dval) {
	c_argi.dval = argi;
	argi += 1.0;

	if (!(cp0 = array_find(Argv, &c_argi, NO_CREATE)))
	    continue;		/* its deleted */

	/* make a copy so we can cast w/o side effect */
	cell_destroy(&argval);
	cp = cellcpy(&argval, cp0);
#ifndef NO_LEAKS
	cell_destroy(cp0);
#endif

	if (cp->type < C_STRING)
	    cast1_to_s(cp);
	if (string(cp)->len == 0) {
	    /* file argument is "" */
	    cell_destroy(cp);
	    continue;
	}

	/* it might be a command line assignment */
	if (is_cmdline_assign(string(cp)->str)) {
	    continue;
	}

	/* try to open it -- we used to continue on failure,
	   but posix says we should quit */
	if (!(main_fin = FINopen(string(cp)->str, 1))) {
	    errmsg(errno, "cannot open %s", string(cp)->str);
	    mawk_exit(2);
	}

	/* success -- set FILENAME and FNR */
	cell_destroy(FILENAME);
	cellcpy(FILENAME, cp);
	cell_destroy(cp);
	cell_destroy(FNR);
	FNR->type = C_DOUBLE;
	FNR->dval = 0.0;
	rt_fnr = 0;

	failed = 0;
	break;
    }

    if (failed) {
	cell_destroy(&argval);

	if (open_flag) {
	    /* all arguments were null or assignment */
	    set_main_to_stdin();
	} else {
	    main_fin = &dead_main;
	    /* since MAIN_FLAG is not set, FINgets won't call next_main() */
	}
    }

    return main_fin;
}