/********************************************
bi_funct.c
libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include "mawk.h"
#include "bi_funct.h"
#include "bi_vars.h"
#include "memory.h"
#include "init.h"
#include "files.h"
#include "fin.h"
#include "field.h"
#include "regexp.h"
#include "repl.h"
#include "num.h"
#include "math_wrap.h"
#include "vio.h"
#include "cell.h"
#include <string.h>
#include <unistd.h>
/* statics */
static mawk_string_t *gsub(mawk_state_t *, PTR, mawk_cell_t *, char *, char *, int);
static void fplib_err(mawk_state_t *, char *, mawk_num_t, char *);
/****************************************************************
string builtins (except split (in split.c) and [g]sub (at end))
****************************************************************/
mawk_cell_t *mawk_bi_length(mawk_state_t *MAWK, register mawk_cell_t *sp)
{
unsigned len;
if (sp->type == 0)
mawk_cellcpy(MAWK, sp, MAWK->field);
else
sp--;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
len = string(sp)->len;
free_STRING(string(sp));
sp->type = C_NUM;
sp->d.dval = (double) len;
return sp;
}
char *mawk_str_str(register char *target, char *key, unsigned key_len)
{
register int k = key[0];
switch (key_len) {
case 0:
return (char *) 0;
case 1:
return strchr(target, k);
case 2:
{
int k1 = key[1];
while ((target = strchr(target, k)))
if (target[1] == k1)
return target;
else
target++;
/*failed */
return (char *) 0;
}
}
key_len--;
while ((target = strchr(target, k))) {
if (strncmp(target + 1, key + 1, key_len) == 0)
return target;
else
target++;
}
/*failed */
return (char *) 0;
}
mawk_cell_t *mawk_bi_index(mawk_state_t *MAWK, register mawk_cell_t *sp)
{
register int idx;
unsigned len;
char *p;
sp--;
if (TEST2(sp) != TWO_STRINGS)
mawk_cast2_to_str(MAWK, sp);
if ((len = string(sp + 1)->len))
idx = (p = mawk_str_str(string(sp)->str, string(sp + 1)->str, len))
? p - string(sp)->str + 1 : 0;
else /* index of the empty string */
idx = 1;
free_STRING(string(sp));
free_STRING(string(sp + 1));
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) idx;
return sp;
}
/* substr(s, i, n)
if l = length(s) then get the characters
from max(1,i) to min(l,n-i-1) inclusive */
mawk_cell_t *mawk_bi_substr(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int n_args, len;
register int i, n;
mawk_string_t *sval; /* substr(sval->str, i, n) */
n_args = sp->type;
sp -= n_args;
if (sp->type != C_STRING)
mawk_cast1_to_str(MAWK, sp);
/* don't use < C_STRING shortcut */
sval = string(sp);
if ((len = sval->len) == 0) { /* substr on null string */
if (n_args == 3) {
mawk_cell_destroy(MAWK, sp + 2);
}
mawk_cell_destroy(MAWK, sp + 1);
return sp;
}
if (n_args == 2) {
n = MAX__INT;
if (sp[1].type != C_NUM)
mawk_cast1_to_num(MAWK, sp + 1);
}
else {
if (TEST2(sp + 1) != TWO_NUMS)
mawk_cast2_to_num(MAWK, sp + 1);
n = d_to_i(sp[2].d.dval);
}
i = d_to_i(sp[1].d.dval) - 1; /* i now indexes into string */
if (i < 0)
i = 0;
if (n > len - i)
n = len - i;
if (n <= 0) { /* the null string */
sp->ptr = (PTR) & (MAWK->null_str);
(MAWK->null_str.ref_cnt)++;
}
else { /* got something */
sp->ptr = (PTR) mawk_new_STRING0(MAWK, n);
memcpy(string(sp)->str, sval->str + i, n);
}
free_STRING(sval);
return sp;
}
/*
match(s,r)
sp[0] holds r, sp[-1] holds s
*/
mawk_cell_t *mawk_bi_match(mawk_state_t *MAWK, mawk_cell_t *sp)
{
char *p;
unsigned length;
if (sp->type != C_RE)
mawk_cast_to_RE(MAWK, sp);
if ((--sp)->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
mawk_cell_destroy(MAWK, RSTART);
mawk_cell_destroy(MAWK, RLENGTH);
RSTART->type = C_NUM;
RLENGTH->type = C_NUM;
p = mawk_REmatch(MAWK, string(sp)->str, (sp + 1)->ptr, &length, 0);
if (p) {
sp->d.dval = (mawk_num_t) (p - string(sp)->str + 1);
RLENGTH->d.dval = (mawk_num_t) length;
}
else {
sp->d.dval = MAWK_NUM_ZERO;
RLENGTH->d.dval = -MAWK_NUM_ONE; /* posix */
}
free_STRING(string(sp));
sp->type = C_NUM;
RSTART->d.dval = sp->d.dval;
return sp;
}
mawk_cell_t *mawk_bi_toupper(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_string_t *old;
register char *p, *q;
if (sp->type != C_STRING)
mawk_cast1_to_str(MAWK, sp);
old = string(sp);
sp->ptr = (PTR) mawk_new_STRING0(MAWK, old->len);
q = string(sp)->str;
p = old->str;
while (*p) {
*q = *p++;
if (*q >= 'a' && *q <= 'z')
*q += 'A' - 'a';
q++;
}
free_STRING(old);
return sp;
}
mawk_cell_t *mawk_bi_tolower(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_string_t *old;
register char *p, *q;
if (sp->type != C_STRING)
mawk_cast1_to_str(MAWK, sp);
old = string(sp);
sp->ptr = (PTR) mawk_new_STRING0(MAWK, old->len);
q = string(sp)->str;
p = old->str;
while (*p) {
*q = *p++;
if (*q >= 'A' && *q <= 'Z')
*q += 'a' - 'A';
q++;
}
free_STRING(old);
return sp;
}
/************************************************
arithemetic builtins
************************************************/
static void fplib_err(mawk_state_t *MAWK, char *fname, mawk_num_t val, char *error)
{
mawk_rt_error(MAWK, "%s(" NUM_FMT ") : %s", fname, val, error);
}
#ifndef MAWK_NO_FLOAT
#ifndef MAWK_HAVE_SAFE_NAN
# define handle_nan_1arg() \
if (P_isnan((sp)->d.dval)) { \
sp->d.dval = P_nan(); \
return sp; \
}
#else
# define handle_nan_1arg()
#endif
mawk_cell_t *mawk_bi_sin(mawk_state_t *MAWK, mawk_cell_t *sp)
{
#if ! STDC_MATHERR
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
sp->d.dval = sin(sp->d.dval);
return sp;
#else
mawk_num_t x;
errno = 0;
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
x = sp->d.dval;
sp->d.dval = sin(sp->d.dval);
if (errno)
fplib_err(MAWK, "sin", x, "loss of precision");
return sp;
#endif
}
mawk_cell_t *mawk_bi_cos(mawk_state_t *MAWK, mawk_cell_t *sp)
{
#if ! STDC_MATHERR
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
sp->d.dval = cos(sp->d.dval);
return sp;
#else
mawk_num_t x;
errno = 0;
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
x = sp->d.dval;
sp->d.dval = cos(sp->d.dval);
if (errno)
fplib_err(MAWK, "cos", x, "loss of precision");
return sp;
#endif
}
mawk_cell_t *mawk_bi_atan2(mawk_state_t *MAWK, mawk_cell_t *sp)
{
#if ! STDC_MATHERR
sp--;
if (TEST2(sp) != TWO_NUMS)
mawk_cast2_to_num(MAWK, sp);
#ifndef MAWK_HAVE_SAFE_NAN
if (P_isnan(sp->d.dval) || P_isnan((sp+1)->d.dval)) {
sp->d.dval = P_nan();
return sp;
}
#endif
sp->d.dval = atan2(sp->d.dval, (sp + 1)->d.dval);
return sp;
#else
errno = 0;
sp--;
if (TEST2(sp) != TWO_NUMS)
mawk_cast2_to_num(MAWK, sp);
#ifndef MAWK_HAVE_SAFE_NAN
if (P_isnan(sp->d.dval) || P_isnan((sp+1)->d.dval)) {
sp->d.dval = P_nan();
return sp;
}
#endif
sp->d.dval = atan2(sp->d.dval, (sp + 1)->d.dval);
if (errno)
mawk_rt_error(MAWK, "atan2(0,0) : domain error");
return sp;
#endif
}
mawk_cell_t *mawk_bi_log(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_num_t x;
errno = 0;
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
x = sp->d.dval;
PM_BEGIN
sp->d.dval = P_log(sp->d.dval);
PM_ERROR
/* temporary workaround until the final nan support is there */
sp->d.dval = P_nan();
/* fplib_err(MAWK, "log", x, "domain error");*/
PM_END;
return sp;
}
mawk_cell_t *mawk_bi_exp(mawk_state_t *MAWK, mawk_cell_t *sp)
{
#if ! STDC_MATHERR
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
sp->d.dval = exp(sp->d.dval);
return sp;
#else
mawk_num_t x;
errno = 0;
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
x = sp->d.dval;
sp->d.dval = exp(sp->d.dval);
if (errno && sp->d.dval)
fplib_err(MAWK, "exp", x, "mawk_overflow");
/* on underflow sp->d.dval==0, ignore */
return sp;
#endif
}
#endif
mawk_cell_t *mawk_bi_int(mawk_state_t *MAWK, mawk_cell_t *sp)
{
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
sp->d.dval = mawk_num_int(sp->d.dval);
return sp;
}
mawk_cell_t *mawk_bi_sqrt(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_num_t x;
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
handle_nan_1arg();
x = sp->d.dval;
if (x < 0) {
sp->d.dval = P_nan();
return sp;
}
#if ! STDC_MATHERR
sp->d.dval = mawk_num_sqrt(x);
return sp;
#else
errno = 0;
sp->d.dval = mawk_num_sqrt(x);
if (errno)
fplib_err(MAWK, "sqrt", x, "domain error");
return sp;
#endif
}
#ifndef NO_TIME_H
#include <time.h>
#else
#include <sys/types.h>
#endif
/* For portability, we'll use our own random number generator , taken
from: Park, SK and Miller KW, "Random Number Generators:
Good Ones are Hard to Find", CACM, 31, 1192-1201, 1988.
*/
#define M 0x7fffffff /* 2^31-1 */
#define MX 0xffffffff
#define A 16807
#define Q 127773 /* M/A */
#define R 2836 /* M%A */
#if M == MAX__LONG
#define crank(s) s = A * (s % Q) - R * (s / Q) ;\
if ( s <= 0 ) s += M
#else
/* 64 bit longs */
#define crank(s) { unsigned long t = s ;\
t = (A * (t % Q) - R * (t / Q)) & MX ;\
if ( t >= M ) t = (t+M)&M ;\
s = t ;\
}
#endif
mawk_cell_t *mawk_bi_srand(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_cell_t c;
if (sp->type == 0) { /* seed off clock */
mawk_cellcpy(MAWK, sp, &MAWK->cseed);
mawk_cell_destroy(MAWK, &MAWK->cseed);
MAWK->cseed.type = C_NUM;
MAWK->cseed.d.dval = (mawk_num_t) time((time_t *) 0);
}
else { /* user seed */
sp--;
/* swap cseed and *sp ; don't need to adjust ref_cnts */
c = *sp;
*sp = MAWK->cseed;
MAWK->cseed = c;
}
/* The old seed is now in *sp ; move the value in cseed to
seed in range [1,M) */
mawk_cellcpy(MAWK, &c, &MAWK->cseed);
if (c.type == C_NOINIT)
mawk_cast1_to_num(MAWK, &c);
MAWK->seed = c.type == C_NUM ? (d_to_i(c.d.dval) & M) % M + 1 : mawk_hash(string(&c)->str) % M + 1;
if (MAWK->seed == M)
MAWK->seed = M - 1;
mawk_cell_destroy(MAWK, &c);
/* crank it once so close seeds don't give a close
first result */
crank(MAWK->seed);
return sp;
}
mawk_cell_t *mawk_bi_rand(mawk_state_t *MAWK, mawk_cell_t *sp)
{
crank(MAWK->seed);
sp++;
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) MAWK->seed / (mawk_num_t) M;
return sp;
}
#undef A
#undef M
#undef MX
#undef Q
#undef R
#undef crank
/*************************************************
miscellaneous builtins
close, system and getline
fflush
*************************************************/
mawk_cell_t *mawk_bi_close(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int x;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
x = mawk_file_close(MAWK, (mawk_string_t *) sp->ptr);
free_STRING(string(sp));
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) x;
return sp;
}
mawk_cell_t *mawk_bi_fflush(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int ret = 0;
if (sp->type == 0)
mawk_vio_flush(MAWK, MAWK->fnode_stdout->vf);
else {
sp--;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
ret = mawk_file_flush(MAWK, string(sp));
free_STRING(string(sp));
}
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) ret;
return sp;
}
#ifndef MAWK_NO_FORK
mawk_cell_t *mawk_bi_system(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int pid;
unsigned ret_val;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
mawk_flush_all_output(MAWK);
switch (pid = fork()) {
case -1: /* fork failed */
mawk_errmsg(MAWK, errno, "could not create a new process");
ret_val = 127;
break;
case 0: /* the child */
mawk_vio_exec_shell(MAWK, string(sp)->str);
default: /* wait for the child */
ret_val = mawk_wait_for(MAWK, pid);
break;
}
mawk_cell_destroy(MAWK, sp);
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) ret_val;
return sp;
}
#endif
/* getline() */
/* if type == 0 : stack is 0 , target address
if type == F_IN : stack is F_IN, expr(filename), target address
if type == PIPE_IN : stack is PIPE_IN, target address, expr(pipename)
*/
mawk_cell_t *mawk_bi_getline(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_cell_t tc, *cp;
char *p;
unsigned len;
FILE_NODE *fnode = NULL;
switch (sp->type) {
case 0:
sp--;
if (!MAWK->main_input)
mawk_FINopen_main(MAWK);
p = mawk_FINgets(MAWK, MAWK->main_input, &len);
if (p == (void *) mawk_FIN_nomore)
goto nomore;
if (!p)
goto eof;
cp = (mawk_cell_t *) sp;
if (TEST2(NR) != TWO_NUMS)
mawk_cast2_to_num(MAWK, NR);
NR->d.dval += MAWK_NUM_ONE;
MAWK->rt_nr++;
FNR->d.dval += MAWK_NUM_ONE;
MAWK->rt_fnr++;
break;
case F_IN:
sp--;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fnode = mawk_file_find(MAWK, sp->ptr, F_IN, 1);
free_STRING(string(sp));
sp--;
if (fnode == NULL)
goto open_failure;
p = mawk_FINgets(MAWK, fnode, &len);
if (p == (void *) mawk_FIN_nomore)
goto nomore;
if (!p) {
mawk_file_close_(MAWK, fnode);
goto eof;
}
cp = sp;
break;
case PIPE_IN:
sp -= 2;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fnode = mawk_file_find(MAWK, sp->ptr, PIPE_IN, 1);
free_STRING(string(sp));
if (fnode == NULL)
goto open_failure;
p = mawk_FINgets(MAWK, fnode, &len);
if (p == (void *) mawk_FIN_nomore)
goto nomore;
if (!p) {
mawk_file_close_(MAWK, fnode);
goto eof;
}
cp = (sp + 1);
break;
default:
mawk_bozo(MAWK, "type in mawk_bi_getline");
}
/* we've read a line , store it */
if (len == 0) {
tc.type = C_STRING;
tc.ptr = (PTR) & (MAWK->null_str);
MAWK->null_str.ref_cnt++;
}
else {
tc.type = C_MBSTRN;
tc.ptr = (PTR) mawk_new_STRING0(MAWK, len);
memcpy(string(&tc)->str, p, len);
}
mawk_bifunct_target_assign(MAWK, cp, &tc);
mawk_cell_destroy(MAWK, &tc);
sp->d.dval = MAWK_NUM_ONE;
goto done;
open_failure:;
sp->d.dval = -MAWK_NUM_ONE;
goto done;
eof:;
sp->d.dval = MAWK_NUM_ZERO; /* fall thru to done */
done:;
sp->type = C_NUM;
return sp;
nomore:;
sp->type = C_REQ_NOMORE;
return sp;
}
/**********************************************
sub() and gsub()
**********************************************/
/* entry: sp[0] = address of mawk_cell_t to sub on
sp[-1] = substitution CELL
sp[-2] = regular expression to match
*/
mawk_cell_t *mawk_bi_sub(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_cell_t *cp; /* pointer to the replacement target */
mawk_cell_t tc; /* build the new string here */
mawk_cell_t sc; /* copy of the target mawk_cell_t */
char *front, *middle, *back; /* pieces */
unsigned front_len, middle_len, back_len;
sp -= 2;
if (sp->type != C_RE)
mawk_cast_to_RE(MAWK, sp);
if (sp[1].type != C_REPL && sp[1].type != C_REPLV)
mawk_cast_to_REPL(MAWK, sp + 1);
cp = (mawk_cell_t *) (sp + 2);
/* make a copy of the target, because we won't change anything
including type unless the match works */
if (cp->type == C_ARR_REF_BT) {
sc.type = C_NOINIT;
mawk_array_find(MAWK, (mawk_array_t)cp->ptr, cp->d.idx_cell, &sc, 1);
}
else
mawk_cellcpy(MAWK, &sc, cp->ptr);
if (sc.type < C_STRING)
mawk_cast1_to_str(MAWK, &sc);
front = string(&sc)->str;
if ((middle = mawk_REmatch(MAWK, front, sp->ptr, &middle_len, 0))) {
front_len = middle - front;
back = middle + middle_len;
back_len = string(&sc)->len - front_len - middle_len;
if ((sp + 1)->type == C_REPLV) {
mawk_string_t *sval = mawk_new_STRING0(MAWK, middle_len);
memcpy(sval->str, middle, middle_len);
mawk_replv_to_repl(MAWK, sp + 1, sval);
free_STRING(sval);
}
tc.type = C_STRING;
tc.ptr = (PTR) mawk_new_STRING0(MAWK, front_len + string(sp + 1)->len + back_len);
{
char *p = string(&tc)->str;
if (front_len) {
memcpy(p, front, front_len);
p += front_len;
}
if (string(sp + 1)->len) {
memcpy(p, string(sp + 1)->str, string(sp + 1)->len);
p += string(sp + 1)->len;
}
if (back_len)
memcpy(p, back, back_len);
}
mawk_bifunct_target_assign(MAWK, cp, &tc);
free_STRING(string(&tc));
}
free_STRING(string(&sc));
mawk_repl_destroy(MAWK, sp + 1);
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) (middle != (char *) 0 ? MAWK_NUM_ONE : MAWK_NUM_ZERO);
return sp;
}
/* recursive global subsitution
dealing with empty matches makes this mildly painful
*/
static mawk_string_t *gsub(mawk_state_t *MAWK, PTR re, mawk_cell_t *repl, char *target, char *orig_target, int flag)
{
/*target -> if on, match of empty string at front is OK */
/* repl -> always of type REPL or REPLV, destroyed by caller */
/* flag -> if on, match of empty string at front is OK */
char *front, *middle;
mawk_string_t *back;
unsigned front_len, middle_len;
mawk_string_t *ret_val;
mawk_cell_t xrepl; /* a copy of repl so we can change repl */
if (!(middle = mawk_REmatch(MAWK, target, re, &middle_len, target != orig_target)))
return mawk_new_STRING(MAWK, target); /* no match */
mawk_cellcpy(MAWK, &xrepl, repl);
if (!flag && middle_len == 0 && middle == target) { /* match at front that's not allowed */
if (*target == 0) { /* target is empty string */
mawk_repl_destroy(MAWK, &xrepl);
MAWK->null_str.ref_cnt++;
return &(MAWK->null_str);
}
else {
char xbuff[2];
front_len = 0;
/* make new repl with target[0] */
mawk_repl_destroy(MAWK, repl);
xbuff[0] = *target++;
xbuff[1] = 0;
repl->type = C_REPL;
repl->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
back = gsub(MAWK, re, &xrepl, target, orig_target, 1);
}
}
else { /* a match that counts */
MAWK->repl_cnt++;
front = target;
front_len = middle - target;
if (*middle == 0) { /* matched back of target */
back = &(MAWK->null_str);
MAWK->null_str.ref_cnt++;
}
else
back = gsub(MAWK, re, &xrepl, middle + middle_len, orig_target, 0);
/* patch the &'s if needed */
if (repl->type == C_REPLV) {
mawk_string_t *sval = mawk_new_STRING0(MAWK, middle_len);
memcpy(sval->str, middle, middle_len);
mawk_replv_to_repl(MAWK, repl, sval);
free_STRING(sval);
}
}
/* put the three pieces together */
ret_val = mawk_new_STRING0(MAWK, front_len + string(repl)->len + back->len);
{
char *p = ret_val->str;
if (front_len) {
memcpy(p, front, front_len);
p += front_len;
}
if (string(repl)->len) {
memcpy(p, string(repl)->str, string(repl)->len);
p += string(repl)->len;
}
if (back->len)
memcpy(p, back->str, back->len);
}
/* cleanup, repl is freed by the caller */
mawk_repl_destroy(MAWK, &xrepl);
free_STRING(back);
return ret_val;
}
/* set up for call to gsub() */
mawk_cell_t *mawk_bi_gsub(mawk_state_t *MAWK, mawk_cell_t *sp)
{
mawk_cell_t *cp; /* pts at the replacement target */
mawk_cell_t sc; /* copy of replacement target */
mawk_cell_t tc; /* build the result here */
sp -= 2;
if (sp->type != C_RE)
mawk_cast_to_RE(MAWK, sp);
if ((sp + 1)->type != C_REPL && (sp + 1)->type != C_REPLV)
mawk_cast_to_REPL(MAWK, sp + 1);
cp = (mawk_cell_t *) (sp + 2);
if (cp->type == C_ARR_REF_BT) {
sc.type = C_NOINIT;
mawk_array_find(MAWK, (mawk_array_t)cp->ptr, cp->d.idx_cell, &sc, 1);
}
else
mawk_cellcpy(MAWK, &sc, cp->ptr);
if (sc.type < C_STRING)
mawk_cast1_to_str(MAWK, &sc);
MAWK->repl_cnt = 0;
tc.ptr = (PTR) gsub(MAWK, sp->ptr, sp + 1, string(&sc)->str, string(&sc)->str, 1);
if (MAWK->repl_cnt) {
tc.type = C_STRING;
mawk_bifunct_target_assign(MAWK, cp, &tc);
}
/* cleanup */
free_STRING(string(&sc));
free_STRING(string(&tc));
mawk_repl_destroy(MAWK, sp + 1);
sp->type = C_NUM;
sp->d.dval = (mawk_num_t) MAWK->repl_cnt;
return sp;
}
mawk_cell_t *mawk_bi_call(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int i, numargs;
SYMTAB *fs;
const char *fn;
/* mawk_cell_t *ret;*/
numargs = sp->type;
sp -= numargs;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fn = string(sp)->str;
fs = mawk_find(MAWK, fn, 0);
if ((fs == NULL) || (fs->type != ST_FUNCT)) {
/* does not exist or not a function */
if (fs == NULL)
mawk_set_errno(MAWK, "1 object does not exist");
else
mawk_set_errno(MAWK, "2 object is not a function");
TODO("this should be some common code in execute.c?")
for (i = 0; i < numargs; i++) {
mawk_cell_destroy(MAWK, &sp[i]);
sp[i].type = C_NOINIT;
sp[i].d.dval = MAWK_NUM_ZERO;
}
sp[numargs].type = C_NOINIT;
sp[numargs].d.dval = MAWK_NUM_ZERO;
return sp;
}
mawk_set_errno(MAWK, "");
/* ret = mawk_call(MAWK, sp + numargs - 1, fs->stval.fbp, numargs - 1);*/
/* shift args down to replace first arg (function name) with the first
actual arg passed to the function */
for (i = 0; i < numargs; i++)
sp[i] = sp[i+1];
sp += numargs-1;
/* perform the call */
sp->type = C_NUM;
sp->d.dval = numargs - 1;
inc_sp();
sp->type = C_REQ_CALL;
sp->ptr = fs->stval.fbp;
return sp;
}
mawk_cell_t *mawk_bi_acall(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int numargs;
SYMTAB *fs, *fa;
const char *fn;
mawk_cell_t *ret, idx;
numargs = 1;
sp -= numargs;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fn = string(sp)->str;
fs = mawk_find(MAWK, fn, 0);
if (fs == NULL) {
/* does not exist */
mawk_set_errno(MAWK, "1 object does not exist");
sp++;
goto error;
}
sp++;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fa = mawk_find(MAWK, string(sp)->str, 0);
if (fa == NULL) {
mawk_set_errno(MAWK, "3 argument array does not exist");
goto error;
}
if (fa->type != ST_ARRAY) {
mawk_set_errno(MAWK, "4 argument array is not an array");
goto error;
}
sp -= 2;
for (numargs = 1;; numargs++) {
inc_sp();
idx.type = C_NUM;
idx.d.dval = numargs;
if (mawk_array_find(MAWK, fa->stval.array, &idx, sp, 0) == 0)
break;
}
if (fs->type == ST_FUNCT) {
/* perform the call */
mawk_set_errno(MAWK, "");
inc_sp();
sp->type = C_NUM;
sp->d.dval = numargs;
inc_sp();
sp->type = C_REQ_CALL;
sp->ptr = fs->stval.fbp;
return sp;
}
else {
mawk_set_errno(MAWK, "5 object is a function");
idx.type = C_NOINIT;
idx.d.dval = MAWK_NUM_ZERO;
ret = &idx;
}
sp -= numargs;
sp--;
TODO(": cell destroy all the allocated but unused args?")
return sp;
error:;
mawk_cell_destroy(MAWK, sp);
sp--;
sp->type = C_NOINIT;
return sp;
}
mawk_cell_t *mawk_bi_valueof(mawk_state_t *MAWK, mawk_cell_t *sp)
{
int numargs;
SYMTAB *fs;
mawk_cell_t *ret, *idx;
numargs = sp->type;
sp -= numargs;
if (sp->type < C_STRING)
mawk_cast1_to_str(MAWK, sp);
fs = mawk_find(MAWK, string(sp)->str, 0);
if (fs == NULL) {
/* does not exist */
mawk_set_errno(MAWK, "1 object does not exist");
goto error;
}
if (fs->type == ST_FUNCT) {
mawk_set_errno(MAWK, "5 object is a function");
goto error;
}
if (numargs > 1) {
if (fs->type == ST_ARRAY) {
idx = sp + 1;
mawk_array_find(MAWK, fs->stval.array, idx, sp, 0);
goto has_set_sp;
}
else {
mawk_set_errno(MAWK, "6 object is not an array, can not index it");
goto error;
}
}
else {
if (fs->type == ST_ARRAY) {
mawk_set_errno(MAWK, "7 object is an array, need to index it");
goto error;
}
ret = fs->stval.cp;
}
if ((ret != NULL) && ((fs->type == ST_VAR) || (fs->type == ST_KEYWORD))) {
mawk_cell_destroy(MAWK, sp);
*sp = *ret;
has_set_sp:;
mawk_set_errno(MAWK, "");
return sp;
}
if (ret != NULL)
mawk_set_errno(MAWK, "8 object is not a variable (and not a function either)");
error:;
mawk_cell_destroy(MAWK, sp);
sp->type = C_NOINIT;
return sp;
}
mawk_cell_t *mawk_bi_isnan(mawk_state_t *MAWK, mawk_cell_t *sp)
{
if (sp->type != C_NUM)
mawk_cast1_to_num(MAWK, sp);
sp->type = C_NUM;
sp->d.dval = P_isnan(sp->d.dval);
return sp--;
}