qse/qse/lib/awk/std.c

1208 lines
24 KiB
C

/*
* $Id$
*
Copyright 2006-2008 Chung, Hyung-Hwan.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "awk.h"
#include <qse/cmn/sio.h>
#include <qse/cmn/pio.h>
#include <qse/cmn/str.h>
#include <qse/cmn/time.h>
#include <qse/utl/stdio.h> /* TODO: remove dependency on qse_vsprintf */
#include <math.h>
#include <stdarg.h>
#include <stdlib.h>
typedef struct xtn_t
{
qse_awk_prmfns_t prmfns;
} xtn_t;
typedef struct rxtn_t
{
unsigned int seed;
} rxtn_t;
static qse_real_t custom_awk_pow (void* custom, qse_real_t x, qse_real_t y)
{
#if defined(HAVE_POWL)
return powl (x, y);
#elif defined(HAVE_POW)
return pow (x, y);
#elif defined(HAVE_POWF)
return powf (x, y);
#else
#error ### no pow function available ###
#endif
}
static int custom_awk_sprintf (
void* custom, qse_char_t* buf, qse_size_t size,
const qse_char_t* fmt, ...)
{
int n;
va_list ap;
va_start (ap, fmt);
n = qse_vsprintf (buf, size, fmt, ap);
va_end (ap);
return n;
}
static int add_functions (qse_awk_t* awk);
qse_awk_t* qse_awk_opensimple (qse_size_t xtnsize)
{
qse_awk_t* awk;
xtn_t* xtn;
awk = qse_awk_open (QSE_MMGR_GETDFL(), xtnsize + QSE_SIZEOF(xtn_t));
qse_awk_setccls (awk, QSE_CCLS_GETDFL());
xtn = (xtn_t*)((qse_byte_t*)qse_awk_getxtn(awk) + xtnsize);
xtn->prmfns.pow = custom_awk_pow;
xtn->prmfns.sprintf = custom_awk_sprintf;
xtn->prmfns.data = QSE_NULL;
qse_awk_setprmfns (awk, &xtn->prmfns);
qse_awk_setoption (awk,
QSE_AWK_IMPLICIT | QSE_AWK_EIO | QSE_AWK_NEWLINE |
QSE_AWK_BASEONE | QSE_AWK_PABLOCK);
if (add_functions (awk) == -1)
{
qse_awk_close (awk);
return QSE_NULL;
}
return awk;
}
/*** PARSESIMPLE ***/
typedef struct sf_t sf_t;
struct sf_t
{
struct
{
int type;
union
{
const qse_char_t*const* files;
const qse_char_t* str;
} p;
qse_size_t index; /* current file index */
qse_sio_t* handle; /* the handle to an open file */
} in;
struct
{
const qse_char_t* file;
qse_sio_t* handle;
} out;
qse_awk_t* awk;
};
static qse_ssize_t sf_in (int cmd, void* arg, qse_char_t* data, qse_size_t size)
{
sf_t* sf = (sf_t*)arg;
if (cmd == QSE_AWK_IO_OPEN)
{
if (sf->in.type == QSE_AWK_PARSE_FILES)
{
if (sf->in.p.files[sf->in.index] == QSE_NULL) return 0;
if (sf->in.p.files[sf->in.index][0] == QSE_T('\0'))
{
sf->in.handle = qse_sio_in;
}
else
{
sf->in.handle = qse_sio_open (
qse_awk_getmmgr(sf->awk),
0,
sf->in.p.files[sf->in.index],
QSE_SIO_READ
);
if (sf->in.handle == QSE_NULL) return -1;
}
/*
qse_awk_setsinname ();
*/
}
return 1;
}
else if (cmd == QSE_AWK_IO_CLOSE)
{
if (sf->in.handle != QSE_NULL &&
sf->in.handle != qse_sio_in &&
sf->in.handle != qse_sio_out &&
sf->in.handle != qse_sio_err)
{
qse_sio_close (sf->in.handle);
}
return 0;
}
else if (cmd == QSE_AWK_IO_READ)
{
qse_ssize_t n = 0;
if (sf->in.type == QSE_AWK_PARSE_FILES)
{
qse_sio_t* sio;
retry:
sio = sf->in.handle;
n = qse_sio_getsn (sio, data, size);
if (n == 0 && sf->in.p.files[++sf->in.index] != QSE_NULL)
{
if (sio != qse_sio_in) qse_sio_close (sio);
if (sf->in.p.files[sf->in.index][0] == QSE_T('\0'))
{
sf->in.handle = qse_sio_in;
}
else
{
sf->in.handle = qse_sio_open (
qse_awk_getmmgr(sf->awk),
0,
sf->in.p.files[sf->in.index],
QSE_SIO_READ
);
if (sf->in.handle == QSE_NULL) return -1;
}
/* TODO: reset internal line counters...
set new source name....
qse_awk_setsinname ();
*/
goto retry;
}
}
else
{
while (n < size && sf->in.p.str[sf->in.index] != QSE_T('\0'))
{
data[n++] = sf->in.p.str[sf->in.index++];
}
}
return n;
}
return -1;
}
static qse_ssize_t sf_out (int cmd, void* arg, qse_char_t* data, qse_size_t size)
{
sf_t* sf = (sf_t*)arg;
if (cmd == QSE_AWK_IO_OPEN)
{
if (sf->out.file[0] == QSE_T('\0'))
{
sf->out.handle = qse_sio_out;
}
else
{
sf->out.handle = qse_sio_open (
qse_awk_getmmgr(sf->awk),
0,
sf->out.file,
QSE_SIO_WRITE|QSE_SIO_CREATE|QSE_SIO_TRUNCATE
);
if (sf->out.handle == QSE_NULL) return -1;
}
return 1;
}
else if (cmd == QSE_AWK_IO_CLOSE)
{
if (sf->out.handle != QSE_NULL)
{
qse_sio_flush (sf->out.handle);
if (sf->out.handle != qse_sio_in &&
sf->out.handle != qse_sio_out &&
sf->out.handle != qse_sio_err)
{
qse_sio_close (sf->out.handle);
}
}
return 0;
}
else if (cmd == QSE_AWK_IO_WRITE)
{
/*
qse_size_t left = size;
while (left > 0)
{
if (*data == QSE_T('\0'))
{
if (qse_fputc (*data, sf->out.handle) == QSE_CHAR_EOF) return -1;
left -= 1; data += 1;
}
else
{
int chunk = (left > QSE_TYPE_MAX(int))? QSE_TYPE_MAX(int): (int)left;
int n = qse_fprintf (sf->out.handle, QSE_T("%.*s"), chunk, data);
if (n < 0) return -1;
left -= n; data += n;
}
}
*/
return qse_sio_putsn (sf->out.handle, data, size);
}
return -1;
}
int qse_awk_parsesimple (
qse_awk_t* awk, const void* isp, int ist, const qse_char_t* osf)
{
sf_t sf;
qse_awk_srcios_t sio;
if (isp == QSE_NULL)
{
qse_awk_seterrnum (awk, QSE_AWK_EINVAL);
return -1;
}
if (ist == QSE_AWK_PARSE_FILES)
{
sf.in.p.files = (const qse_char_t* const*)isp;
}
else if (ist == QSE_AWK_PARSE_STRING)
{
sf.in.p.str = (const qse_char_t*)isp;
}
else
{
qse_awk_seterrnum (awk, QSE_AWK_EINVAL);
return -1;
}
sf.in.type = ist;
sf.in.index = 0;
sf.in.handle = QSE_NULL;
sf.out.file = osf;
sf.out.handle = QSE_NULL;
sf.awk = awk;
sio.in = sf_in;
sio.out = (osf == QSE_NULL)? QSE_NULL: sf_out;
sio.data = &sf;
return qse_awk_parse (awk, &sio);
}
/*** RUNSIMPLE ***/
typedef struct runio_data_t
{
struct
{
qse_char_t** files;
qse_size_t index;
} ic; /* input console */
} runio_data_t;
static qse_ssize_t awk_eio_pipe (
int cmd, void* arg, qse_char_t* data, qse_size_t size)
{
qse_awk_eio_t* epa = (qse_awk_eio_t*)arg;
switch (cmd)
{
case QSE_AWK_IO_OPEN:
{
qse_pio_t* handle;
int flags;
if (epa->mode == QSE_AWK_EIO_PIPE_READ)
{
/* TODO: should we specify ERRTOOUT? */
flags = QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT;
}
else if (epa->mode == QSE_AWK_EIO_PIPE_WRITE)
{
flags = QSE_PIO_WRITEIN;
}
else if (epa->mode == QSE_AWK_EIO_PIPE_RW)
{
flags = QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT |
QSE_PIO_WRITEIN;
}
else return -1; /* TODO: any way to set the error number? */
/*dprint (QSE_T("opening %s of type %d (pipe)\n"), epa->name, epa->type);*/
handle = qse_pio_open (
qse_awk_rtx_getmmgr(epa->run),
0,
epa->name,
flags|QSE_PIO_SHELL|QSE_PIO_TEXT
);
if (handle == QSE_NULL) return -1;
epa->handle = (void*)handle;
return 1;
}
case QSE_AWK_IO_CLOSE:
{
/*dprint (QSE_T("closing %s of type (pipe) %d\n"), epa->name, epa->type);*/
qse_pio_close ((qse_pio_t*)epa->handle);
epa->handle = QSE_NULL;
return 0;
}
case QSE_AWK_IO_READ:
{
return qse_pio_read (
(qse_pio_t*)epa->handle,
data,
size,
QSE_PIO_OUT
);
}
case QSE_AWK_IO_WRITE:
{
return qse_pio_write (
(qse_pio_t*)epa->handle,
data,
size,
QSE_PIO_IN
);
}
case QSE_AWK_IO_FLUSH:
{
/*if (epa->mode == QSE_AWK_EIO_PIPE_READ) return -1;*/
return qse_pio_flush ((qse_pio_t*)epa->handle, QSE_PIO_IN);
}
case QSE_AWK_IO_NEXT:
{
return -1;
}
}
return -1;
}
static qse_ssize_t awk_eio_file (
int cmd, void* arg, qse_char_t* data, qse_size_t size)
{
qse_awk_eio_t* epa = (qse_awk_eio_t*)arg;
switch (cmd)
{
case QSE_AWK_IO_OPEN:
{
qse_fio_t* handle;
int flags;
if (epa->mode == QSE_AWK_EIO_FILE_READ)
{
flags = QSE_FIO_READ;
}
else if (epa->mode == QSE_AWK_EIO_FILE_WRITE)
{
flags = QSE_FIO_WRITE |
QSE_FIO_CREATE |
QSE_FIO_TRUNCATE;
}
else if (epa->mode == QSE_AWK_EIO_FILE_APPEND)
{
flags = QSE_FIO_APPEND |
QSE_FIO_CREATE;
}
else return -1; /* TODO: any way to set the error number? */
/*dprint (QSE_T("opening %s of type %d (file)\n"), epa->name, epa->type);*/
handle = qse_fio_open (
qse_awk_rtx_getmmgr(epa->run),
0,
epa->name,
flags | QSE_FIO_TEXT,
QSE_FIO_RUSR | QSE_FIO_WUSR |
QSE_FIO_RGRP | QSE_FIO_ROTH
);
if (handle == QSE_NULL)
{
qse_cstr_t errarg;
errarg.ptr = epa->name;
errarg.len = qse_strlen(epa->name);
qse_awk_setrunerror (epa->run, QSE_AWK_EOPEN, 0, &errarg, 1);
return -1;
}
epa->handle = (void*)handle;
return 1;
}
case QSE_AWK_IO_CLOSE:
{
/*dprint (QSE_T("closing %s of type %d (file)\n"), epa->name, epa->type);*/
qse_fio_close ((qse_fio_t*)epa->handle);
epa->handle = QSE_NULL;
return 0;
}
case QSE_AWK_IO_READ:
{
return qse_fio_read (
(qse_fio_t*)epa->handle,
data,
size
);
}
case QSE_AWK_IO_WRITE:
{
return qse_fio_write (
(qse_fio_t*)epa->handle,
data,
size
);
}
case QSE_AWK_IO_FLUSH:
{
return qse_fio_flush ((qse_fio_t*)epa->handle);
}
case QSE_AWK_IO_NEXT:
{
return -1;
}
}
return -1;
}
static int open_eio_console (qse_awk_eio_t* epa)
{
runio_data_t* rd = (runio_data_t*)epa->data;
/*dprint (QSE_T("opening console[%s] of type %x\n"), epa->name, epa->type);*/
if (epa->mode == QSE_AWK_EIO_CONSOLE_READ)
{
if (rd->ic.files[rd->ic.index] == QSE_NULL)
{
/* no more input file */
/*dprint (QSE_T("console - no more file\n"));*/
return 0;
}
if (rd->ic.files[rd->ic.index][0] == QSE_T('\0'))
{
/*dprint (QSE_T(" console(r) - <standard input>\n"));*/
epa->handle = qse_sio_in;
}
else
{
/* a temporary variable fp is used here not to change
* any fields of epa when the open operation fails */
qse_sio_t* fp;
fp = qse_sio_open (
qse_awk_rtx_getmmgr(epa->run),
0,
rd->ic.files[rd->ic.index],
QSE_SIO_READ
);
if (fp == QSE_NULL)
{
qse_cstr_t errarg;
errarg.ptr = rd->ic.files[rd->ic.index];
errarg.len = qse_strlen(rd->ic.files[rd->ic.index]);
qse_awk_setrunerror (epa->run, QSE_AWK_EOPEN, 0, &errarg, 1);
return -1;
}
/*dprint (QSE_T(" console(r) - %s\n"), rd->ic.files[rd->ic.index]);*/
if (qse_awk_rtx_setfilename (
epa->run, rd->ic.files[rd->ic.index],
qse_strlen(rd->ic.files[rd->ic.index])) == -1)
{
qse_sio_close (fp);
return -1;
}
epa->handle = fp;
}
rd->ic.index++;
return 1;
}
else if (epa->mode == QSE_AWK_EIO_CONSOLE_WRITE)
{
/*dprint (QSE_T(" console(w) - <standard output>\n"));*/
if (qse_awk_rtx_setofilename (epa->run, QSE_T(""), 0) == -1)
{
return -1;
}
epa->handle = qse_sio_out;
return 1;
}
return -1;
}
static qse_ssize_t awk_eio_console (
int cmd, void* arg, qse_char_t* data, qse_size_t size)
{
qse_awk_eio_t* epa = (qse_awk_eio_t*)arg;
runio_data_t* rd = (runio_data_t*)epa->data;
if (cmd == QSE_AWK_IO_OPEN)
{
return open_eio_console (epa);
}
else if (cmd == QSE_AWK_IO_CLOSE)
{
/*dprint (QSE_T("closing console of type %x\n"), epa->type);*/
if (epa->handle != QSE_NULL &&
epa->handle != qse_sio_in &&
epa->handle != qse_sio_out &&
epa->handle != qse_sio_err)
{
qse_sio_close ((qse_sio_t*)epa->handle);
}
return 0;
}
else if (cmd == QSE_AWK_IO_READ)
{
qse_ssize_t n;
while ((n = qse_sio_getsn((qse_sio_t*)epa->handle,data,size)) == 0)
{
/* it has reached the end of the current file.
* open the next file if available */
if (rd->ic.files[rd->ic.index] == QSE_NULL)
{
/* no more input console */
return 0;
}
if (rd->ic.files[rd->ic.index][0] == QSE_T('\0'))
{
if (epa->handle != QSE_NULL &&
epa->handle != qse_sio_in &&
epa->handle != qse_sio_out &&
epa->handle != qse_sio_err)
{
qse_sio_close ((qse_sio_t*)epa->handle);
}
epa->handle = qse_sio_in;
}
else
{
qse_sio_t* fp;
fp = qse_sio_open (
qse_awk_rtx_getmmgr(epa->run),
0,
rd->ic.files[rd->ic.index],
QSE_SIO_READ
);
if (fp == QSE_NULL)
{
qse_cstr_t errarg;
errarg.ptr = rd->ic.files[rd->ic.index];
errarg.len = qse_strlen(rd->ic.files[rd->ic.index]);
qse_awk_setrunerror (epa->run, QSE_AWK_EOPEN, 0, &errarg, 1);
return -1;
}
if (qse_awk_rtx_setfilename (
epa->run, rd->ic.files[rd->ic.index],
qse_strlen(rd->ic.files[rd->ic.index])) == -1)
{
qse_sio_close (fp);
return -1;
}
if (qse_awk_rtx_setglobal (
epa->run, QSE_AWK_GLOBAL_FNR, qse_awk_val_zero) == -1)
{
/* need to reset FNR */
qse_sio_close (fp);
return -1;
}
if (epa->handle != QSE_NULL &&
epa->handle != qse_sio_in &&
epa->handle != qse_sio_out &&
epa->handle != qse_sio_err)
{
qse_sio_close ((qse_sio_t*)epa->handle);
}
/*dprint (QSE_T("open the next console [%s]\n"), rd->ic.files[rd->ic.index]);*/
epa->handle = fp;
}
rd->ic.index++;
}
return n;
}
else if (cmd == QSE_AWK_IO_WRITE)
{
return qse_sio_putsn (
(qse_sio_t*)epa->handle,
data,
size
);
}
else if (cmd == QSE_AWK_IO_FLUSH)
{
return qse_sio_flush ((qse_sio_t*)epa->handle);
}
else if (cmd == QSE_AWK_IO_NEXT)
{
int n;
qse_sio_t* fp = (qse_sio_t*)epa->handle;
/*dprint (QSE_T("switching console[%s] of type %x\n"), epa->name, epa->type);*/
n = open_eio_console(epa);
if (n == -1) return -1;
if (n == 0)
{
/* if there is no more file, keep the previous handle */
return 0;
}
if (fp != QSE_NULL &&
fp != qse_sio_in &&
fp != qse_sio_out &&
fp != qse_sio_err)
{
qse_sio_close (fp);
}
return n;
}
return -1;
}
int qse_awk_runsimple (qse_awk_t* awk, qse_char_t** icf, qse_awk_runcbs_t* cbs)
{
qse_awk_runios_t ios;
runio_data_t rd;
rxtn_t rxtn;
qse_ntime_t now;
rd.ic.files = icf;
rd.ic.index = 0;
ios.pipe = awk_eio_pipe;
ios.file = awk_eio_file;
ios.console = awk_eio_console;
ios.data = &rd;
if (qse_gettime (&now) == -1) rxtn.seed = 0;
else rxtn.seed = (unsigned int)now;
srand (rxtn.seed);
return qse_awk_run (
awk,
QSE_NULL/*mfn*/,
&ios,
cbs,
QSE_NULL/*runarg*/,
&rxtn/*QSE_NULL*/
);
}
/*** EXTRA BUILTIN FUNCTIONS ***/
enum
{
BFN_MATH_LD,
BFN_MATH_D,
BFN_MATH_F
};
static int bfn_math_1 (
qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl, int type, void* f)
{
qse_size_t nargs;
qse_awk_val_t* a0;
qse_long_t lv;
qse_real_t rv;
qse_awk_val_t* r;
int n;
nargs = qse_awk_rtx_getnargs (run);
QSE_ASSERT (nargs == 1);
a0 = qse_awk_rtx_getarg (run, 0);
n = qse_awk_valtonum (run, a0, &lv, &rv);
if (n == -1) return -1;
if (n == 0) rv = (qse_real_t)lv;
if (type == BFN_MATH_LD)
{
long double (*rf) (long double) =
(long double(*)(long double))f;
r = qse_awk_makerealval (run, rf(rv));
}
else if (type == BFN_MATH_D)
{
double (*rf) (double) = (double(*)(double))f;
r = qse_awk_makerealval (run, rf(rv));
}
else
{
QSE_ASSERT (type == BFN_MATH_F);
float (*rf) (float) = (float(*)(float))f;
r = qse_awk_makerealval (run, rf(rv));
}
if (r == QSE_NULL)
{
qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);
return -1;
}
qse_awk_rtx_setretval (run, r);
return 0;
}
static int bfn_math_2 (
qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl, int type, void* f)
{
qse_size_t nargs;
qse_awk_val_t* a0, * a1;
qse_long_t lv0, lv1;
qse_real_t rv0, rv1;
qse_awk_val_t* r;
int n;
nargs = qse_awk_rtx_getnargs (run);
QSE_ASSERT (nargs == 2);
a0 = qse_awk_rtx_getarg (run, 0);
a1 = qse_awk_rtx_getarg (run, 1);
n = qse_awk_valtonum (run, a0, &lv0, &rv0);
if (n == -1) return -1;
if (n == 0) rv0 = (qse_real_t)lv0;
n = qse_awk_valtonum (run, a1, &lv1, &rv1);
if (n == -1) return -1;
if (n == 0) rv1 = (qse_real_t)lv1;
if (type == BFN_MATH_LD)
{
long double (*rf) (long double,long double) =
(long double(*)(long double,long double))f;
r = qse_awk_makerealval (run, rf(rv0,rv1));
}
else if (type == BFN_MATH_D)
{
double (*rf) (double,double) = (double(*)(double,double))f;
r = qse_awk_makerealval (run, rf(rv0,rv1));
}
else
{
QSE_ASSERT (type == BFN_MATH_F);
float (*rf) (float,float) = (float(*)(float,float))f;
r = qse_awk_makerealval (run, rf(rv0,rv1));
}
if (r == QSE_NULL)
{
qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);
return -1;
}
qse_awk_rtx_setretval (run, r);
return 0;
}
static int bfn_sin (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_SINL)
BFN_MATH_LD, (void*)sinl
#elif defined(HAVE_SIN)
BFN_MATH_D, (void*)sin
#elif defined(HAVE_SINF)
BFN_MATH_F, (void*)sinf
#else
#error ### no sin function available ###
#endif
);
}
static int bfn_cos (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_COSL)
BFN_MATH_LD, (void*)cosl
#elif defined(HAVE_COS)
BFN_MATH_D, (void*)cos
#elif defined(HAVE_COSF)
BFN_MATH_F, (void*)cosf
#else
#error ### no cos function available ###
#endif
);
}
static int bfn_tan (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_TANL)
BFN_MATH_LD, (void*)tanl
#elif defined(HAVE_TAN)
BFN_MATH_D, (void*)tan
#elif defined(HAVE_TANF)
BFN_MATH_F, (void*)tanf
#else
#error ### no tan function available ###
#endif
);
}
static int bfn_atan (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_ATANL)
BFN_MATH_LD, (void*)atanl
#elif defined(HAVE_ATAN)
BFN_MATH_D, (void*)atan
#elif defined(HAVE_ATANF)
BFN_MATH_F, (void*)atanf
#else
#error ### no atan function available ###
#endif
);
}
static int bfn_atan2 (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_2 (
run, fnm, fnl,
#if defined(HAVE_ATAN2L)
BFN_MATH_LD, (void*)atan2l
#elif defined(HAVE_ATAN2)
BFN_MATH_D, (void*)atan2
#elif defined(HAVE_ATAN2F)
BFN_MATH_F, (void*)atan2f
#else
#error ### no atan2 function available ###
#endif
);
}
static int bfn_log (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_LOGL)
BFN_MATH_LD, (void*)logl
#elif defined(HAVE_LOG)
BFN_MATH_D, (void*)log
#elif defined(HAVE_LOGF)
BFN_MATH_F, (void*)logf
#else
#error ### no log function available ###
#endif
);
}
static int bfn_exp (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_EXPL)
BFN_MATH_LD, (void*)expl
#elif defined(HAVE_EXP)
BFN_MATH_D, (void*)exp
#elif defined(HAVE_EXPF)
BFN_MATH_F, (void*)expf
#else
#error ### no exp function available ###
#endif
);
}
static int bfn_sqrt (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
return bfn_math_1 (
run, fnm, fnl,
#if defined(HAVE_SQRTL)
BFN_MATH_LD, (void*)sqrtl
#elif defined(HAVE_SQRT)
BFN_MATH_D, (void*)sqrt
#elif defined(HAVE_SQRTF)
BFN_MATH_F, (void*)sqrtf
#else
#error ### no sqrt function available ###
#endif
);
}
static int bfn_int (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
qse_size_t nargs;
qse_awk_val_t* a0;
qse_long_t lv;
qse_real_t rv;
qse_awk_val_t* r;
int n;
nargs = qse_awk_rtx_getnargs (run);
QSE_ASSERT (nargs == 1);
a0 = qse_awk_rtx_getarg (run, 0);
n = qse_awk_valtonum (run, a0, &lv, &rv);
if (n == -1) return -1;
if (n == 1) lv = (qse_long_t)rv;
r = qse_awk_makeintval (run, lv);
if (r == QSE_NULL)
{
qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);
return -1;
}
qse_awk_rtx_setretval (run, r);
return 0;
}
static int bfn_rand (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
qse_awk_val_t* r;
r = qse_awk_makeintval (run, rand());
if (r == QSE_NULL)
{
qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);
return -1;
}
qse_awk_rtx_setretval (run, r);
return 0;
}
static int bfn_srand (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
qse_size_t nargs;
qse_awk_val_t* a0;
qse_long_t lv;
qse_real_t rv;
qse_awk_val_t* r;
int n;
unsigned int prev;
rxtn_t* rxtn;
rxtn = (rxtn_t*)qse_awk_rtx_getdata (run);
nargs = qse_awk_rtx_getnargs (run);
QSE_ASSERT (nargs == 0 || nargs == 1);
prev = rxtn->seed;
if (nargs == 1)
{
a0 = qse_awk_rtx_getarg (run, 0);
n = qse_awk_valtonum (run, a0, &lv, &rv);
if (n == -1) return -1;
if (n == 1) lv = (qse_long_t)rv;
rxtn->seed = lv;
}
else
{
qse_ntime_t now;
if (qse_gettime(&now) == -1) rxtn->seed >>= 1;
else rxtn->seed = (unsigned int)now;
}
srand (rxtn->seed);
r = qse_awk_makeintval (run, prev);
if (r == QSE_NULL)
{
qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);
return -1;
}
qse_awk_rtx_setretval (run, r);
return 0;
}
static int bfn_system (qse_awk_rtx_t* run, const qse_char_t* fnm, qse_size_t fnl)
{
qse_size_t nargs;
qse_awk_val_t* v;
qse_char_t* str, * ptr, * end;
qse_size_t len;
int n = 0;
nargs = qse_awk_rtx_getnargs (run);
QSE_ASSERT (nargs == 1);
v = qse_awk_rtx_getarg (run, 0);
if (v->type == QSE_AWK_VAL_STR)
{
str = ((qse_awk_val_str_t*)v)->ptr;
len = ((qse_awk_val_str_t*)v)->len;
}
else
{
str = qse_awk_valtostr (
run, v, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL) return -1;
}
/* the target name contains a null character.
* make system return -1 */
ptr = str; end = str + len;
while (ptr < end)
{
if (*ptr == QSE_T('\0'))
{
n = -1;
goto skip_system;
}
ptr++;
}
#if defined(_WIN32)
n = _tsystem (str);
#elif defined(QSE_CHAR_IS_MCHAR)
n = system (str);
#else
{
char* mbs;
qse_size_t mbl;
mbs = (char*) qse_awk_alloc (run->awk, len*5+1);
if (mbs == QSE_NULL)
{
n = -1;
goto skip_system;
}
/* at this point, the string is guaranteed to be
* null-terminating. so qse_wcstombs() can be used to convert
* the string, not qse_wcsntombsn(). */
mbl = len * 5;
if (qse_wcstombs (str, mbs, &mbl) != len && mbl >= len * 5)
{
/* not the entire string is converted.
* mbs is not null-terminated properly. */
n = -1;
goto skip_system_mbs;
}
mbs[mbl] = '\0';
n = system (mbs);
skip_system_mbs:
qse_awk_free (run->awk, mbs);
}
#endif
skip_system:
if (v->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str);
v = qse_awk_makeintval (run, (qse_long_t)n);
if (v == QSE_NULL)
{
/*qse_awk_setrunerrnum (run, QSE_AWK_ENOMEM);*/
return -1;
}
qse_awk_rtx_setretval (run, v);
return 0;
}
#define ADD_FUNC(awk,name,min,max,bfn) \
if (qse_awk_addfunc (\
(awk), (name), qse_strlen(name), \
0, (min), (max), QSE_NULL, (bfn)) == QSE_NULL) return -1;
static int add_functions (qse_awk_t* awk)
{
ADD_FUNC (awk, QSE_T("sin"), 1, 1, bfn_sin);
ADD_FUNC (awk, QSE_T("cos"), 1, 1, bfn_cos);
ADD_FUNC (awk, QSE_T("tan"), 1, 1, bfn_tan);
ADD_FUNC (awk, QSE_T("atan"), 1, 1, bfn_atan);
ADD_FUNC (awk, QSE_T("atan2"), 2, 2, bfn_atan2);
ADD_FUNC (awk, QSE_T("log"), 1, 1, bfn_log);
ADD_FUNC (awk, QSE_T("exp"), 1, 1, bfn_exp);
ADD_FUNC (awk, QSE_T("sqrt"), 1, 1, bfn_sqrt);
ADD_FUNC (awk, QSE_T("int"), 1, 1, bfn_int);
ADD_FUNC (awk, QSE_T("rand"), 0, 0, bfn_rand);
ADD_FUNC (awk, QSE_T("srand"), 0, 1, bfn_srand);
ADD_FUNC (awk, QSE_T("system"), 1, 1, bfn_system);
return 0;
}