1301 lines
30 KiB
C
1301 lines
30 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <qse/awk/stdawk.h>
|
|
#include <qse/cmn/sll.h>
|
|
#include <qse/cmn/mem.h>
|
|
#include <qse/cmn/chr.h>
|
|
#include <qse/cmn/opt.h>
|
|
#include <qse/cmn/path.h>
|
|
#include <qse/cmn/main.h>
|
|
#include <qse/cmn/mbwc.h>
|
|
#include <qse/cmn/xma.h>
|
|
#include <qse/cmn/fmt.h>
|
|
|
|
#include <qse/si/glob.h>
|
|
#include <qse/si/sio.h>
|
|
#include <qse/si/intr.h>
|
|
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <locale.h>
|
|
|
|
#define ENABLE_CALLBACK
|
|
#define ABORT(label) goto label
|
|
|
|
#if defined(_WIN32)
|
|
# include <winsock2.h>
|
|
# include <windows.h>
|
|
#elif defined(__OS2__)
|
|
# define INCL_ERRORS
|
|
# include <os2.h>
|
|
#elif defined(__DOS__)
|
|
# include <dos.h>
|
|
# include <tcp.h> /* watt-32 */
|
|
#else
|
|
# include <unistd.h>
|
|
# include <errno.h>
|
|
# if defined(QSE_ENABLE_LIBLTDL)
|
|
# include <ltdl.h>
|
|
# define USE_LTDL
|
|
# elif defined(HAVE_DLFCN_H)
|
|
# include <dlfcn.h>
|
|
# define USE_DLFCN
|
|
# else
|
|
# error UNSUPPORTED DYNAMIC LINKER
|
|
# endif
|
|
|
|
#endif
|
|
|
|
static qse_awk_rtx_t* app_rtx = QSE_NULL;
|
|
static int app_debug = 0;
|
|
|
|
typedef struct arg_t arg_t;
|
|
typedef struct xarg_t xarg_t;
|
|
|
|
struct xarg_t
|
|
{
|
|
qse_mmgr_t* mmgr;
|
|
qse_char_t** ptr;
|
|
qse_size_t size;
|
|
qse_size_t capa;
|
|
};
|
|
|
|
struct arg_t
|
|
{
|
|
int incl_conv;
|
|
qse_awk_parsestd_t* psin; /* input source streams */
|
|
qse_char_t* osf; /* output source file */
|
|
|
|
xarg_t icf; /* input console files */
|
|
|
|
qse_htb_t* gvm; /* global variable map */
|
|
qse_char_t* fs; /* field separator */
|
|
qse_char_t* call; /* function to call */
|
|
qse_cmgr_t* script_cmgr;
|
|
qse_cmgr_t* console_cmgr;
|
|
|
|
unsigned int modern: 1;
|
|
unsigned int classic: 1;
|
|
int opton;
|
|
int optoff;
|
|
|
|
qse_ulong_t memlimit;
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
qse_ulong_t failmalloc;
|
|
#endif
|
|
};
|
|
|
|
struct gvmv_t
|
|
{
|
|
int idx;
|
|
qse_cstr_t str;
|
|
};
|
|
|
|
static void dprint (const qse_char_t* fmt, ...)
|
|
{
|
|
if (app_debug)
|
|
{
|
|
va_list ap;
|
|
va_start (ap, fmt);
|
|
qse_sio_putstrvf (QSE_STDERR, fmt, ap);
|
|
va_end (ap);
|
|
}
|
|
}
|
|
|
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__) && defined(SIGPIPE)
|
|
static int setsignal (int sig, void(*handler)(int), int restart)
|
|
{
|
|
struct sigaction sa_int;
|
|
|
|
sa_int.sa_handler = handler;
|
|
sigemptyset (&sa_int.sa_mask);
|
|
|
|
sa_int.sa_flags = 0;
|
|
|
|
if (restart)
|
|
{
|
|
#if defined(SA_RESTART)
|
|
sa_int.sa_flags |= SA_RESTART;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(SA_INTERRUPT)
|
|
sa_int.sa_flags |= SA_INTERRUPT;
|
|
#endif
|
|
}
|
|
return sigaction (sig, &sa_int, NULL);
|
|
}
|
|
#endif
|
|
|
|
static void stop_run (void* arg)
|
|
{
|
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__)
|
|
int e = errno;
|
|
#endif
|
|
|
|
qse_awk_rtx_halt (app_rtx);
|
|
|
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__)
|
|
errno = e;
|
|
#endif
|
|
}
|
|
|
|
static void set_intr_run (void)
|
|
{
|
|
qse_set_intr_handler (stop_run, QSE_NULL);
|
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__) && defined(SIGPIPE)
|
|
setsignal (SIGPIPE, SIG_IGN, 0);
|
|
#endif
|
|
}
|
|
|
|
static void unset_intr_run (void)
|
|
{
|
|
qse_clear_intr_handler ();
|
|
#if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__) && defined(SIGPIPE)
|
|
setsignal (SIGPIPE, SIG_DFL, 0);
|
|
#endif
|
|
}
|
|
|
|
static qse_htb_walk_t print_awk_value (qse_htb_t* map, qse_htb_pair_t* pair, void* arg)
|
|
{
|
|
qse_awk_rtx_t* rtx = (qse_awk_rtx_t*)arg;
|
|
qse_char_t* str;
|
|
qse_size_t len;
|
|
qse_awk_errinf_t oerrinf;
|
|
|
|
qse_awk_rtx_geterrinf (rtx, &oerrinf);
|
|
|
|
str = qse_awk_rtx_valtostrdup(rtx, QSE_HTB_VPTR(pair), &len);
|
|
if (str == QSE_NULL)
|
|
{
|
|
if (qse_awk_rtx_geterrnum(rtx) == QSE_AWK_EVALTOSTR)
|
|
{
|
|
dprint (QSE_T("%.*s = [not printable]\n"),
|
|
(int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair));
|
|
|
|
qse_awk_rtx_seterrinf (rtx, &oerrinf);
|
|
}
|
|
else
|
|
{
|
|
dprint (QSE_T("***OUT OF MEMORY***\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprint (QSE_T("%.*s = %.*s\n"),
|
|
(int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair),
|
|
(int)len, str);
|
|
qse_awk_freemem (qse_awk_rtx_getawk(rtx), str);
|
|
}
|
|
|
|
return QSE_HTB_WALK_FORWARD;
|
|
}
|
|
|
|
struct set_global_ctx_t
|
|
{
|
|
qse_awk_rtx_t* rtx;
|
|
int fail;
|
|
};
|
|
|
|
static qse_htb_walk_t set_global (qse_htb_t* map, qse_htb_pair_t* pair, void* arg)
|
|
{
|
|
qse_awk_val_t* v;
|
|
struct set_global_ctx_t* ctx = (struct set_global_ctx_t*)arg;
|
|
struct gvmv_t* gvmv = (struct gvmv_t*)QSE_HTB_VPTR(pair);
|
|
|
|
v = qse_awk_rtx_makenstrvalwithcstr(ctx->rtx, &gvmv->str);
|
|
if (v == QSE_NULL)
|
|
{
|
|
ctx->fail = 1;
|
|
return QSE_HTB_WALK_STOP;
|
|
}
|
|
|
|
qse_awk_rtx_refupval (ctx->rtx, v);
|
|
qse_awk_rtx_setgbl (ctx->rtx, gvmv->idx, v);
|
|
qse_awk_rtx_refdownval (ctx->rtx, v);
|
|
|
|
return QSE_HTB_WALK_FORWARD;
|
|
}
|
|
|
|
static int apply_fs_and_gvm (qse_awk_rtx_t* rtx, struct arg_t* arg)
|
|
{
|
|
if (arg->fs)
|
|
{
|
|
qse_awk_val_t* fs;
|
|
|
|
/* compose a string value to use to set FS to */
|
|
fs = qse_awk_rtx_makestrvalwithstr (rtx, arg->fs);
|
|
if (fs == QSE_NULL) return -1;
|
|
|
|
/* change FS according to the command line argument */
|
|
qse_awk_rtx_refupval (rtx, fs);
|
|
qse_awk_rtx_setgbl (rtx, QSE_AWK_GBL_FS, fs);
|
|
qse_awk_rtx_refdownval (rtx, fs);
|
|
}
|
|
|
|
if (arg->gvm)
|
|
{
|
|
/* set the value of user-defined global variables
|
|
* to a runtime context */
|
|
struct set_global_ctx_t ctx;
|
|
ctx.fail = 0;
|
|
ctx.rtx = rtx;
|
|
qse_htb_walk (arg->gvm, set_global, &ctx);
|
|
if (ctx.fail) return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void dprint_return (qse_awk_rtx_t* rtx, qse_awk_val_t* ret)
|
|
{
|
|
qse_size_t len;
|
|
qse_char_t* str;
|
|
|
|
if (qse_awk_rtx_isnilval (rtx, ret))
|
|
{
|
|
dprint (QSE_T("[RETURN] - ***nil***\n"));
|
|
}
|
|
else
|
|
{
|
|
str = qse_awk_rtx_valtostrdup (rtx, ret, &len);
|
|
if (str == QSE_NULL)
|
|
{
|
|
dprint (QSE_T("[RETURN] - ***OUT OF MEMORY***\n"));
|
|
}
|
|
else
|
|
{
|
|
dprint (QSE_T("[RETURN] - [%.*s]\n"), (int)len, str);
|
|
qse_awk_freemem (qse_awk_rtx_getawk(rtx), str);
|
|
}
|
|
}
|
|
|
|
dprint (QSE_T("[NAMED VARIABLES]\n"));
|
|
qse_htb_walk (qse_awk_rtx_getnvmap(rtx), print_awk_value, rtx);
|
|
dprint (QSE_T("[END NAMED VARIABLES]\n"));
|
|
}
|
|
|
|
#if defined(ENABLE_CALLBACK)
|
|
static void on_statement (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
|
|
{
|
|
dprint (QSE_T("running %d at line %zu\n"), (int)nde->type, (qse_size_t)nde->loc.line);
|
|
}
|
|
#endif
|
|
|
|
static void print_version (void)
|
|
{
|
|
qse_sio_putstrf (QSE_STDOUT, QSE_T("QSEAWK %hs\n"), QSE_PACKAGE_VERSION);
|
|
qse_sio_putstrf (QSE_STDOUT, QSE_T("Copyright 2006-2014 Chung, Hyung-Hwan\n"));
|
|
}
|
|
|
|
static void print_error (const qse_char_t* fmt, ...)
|
|
{
|
|
va_list va;
|
|
|
|
qse_sio_putstr (QSE_STDERR, QSE_T("ERROR: "));
|
|
va_start (va, fmt);
|
|
qse_sio_putstrvf (QSE_STDERR, fmt, va);
|
|
va_end (va);
|
|
}
|
|
|
|
static void print_warning (const qse_char_t* fmt, ...)
|
|
{
|
|
va_list va;
|
|
|
|
qse_sio_putstr (QSE_STDERR, QSE_T("WARNING: "));
|
|
va_start (va, fmt);
|
|
qse_sio_putstrvf (QSE_STDERR, fmt, va);
|
|
va_end (va);
|
|
}
|
|
|
|
struct opttab_t
|
|
{
|
|
const qse_char_t* name;
|
|
int opt;
|
|
const qse_char_t* desc;
|
|
} opttab[] =
|
|
{
|
|
{ QSE_T("implicit"), QSE_AWK_IMPLICIT, QSE_T("allow undeclared variables") },
|
|
{ QSE_T("nextofile"), QSE_AWK_NEXTOFILE, QSE_T("enable nextofile & OFILENAME") },
|
|
{ QSE_T("rio"), QSE_AWK_RIO, QSE_T("enable builtin I/O including getline & print") },
|
|
{ QSE_T("rwpipe"), QSE_AWK_RWPIPE, QSE_T("allow a dual-directional pipe") },
|
|
{ QSE_T("newline"), QSE_AWK_NEWLINE, QSE_T("enable a newline to terminate a statement") },
|
|
{ QSE_T("striprecspc"), QSE_AWK_STRIPRECSPC, QSE_T("strip spaces in splitting a record") },
|
|
{ QSE_T("stripstrspc"), QSE_AWK_STRIPSTRSPC, QSE_T("strip spaces in string-to-number conversion") },
|
|
{ QSE_T("blankconcat"), QSE_AWK_BLANKCONCAT, QSE_T("enable concatenation by blanks") },
|
|
{ QSE_T("crlf"), QSE_AWK_CRLF, QSE_T("use CRLF for a newline") },
|
|
{ QSE_T("flexmap"), QSE_AWK_FLEXMAP, QSE_T("allow a map to be assigned or returned") },
|
|
{ QSE_T("pablock"), QSE_AWK_PABLOCK, QSE_T("enable pattern-action loop") },
|
|
{ QSE_T("rexbound"), QSE_AWK_REXBOUND, QSE_T("enable {n,m} in a regular expression") },
|
|
{ QSE_T("ncmponstr"), QSE_AWK_NCMPONSTR, QSE_T("perform numeric comparsion on numeric strings") },
|
|
{ QSE_T("strictnaming"), QSE_AWK_STRICTNAMING, QSE_T("enable the strict naming rule") },
|
|
{ QSE_T("tolerant"), QSE_AWK_TOLERANT, QSE_T("make more fault-tolerant") },
|
|
{ QSE_NULL, 0, QSE_NULL }
|
|
};
|
|
|
|
static void print_usage (qse_sio_t* out, const qse_char_t* argv0)
|
|
{
|
|
int j;
|
|
const qse_char_t* b = qse_basename (argv0);
|
|
|
|
qse_fprintf (out, QSE_T("USAGE: %s [options] -f sourcefile [ -- ] [datafile]*\n"), b);
|
|
qse_fprintf (out, QSE_T(" %s [options] [ -- ] sourcestring [datafile]*\n"), b);
|
|
qse_fprintf (out, QSE_T("Where options are:\n"));
|
|
qse_fprintf (out, QSE_T(" -h/--help print this message\n"));
|
|
qse_fprintf (out, QSE_T(" --version print version\n"));
|
|
qse_fprintf (out, QSE_T(" -D show extra information\n"));
|
|
qse_fprintf (out, QSE_T(" -c/--call name call a function instead of entering\n"));
|
|
qse_fprintf (out, QSE_T(" the pattern-action loop. [datafile]* is\n"));
|
|
qse_fprintf (out, QSE_T(" passed to the function as parameters\n"));
|
|
qse_fprintf (out, QSE_T(" -f/--file sourcefile set the source script file\n"));
|
|
qse_fprintf (out, QSE_T(" -d/--deparsed-file deparsedfile set the deparsing output file\n"));
|
|
qse_fprintf (out, QSE_T(" -F/--field-separator string set a field separator(FS)\n"));
|
|
qse_fprintf (out, QSE_T(" -v/--assign var=value add a global variable with a value\n"));
|
|
qse_fprintf (out, QSE_T(" -m/--memory-limit number limit the memory usage (bytes)\n"));
|
|
qse_fprintf (out, QSE_T(" -w expand datafile wildcards\n"));
|
|
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
qse_fprintf (out, QSE_T(" -X number fail the number'th memory allocation\n"));
|
|
#endif
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
qse_fprintf (out, QSE_T(" --script-encoding string specify script file encoding name\n"));
|
|
qse_fprintf (out, QSE_T(" --console-encoding string specify console encoding name\n"));
|
|
#endif
|
|
qse_fprintf (out, QSE_T(" --modern run in the modern mode(default)\n"));
|
|
qse_fprintf (out, QSE_T(" --classic run in the classic mode\n"));
|
|
|
|
for (j = 0; opttab[j].name; j++)
|
|
{
|
|
qse_fprintf (out,
|
|
QSE_T(" --%-18s on/off %s\n"),
|
|
opttab[j].name, opttab[j].desc);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
static int collect_into_xarg (const qse_cstr_t* path, void* ctx)
|
|
{
|
|
xarg_t* xarg = (xarg_t*)ctx;
|
|
|
|
if (xarg->size <= xarg->capa)
|
|
{
|
|
qse_char_t** tmp;
|
|
|
|
tmp = QSE_MMGR_REALLOC (
|
|
xarg->mmgr, xarg->ptr,
|
|
QSE_SIZEOF(*tmp) * (xarg->capa + 128 + 1));
|
|
if (tmp == QSE_NULL) return -1;
|
|
|
|
xarg->ptr = tmp;
|
|
xarg->capa += 128;
|
|
}
|
|
|
|
xarg->ptr[xarg->size] = qse_strdup (path->ptr, xarg->mmgr);
|
|
if (xarg->ptr[xarg->size] == QSE_NULL) return -1;
|
|
xarg->size++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void purge_xarg (xarg_t* xarg)
|
|
{
|
|
if (xarg->ptr)
|
|
{
|
|
qse_size_t i;
|
|
|
|
for (i = 0; i < xarg->size; i++)
|
|
QSE_MMGR_FREE (xarg->mmgr, xarg->ptr[i]);
|
|
QSE_MMGR_FREE (xarg->mmgr, xarg->ptr);
|
|
|
|
xarg->size = 0;
|
|
xarg->capa = 0;
|
|
xarg->ptr = QSE_NULL;
|
|
}
|
|
}
|
|
|
|
static int expand_wildcard (int argc, qse_char_t* argv[], int glob, xarg_t* xarg)
|
|
{
|
|
int i;
|
|
qse_cstr_t tmp;
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
int x;
|
|
|
|
if (glob)
|
|
{
|
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
|
int glob_flags = QSE_GLOB_TOLERANT | QSE_GLOB_PERIOD | QSE_GLOB_NOESCAPE | QSE_GLOB_IGNORECASE;
|
|
#else
|
|
int glob_flags = QSE_GLOB_TOLERANT | QSE_GLOB_PERIOD;
|
|
#endif
|
|
|
|
x = qse_glob (
|
|
argv[i], collect_into_xarg, xarg,
|
|
glob_flags, xarg->mmgr, qse_getdflcmgr()
|
|
);
|
|
if (x <= -1) return -1;
|
|
}
|
|
else x = 0;
|
|
|
|
if (x == 0)
|
|
{
|
|
/* not expanded. just use it as is */
|
|
tmp.ptr = argv[i];
|
|
tmp.len = qse_strlen(argv[i]);
|
|
if (collect_into_xarg (&tmp, xarg) <= -1) return -1;
|
|
}
|
|
}
|
|
|
|
xarg->ptr[xarg->size] = QSE_NULL;
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
|
|
{
|
|
static qse_opt_lng_t lng[] =
|
|
{
|
|
|
|
{ QSE_T(":implicit"), QSE_T('\0') },
|
|
{ QSE_T(":nextofile"), QSE_T('\0') },
|
|
{ QSE_T(":rio"), QSE_T('\0') },
|
|
{ QSE_T(":rwpipe"), QSE_T('\0') },
|
|
{ QSE_T(":newline"), QSE_T('\0') },
|
|
{ QSE_T(":striprecspc"), QSE_T('\0') },
|
|
{ QSE_T(":stripstrspc"), QSE_T('\0') },
|
|
{ QSE_T(":blankconcat"), QSE_T('\0') },
|
|
{ QSE_T(":crlf"), QSE_T('\0') },
|
|
{ QSE_T(":flexmap"), QSE_T('\0') },
|
|
{ QSE_T(":pablock"), QSE_T('\0') },
|
|
{ QSE_T(":rexbound"), QSE_T('\0') },
|
|
{ QSE_T(":ncmponstr"), QSE_T('\0') },
|
|
{ QSE_T(":strictnaming"), QSE_T('\0') },
|
|
{ QSE_T(":tolerant"), QSE_T('\0') },
|
|
|
|
{ QSE_T(":call"), QSE_T('c') },
|
|
{ QSE_T(":file"), QSE_T('f') },
|
|
{ QSE_T(":deparsed-file"), QSE_T('d') },
|
|
{ QSE_T(":field-separator"), QSE_T('F') },
|
|
{ QSE_T(":assign"), QSE_T('v') },
|
|
{ QSE_T(":memory-limit"), QSE_T('m') },
|
|
|
|
{ QSE_T(":script-encoding"), QSE_T('\0') },
|
|
{ QSE_T(":console-encoding"), QSE_T('\0') },
|
|
|
|
{ QSE_T("modern"), QSE_T('\0') },
|
|
{ QSE_T("classic"), QSE_T('\0') },
|
|
|
|
{ QSE_T("version"), QSE_T('\0') },
|
|
{ QSE_T("help"), QSE_T('h') },
|
|
{ QSE_NULL, QSE_T('\0') }
|
|
};
|
|
|
|
static qse_opt_t opt =
|
|
{
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
QSE_T("hDc:f:d:F:v:m:wX:"),
|
|
#else
|
|
QSE_T("hDc:f:d:F:v:m:w"),
|
|
#endif
|
|
lng
|
|
};
|
|
|
|
qse_cint_t c;
|
|
|
|
qse_size_t i;
|
|
qse_size_t isfc = 16; /* the capacity of isf */
|
|
qse_size_t isfl = 0; /* number of input source files */
|
|
qse_awk_parsestd_t* isf = QSE_NULL; /* input source files */
|
|
|
|
qse_char_t* osf = QSE_NULL; /* output source file */
|
|
|
|
qse_htb_t* gvm = QSE_NULL; /* global variable map */
|
|
qse_char_t* fs = QSE_NULL; /* field separator */
|
|
qse_char_t* call = QSE_NULL; /* function to call */
|
|
|
|
int oops_ret = -1;
|
|
int do_glob = 0;
|
|
|
|
isf = QSE_MMGR_ALLOC (arg->icf.mmgr, QSE_SIZEOF(*isf) * isfc);
|
|
if (isf == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("out of memory\n"));
|
|
goto oops;
|
|
}
|
|
|
|
gvm = qse_htb_open (
|
|
QSE_MMGR_GETDFL(), 0, 30, 70,
|
|
QSE_SIZEOF(qse_char_t), QSE_SIZEOF(struct gvmv_t)
|
|
);
|
|
if (gvm == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("out of memory\n"));
|
|
goto oops;
|
|
}
|
|
|
|
qse_htb_setstyle (gvm,
|
|
qse_gethtbstyle(QSE_HTB_STYLE_INLINE_VALUE_COPIER)
|
|
);
|
|
|
|
while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
|
|
{
|
|
switch (c)
|
|
{
|
|
case QSE_T('h'):
|
|
oops_ret = 0;
|
|
goto oops;
|
|
|
|
case QSE_T('D'):
|
|
{
|
|
app_debug = 1;
|
|
break;
|
|
}
|
|
|
|
case QSE_T('c'):
|
|
{
|
|
call = opt.arg;
|
|
break;
|
|
}
|
|
|
|
case QSE_T('f'):
|
|
{
|
|
if (isfl >= isfc - 1) /* -1 for last QSE_NULL */
|
|
{
|
|
qse_awk_parsestd_t* tmp;
|
|
tmp = QSE_MMGR_REALLOC (arg->icf.mmgr, isf, QSE_SIZEOF(*isf)*(isfc+16));
|
|
if (tmp == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("out of memory\n"));
|
|
goto oops;
|
|
}
|
|
|
|
isf = tmp;
|
|
isfc = isfc + 16;
|
|
}
|
|
|
|
isf[isfl].type = QSE_AWK_PARSESTD_FILE;
|
|
isf[isfl].u.file.path = opt.arg;
|
|
isf[isfl].u.file.cmgr = QSE_NULL;
|
|
isfl++;
|
|
break;
|
|
}
|
|
|
|
case QSE_T('d'):
|
|
{
|
|
osf = opt.arg;
|
|
break;
|
|
}
|
|
|
|
case QSE_T('F'):
|
|
{
|
|
fs = opt.arg;
|
|
break;
|
|
}
|
|
|
|
case QSE_T('v'):
|
|
{
|
|
struct gvmv_t gvmv;
|
|
qse_char_t* eq;
|
|
|
|
eq = qse_strchr(opt.arg, QSE_T('='));
|
|
if (eq == QSE_NULL)
|
|
{
|
|
if (opt.lngopt)
|
|
print_error (QSE_T("no value for '%s' in '%s'\n"), opt.arg, opt.lngopt);
|
|
else
|
|
print_error (QSE_T("no value for '%s' in '%c'\n"), opt.arg, opt.opt);
|
|
goto oops;
|
|
}
|
|
|
|
*eq = QSE_T('\0');
|
|
|
|
gvmv.idx = -1;
|
|
gvmv.str.ptr = ++eq;
|
|
gvmv.str.len = qse_strlen(eq);
|
|
|
|
/* +1 for null-termination of the key in the table */
|
|
if (qse_htb_upsert (gvm, opt.arg, qse_strlen(opt.arg) + 1, &gvmv, 1) == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("out of memory\n"));
|
|
goto oops;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case QSE_T('m'):
|
|
{
|
|
arg->memlimit = qse_strtoulong (opt.arg, 10, QSE_NULL);
|
|
break;
|
|
}
|
|
|
|
case QSE_T('w'):
|
|
{
|
|
do_glob = 1;
|
|
break;
|
|
}
|
|
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
case QSE_T('X'):
|
|
{
|
|
arg->failmalloc = qse_strtoulong (opt.arg, 10, QSE_NULL);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
case QSE_T('\0'):
|
|
{
|
|
/* a long option with no corresponding short option */
|
|
qse_size_t i;
|
|
|
|
if (qse_strcmp(opt.lngopt, QSE_T("version")) == 0)
|
|
{
|
|
print_version ();
|
|
oops_ret = 2;
|
|
goto oops;
|
|
}
|
|
else if (qse_strcmp(opt.lngopt, QSE_T("script-encoding")) == 0)
|
|
{
|
|
arg->script_cmgr = qse_findcmgr (opt.arg);
|
|
if (arg->script_cmgr == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("unknown script encoding - %s\n"), opt.arg);
|
|
oops_ret = 3;
|
|
goto oops;
|
|
}
|
|
}
|
|
else if (qse_strcmp(opt.lngopt, QSE_T("console-encoding")) == 0)
|
|
{
|
|
arg->console_cmgr = qse_findcmgr (opt.arg);
|
|
if (arg->console_cmgr == QSE_NULL)
|
|
{
|
|
print_error (QSE_T("unknown console encoding - %s\n"), opt.arg);
|
|
oops_ret = 3;
|
|
goto oops;
|
|
}
|
|
}
|
|
else if (qse_strcmp(opt.lngopt, QSE_T("modern")) == 0)
|
|
{
|
|
arg->modern = 1;
|
|
}
|
|
else if (qse_strcmp(opt.lngopt, QSE_T("classic")) == 0)
|
|
{
|
|
arg->classic = 1;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; opttab[i].name; i++)
|
|
{
|
|
if (qse_strcmp (opt.lngopt, opttab[i].name) == 0)
|
|
{
|
|
if (qse_strcmp (opt.arg, QSE_T("off")) == 0)
|
|
arg->optoff |= opttab[i].opt;
|
|
else if (qse_strcmp (opt.arg, QSE_T("on")) == 0)
|
|
arg->opton |= opttab[i].opt;
|
|
else
|
|
{
|
|
print_error (QSE_T("invalid value '%s' for '%s' - use 'on' or 'off'\n"), opt.arg, opt.lngopt);
|
|
oops_ret = 3;
|
|
goto oops;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case QSE_T('?'):
|
|
{
|
|
if (opt.lngopt)
|
|
print_error (QSE_T("illegal option - '%s'\n"), opt.lngopt);
|
|
else
|
|
print_error (QSE_T("illegal option - '%c'\n"), opt.opt);
|
|
|
|
goto oops;
|
|
}
|
|
|
|
case QSE_T(':'):
|
|
{
|
|
if (opt.lngopt)
|
|
print_error (QSE_T("bad argument for '%s'\n"), opt.lngopt);
|
|
else
|
|
print_error (QSE_T("bad argument for '%c'\n"), opt.opt);
|
|
|
|
goto oops;
|
|
}
|
|
|
|
default:
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
if (isfl <= 0)
|
|
{
|
|
/* no -f specified */
|
|
if (opt.ind >= argc)
|
|
{
|
|
/* no source code specified */
|
|
goto oops;
|
|
}
|
|
|
|
/* the source code is the string, not from the file */
|
|
isf[isfl].type = QSE_AWK_PARSESTD_STR;
|
|
isf[isfl].u.str.ptr = argv[opt.ind++];
|
|
isf[isfl].u.str.len = qse_strlen(isf[isfl].u.str.ptr);
|
|
|
|
isfl++;
|
|
}
|
|
|
|
for (i = 0; i < isfl ; i++)
|
|
{
|
|
if (isf[i].type == QSE_AWK_PARSESTD_FILE)
|
|
isf[i].u.file.cmgr = arg->script_cmgr;
|
|
}
|
|
|
|
isf[isfl].type = QSE_AWK_PARSESTD_NULL;
|
|
arg->psin = isf;
|
|
|
|
if (opt.ind < argc)
|
|
{
|
|
/* the remaining arguments are input console file names */
|
|
if (expand_wildcard (argc - opt.ind, &argv[opt.ind], do_glob, &arg->icf) <= -1)
|
|
{
|
|
print_error (QSE_T("failed to expand wildcard\n"));
|
|
goto oops;
|
|
}
|
|
}
|
|
|
|
arg->osf = osf;
|
|
arg->gvm = gvm;
|
|
arg->fs = fs;
|
|
arg->call = call;
|
|
|
|
return 1;
|
|
|
|
oops:
|
|
if (gvm) qse_htb_close (gvm);
|
|
purge_xarg (&arg->icf);
|
|
if (isf)
|
|
{
|
|
if (arg->incl_conv) QSE_MMGR_FREE (arg->icf.mmgr, isf[0].u.str.ptr);
|
|
QSE_MMGR_FREE (arg->icf.mmgr, isf);
|
|
}
|
|
return oops_ret;
|
|
}
|
|
|
|
static void freearg (struct arg_t* arg)
|
|
{
|
|
if (arg->psin)
|
|
{
|
|
if (arg->incl_conv) QSE_MMGR_FREE (arg->icf.mmgr, arg->psin[0].u.str.ptr);
|
|
QSE_MMGR_FREE (arg->icf.mmgr, arg->psin);
|
|
}
|
|
|
|
/*if (arg->osf != QSE_NULL) free (arg->osf);*/
|
|
purge_xarg (&arg->icf);
|
|
if (arg->gvm != QSE_NULL) qse_htb_close (arg->gvm);
|
|
}
|
|
|
|
static void print_awkerr (qse_awk_t* awk)
|
|
{
|
|
const qse_awk_loc_t* loc = qse_awk_geterrloc (awk);
|
|
|
|
print_error (
|
|
QSE_T("CODE %d LINE %zu COLUMN %zu %s%s%s- %s\n"),
|
|
qse_awk_geterrnum(awk),
|
|
(qse_size_t)loc->line,
|
|
(qse_size_t)loc->colm,
|
|
((loc->file == QSE_NULL)? QSE_T(""): QSE_T("FILE ")),
|
|
((loc->file == QSE_NULL)? QSE_T(""): loc->file),
|
|
((loc->file == QSE_NULL)? QSE_T(""): QSE_T(" ")),
|
|
qse_awk_geterrmsg(awk)
|
|
);
|
|
}
|
|
|
|
static void print_rtxerr (qse_awk_rtx_t* rtx)
|
|
{
|
|
const qse_awk_loc_t* loc = qse_awk_rtx_geterrloc (rtx);
|
|
|
|
print_error (
|
|
QSE_T("CODE %d LINE %zu COLUMN %zu %s%s%s- %s\n"),
|
|
qse_awk_rtx_geterrnum(rtx),
|
|
(qse_size_t)loc->line,
|
|
(qse_size_t)loc->colm,
|
|
((loc->file == QSE_NULL)? QSE_T(""): QSE_T("FILE ")),
|
|
((loc->file == QSE_NULL)? QSE_T(""): loc->file),
|
|
((loc->file == QSE_NULL)? QSE_T(""): QSE_T(" ")),
|
|
qse_awk_rtx_geterrmsg(rtx)
|
|
);
|
|
}
|
|
|
|
struct add_global_ctx_t
|
|
{
|
|
qse_awk_t* awk;
|
|
int fail;
|
|
};
|
|
|
|
qse_htb_walk_t add_global (qse_htb_t* map, qse_htb_pair_t* pair, void* arg)
|
|
{
|
|
struct add_global_ctx_t* ctx = (struct add_global_ctx_t*)arg;
|
|
struct gvmv_t* gvmv = (struct gvmv_t*)QSE_HTB_VPTR(pair);
|
|
|
|
/* the key was inserted to the table with a null at the end
|
|
* and the key length was even incremetned for that.
|
|
* so i can pass the pointer without other adjustments. */
|
|
gvmv->idx = qse_awk_addgbl(ctx->awk, QSE_HTB_KPTR(pair));
|
|
if (gvmv->idx <= -1)
|
|
{
|
|
ctx->fail = 1;
|
|
return QSE_HTB_WALK_STOP;
|
|
}
|
|
return QSE_HTB_WALK_FORWARD;
|
|
}
|
|
|
|
static void* xma_alloc (qse_mmgr_t* mmgr, qse_size_t size)
|
|
{
|
|
return qse_xma_alloc (mmgr->ctx, size);
|
|
}
|
|
|
|
static void* xma_realloc (qse_mmgr_t* mmgr, void* ptr, qse_size_t size)
|
|
{
|
|
return qse_xma_realloc (mmgr->ctx, ptr, size);
|
|
}
|
|
|
|
static void xma_free (qse_mmgr_t* mmgr, void* ptr)
|
|
{
|
|
qse_xma_free (mmgr->ctx, ptr);
|
|
}
|
|
|
|
static qse_mmgr_t xma_mmgr =
|
|
{
|
|
xma_alloc,
|
|
xma_realloc,
|
|
xma_free,
|
|
QSE_NULL
|
|
};
|
|
|
|
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
static qse_ulong_t debug_mmgr_count = 0;
|
|
static qse_ulong_t debug_mmgr_alloc_count = 0;
|
|
static qse_ulong_t debug_mmgr_realloc_count = 0;
|
|
static qse_ulong_t debug_mmgr_free_count = 0;
|
|
|
|
static void* debug_mmgr_alloc (qse_mmgr_t* mmgr, qse_size_t size)
|
|
{
|
|
void* ptr;
|
|
struct arg_t* arg = (struct arg_t*)mmgr->ctx;
|
|
debug_mmgr_count++;
|
|
if (debug_mmgr_count % arg->failmalloc == 0) return QSE_NULL;
|
|
ptr = malloc (size);
|
|
if (ptr) debug_mmgr_alloc_count++;
|
|
return ptr;
|
|
}
|
|
|
|
static void* debug_mmgr_realloc (qse_mmgr_t* mmgr, void* ptr, qse_size_t size)
|
|
{
|
|
void* rptr;
|
|
struct arg_t* arg = (struct arg_t*)mmgr->ctx;
|
|
debug_mmgr_count++;
|
|
if (debug_mmgr_count % arg->failmalloc == 0) return QSE_NULL;
|
|
rptr = realloc (ptr, size);
|
|
if (rptr)
|
|
{
|
|
if (ptr) debug_mmgr_realloc_count++;
|
|
else debug_mmgr_alloc_count++;
|
|
}
|
|
return rptr;
|
|
}
|
|
|
|
static void debug_mmgr_free (qse_mmgr_t* mmgr, void* ptr)
|
|
{
|
|
debug_mmgr_free_count++;
|
|
free (ptr);
|
|
}
|
|
|
|
static qse_mmgr_t debug_mmgr =
|
|
{
|
|
debug_mmgr_alloc,
|
|
debug_mmgr_realloc,
|
|
debug_mmgr_free,
|
|
QSE_NULL
|
|
};
|
|
#endif
|
|
|
|
static int awk_main (int argc, qse_char_t* argv[])
|
|
{
|
|
qse_awk_t* awk = QSE_NULL;
|
|
qse_awk_rtx_t* rtx = QSE_NULL;
|
|
qse_awk_val_t* retv;
|
|
int i;
|
|
struct arg_t arg;
|
|
struct add_global_ctx_t agctx;
|
|
int ret = -1;
|
|
|
|
#if defined(ENABLE_CALLBACK)
|
|
static qse_awk_rtx_ecb_t rtx_ecb =
|
|
{
|
|
QSE_FV(.close, QSE_NULL),
|
|
QSE_FV(.stmt, on_statement),
|
|
QSE_FV(.gblset, QSE_NULL)
|
|
};
|
|
#endif
|
|
|
|
/* TODO: change it to support multiple source files */
|
|
qse_awk_parsestd_t psout;
|
|
qse_mmgr_t* mmgr = QSE_MMGR_GETDFL();
|
|
|
|
qse_memset (&arg, 0, QSE_SIZEOF(arg));
|
|
arg.icf.mmgr = mmgr;
|
|
|
|
i = comparg (argc, argv, &arg);
|
|
if (i <= 0)
|
|
{
|
|
print_usage (((i == 0)? QSE_STDOUT: QSE_STDERR), argv[0]);
|
|
return i;
|
|
}
|
|
if (i == 2) return 0;
|
|
if (i == 3) return -1;
|
|
|
|
if (arg.osf)
|
|
{
|
|
psout.type = QSE_AWK_PARSESTD_FILE;
|
|
psout.u.file.path = arg.osf;
|
|
psout.u.file.cmgr = arg.script_cmgr;
|
|
}
|
|
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
if (arg.failmalloc > 0)
|
|
{
|
|
debug_mmgr.ctx = &arg;
|
|
mmgr = &debug_mmgr;
|
|
}
|
|
else
|
|
#endif
|
|
if (arg.memlimit > 0)
|
|
{
|
|
xma_mmgr.ctx = qse_xma_open (QSE_MMGR_GETDFL(), 0, QSE_NULL, arg.memlimit);
|
|
if (xma_mmgr.ctx == QSE_NULL)
|
|
{
|
|
qse_printf (QSE_T("ERROR: cannot open memory heap\n"));
|
|
goto oops;
|
|
}
|
|
mmgr = &xma_mmgr;
|
|
}
|
|
|
|
awk = qse_awk_openstdwithmmgr (mmgr, 0, QSE_NULL);
|
|
/*awk = qse_awk_openstd (0);*/
|
|
if (awk == QSE_NULL)
|
|
{
|
|
qse_printf (QSE_T("ERROR: cannot open awk\n"));
|
|
goto oops;
|
|
}
|
|
|
|
if (arg.modern) i = QSE_AWK_MODERN;
|
|
else if (arg.classic) i = QSE_AWK_CLASSIC;
|
|
else qse_awk_getopt (awk, QSE_AWK_TRAIT, &i);
|
|
if (arg.opton) i |= arg.opton;
|
|
if (arg.optoff) i &= ~arg.optoff;
|
|
qse_awk_setopt (awk, QSE_AWK_TRAIT, &i);
|
|
|
|
/* TODO: get depth from command line */
|
|
{
|
|
qse_size_t tmp;
|
|
tmp = 50;
|
|
qse_awk_setopt (awk, QSE_AWK_DEPTH_BLOCK_PARSE, &tmp);
|
|
qse_awk_setopt (awk, QSE_AWK_DEPTH_EXPR_PARSE, &tmp);
|
|
tmp = 500;
|
|
qse_awk_setopt (awk, QSE_AWK_DEPTH_BLOCK_RUN, &tmp);
|
|
qse_awk_setopt (awk, QSE_AWK_DEPTH_EXPR_RUN, &tmp);
|
|
tmp = 64;
|
|
qse_awk_setopt (awk, QSE_AWK_DEPTH_INCLUDE, &tmp);
|
|
}
|
|
|
|
agctx.awk = awk;
|
|
agctx.fail = 0;
|
|
qse_htb_walk (arg.gvm, add_global, &agctx);
|
|
if (agctx.fail)
|
|
{
|
|
print_awkerr (awk);
|
|
goto oops;
|
|
}
|
|
|
|
if (qse_awk_parsestd(awk, arg.psin, ((arg.osf == QSE_NULL)? QSE_NULL: &psout)) <= -1)
|
|
{
|
|
print_awkerr (awk);
|
|
goto oops;
|
|
}
|
|
|
|
rtx = qse_awk_rtx_openstd (
|
|
awk, 0, QSE_T("qseawk"),
|
|
(arg.call? QSE_NULL: (const qse_char_t**)arg.icf.ptr), /* console input */
|
|
QSE_NULL, /* console output */
|
|
arg.console_cmgr
|
|
);
|
|
if (rtx == QSE_NULL)
|
|
{
|
|
print_awkerr (awk);
|
|
goto oops;
|
|
}
|
|
|
|
if (apply_fs_and_gvm (rtx, &arg) <= -1)
|
|
{
|
|
print_awkerr (awk);
|
|
goto oops;
|
|
}
|
|
|
|
app_rtx = rtx;
|
|
#if defined(ENABLE_CALLBACK)
|
|
qse_awk_rtx_pushecb (rtx, &rtx_ecb);
|
|
#endif
|
|
|
|
set_intr_run ();
|
|
|
|
retv = arg.call?
|
|
qse_awk_rtx_callwithstrs (rtx, arg.call, (const qse_char_t**)arg.icf.ptr, arg.icf.size):
|
|
qse_awk_rtx_loop (rtx);
|
|
|
|
unset_intr_run ();
|
|
|
|
if (retv)
|
|
{
|
|
qse_awk_int_t tmp;
|
|
|
|
qse_awk_rtx_refdownval (rtx, retv);
|
|
if (app_debug) dprint_return (rtx, retv);
|
|
|
|
ret = 0;
|
|
if (qse_awk_rtx_valtoint (rtx, retv, &tmp) >= 0) ret = tmp;
|
|
}
|
|
else
|
|
{
|
|
print_rtxerr (rtx);
|
|
goto oops;
|
|
}
|
|
|
|
oops:
|
|
if (rtx) qse_awk_rtx_close (rtx);
|
|
if (awk) qse_awk_close (awk);
|
|
|
|
if (xma_mmgr.ctx)
|
|
{
|
|
if (app_debug) qse_xma_dump (xma_mmgr.ctx, qse_fprintf, QSE_STDERR);
|
|
qse_xma_close (xma_mmgr.ctx);
|
|
}
|
|
freearg (&arg);
|
|
|
|
#if defined(QSE_BUILD_DEBUG)
|
|
if (arg.failmalloc > 0)
|
|
{
|
|
qse_fprintf (QSE_STDERR, QSE_T("\n"));
|
|
qse_fprintf (QSE_STDERR, QSE_T("-[MALLOC COUNTS]---------------------------------------\n"));
|
|
qse_fprintf (QSE_STDERR, QSE_T("ALLOC: %lu FREE: %lu: REALLOC: %lu\n"),
|
|
(unsigned long)debug_mmgr_alloc_count,
|
|
(unsigned long)debug_mmgr_free_count,
|
|
(unsigned long)debug_mmgr_realloc_count);
|
|
qse_fprintf (QSE_STDERR, QSE_T("-------------------------------------------------------\n"));
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct mpi_t
|
|
{
|
|
void* h;
|
|
int (*i) (int argc, qse_achar_t* argv[]);
|
|
void (*f) (void);
|
|
};
|
|
|
|
typedef struct mpi_t mpi_t;
|
|
|
|
static void open_mpi (mpi_t* mpi, int argc, qse_achar_t* argv[])
|
|
{
|
|
#if defined(USE_LTDL)
|
|
lt_dladvise adv;
|
|
#endif
|
|
|
|
qse_memset (mpi, 0, QSE_SIZEOF(*mpi));
|
|
|
|
#if defined(USE_LTDL)
|
|
|
|
#if defined(QSE_ACHAR_IS_MCHAR)
|
|
if (qse_mbscmp(qse_mbsbasename(argv[0]), QSE_MT("qseawkmp")) != 0 &&
|
|
qse_mbscmp(qse_mbsbasename(argv[0]), QSE_MT("qseawkmpi")) != 0) return;
|
|
#else
|
|
if (qse_wcscmp(qse_wcsbasename(argv[0]), QSE_WT("qseawkmp")) != 0 &&
|
|
qse_wcscmp(qse_wcsbasename(argv[0]), QSE_WT("qseawkmpi")) != 0) return;
|
|
#endif
|
|
|
|
if (lt_dlinit () != 0) return;
|
|
|
|
if (lt_dladvise_init(&adv) != 0) goto oops;
|
|
|
|
/* If i don't set the global option, loading may end up with an error
|
|
* like this depending on your MPI library.
|
|
*
|
|
* symbol lookup error: /usr/lib/openmpi/lib/openmpi/mca_paffinity_linux.so: undefined symbol: mca_base_param_reg_int
|
|
*/
|
|
|
|
if (lt_dladvise_global(&adv) != 0 || lt_dladvise_ext(&adv) != 0)
|
|
{
|
|
lt_dladvise_destroy (&adv);
|
|
goto oops;
|
|
}
|
|
|
|
mpi->h = lt_dlopenadvise(DEFAULT_MODPREFIX "mpi" DEFAULT_MODPOSTFIX, adv);
|
|
lt_dladvise_destroy (&adv);
|
|
|
|
if (mpi->h)
|
|
{
|
|
mpi->i = lt_dlsym(mpi->h, "qse_awk_mod_mpi_init");
|
|
mpi->f = lt_dlsym(mpi->h, "qse_awk_mod_mpi_fini");
|
|
|
|
if (mpi->i == QSE_NULL ||
|
|
mpi->f == QSE_NULL ||
|
|
mpi->i(argc, argv) <= -1)
|
|
{
|
|
lt_dlclose (mpi->h);
|
|
mpi->h = QSE_NULL;
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
oops:
|
|
lt_dlexit ();
|
|
#endif
|
|
}
|
|
|
|
static void close_mpi (mpi_t* mpi)
|
|
{
|
|
if (mpi->h)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
mpi->f ();
|
|
lt_dlclose (mpi->h);
|
|
mpi->h = QSE_NULL;
|
|
lt_dlexit ();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int qse_main (int argc, qse_achar_t* argv[])
|
|
{
|
|
int ret;
|
|
mpi_t mpi;
|
|
|
|
#if defined(_WIN32)
|
|
char locale[100];
|
|
UINT codepage;
|
|
WSADATA wsadata;
|
|
#elif defined(__DOS__)
|
|
extern BOOL _watt_do_exit;
|
|
int sock_inited = 0;
|
|
#else
|
|
/* nothing special */
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
codepage = GetConsoleOutputCP();
|
|
if (codepage == CP_UTF8)
|
|
{
|
|
/*SetConsoleOUtputCP (CP_UTF8);*/
|
|
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
|
}
|
|
else
|
|
{
|
|
/* .codepage */
|
|
qse_fmtuintmaxtombs (locale, QSE_COUNTOF(locale),
|
|
codepage, 10, -1, QSE_MT('\0'), QSE_MT("."));
|
|
setlocale (LC_ALL, locale);
|
|
/* qse_setdflcmgrbyid (QSE_CMGR_SLMB); */
|
|
}
|
|
|
|
#else
|
|
setlocale (LC_ALL, "");
|
|
/* qse_setdflcmgrbyid (QSE_CMGR_SLMB); */
|
|
#endif
|
|
|
|
qse_open_stdsios ();
|
|
|
|
#if defined(_WIN32)
|
|
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
|
|
{
|
|
print_error (QSE_T("Failed to start up winsock\n"));
|
|
ret = -1;
|
|
goto oops;
|
|
}
|
|
#elif defined(__DOS__)
|
|
/* TODO: add an option to skip watt-32 */
|
|
_watt_do_exit = 0; /* prevent sock_init from exiting upon failure */
|
|
if (sock_init() != 0)
|
|
print_warning (QSE_T("Failed to initialize watt-32\n"));
|
|
else sock_inited = 1;
|
|
#endif
|
|
|
|
open_mpi (&mpi, argc, argv);
|
|
|
|
ret = qse_run_main(argc, argv, awk_main);
|
|
|
|
close_mpi (&mpi);
|
|
|
|
#if defined(_WIN32)
|
|
WSACleanup ();
|
|
#elif defined(__DOS__)
|
|
if (sock_inited) sock_exit ();
|
|
#endif
|
|
|
|
oops:
|
|
qse_close_stdsios ();
|
|
return ret;
|
|
}
|
|
|
|
|
|
#if defined(FAKE_SOCKET)
|
|
socket () {}
|
|
listen () {}
|
|
accept () {}
|
|
recvfrom () {}
|
|
connect () {}
|
|
getsockopt () {}
|
|
recv () {}
|
|
setsockopt () {}
|
|
send () {}
|
|
bind () {}
|
|
shutdown () {}
|
|
|
|
void* memmove (void* x, void* y, size_t z) {}
|
|
#endif
|