984 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			984 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * $Id$
 | |
|  *
 | |
|     Copyright (c) 2006-2020 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 "main.h"
 | |
| 
 | |
| #include <hawk.h>
 | |
| #include <hawk-utl.h>
 | |
| #include <hawk-fmt.h>
 | |
| #include <hawk-cli.h>
 | |
| #include <hawk-xma.h>
 | |
| 
 | |
| #if !defined(_GNU_SOURCE)
 | |
| #	define _GNU_SOURCE
 | |
| #endif
 | |
| #if !defined(_XOPEN_SOURCE)
 | |
| #	define _XOPEN_SOURCE 700
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <signal.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdlib.h>
 | |
| #include <locale.h>
 | |
| 
 | |
| /* #define ENABLE_CALLBACK  TODO: enable this back */
 | |
| #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(HAWK_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 hawk_rtx_t* app_rtx = HAWK_NULL;
 | |
| 
 | |
| typedef struct gv_t gv_t;
 | |
| typedef struct gvm_t gvm_t;
 | |
| typedef struct arg_t arg_t;
 | |
| 
 | |
| struct gv_t
 | |
| {
 | |
| 	int        idx;
 | |
| 	int        uc; /* if 0, the name and the value are bchs. otherwise, uchs */
 | |
| 	void*      name; /* hawk_bch_t* or hawk_uch_t* */
 | |
| 	hawk_ptl_t value;  /* hawk_bcs_t or hawk_ucs_t */
 | |
| };
 | |
| 
 | |
| struct gvm_t
 | |
| {
 | |
| 	gv_t*      ptr;
 | |
| 	hawk_oow_t size;
 | |
| 	hawk_oow_t capa;
 | |
| };
 | |
| 
 | |
| struct arg_t
 | |
| {
 | |
| 	hawk_parsestd_t* psin; /* input source streams */
 | |
| 	hawk_bch_t*      osf;  /* output source file */
 | |
| 	hawk_main_xarg_t icf; /* input console files */
 | |
| 	hawk_main_xarg_t ocf; /* output console files */
 | |
| 	gvm_t            gvm; /* global variable map */
 | |
| 	hawk_bch_t*      fs;   /* field separator */
 | |
| 	hawk_bch_t*      call; /* function to call */
 | |
| 	hawk_cmgr_t*     script_cmgr;
 | |
| 	hawk_cmgr_t*     console_cmgr;
 | |
| 	hawk_bch_t*      includedirs;
 | |
| 	hawk_bch_t*      modlibdirs;
 | |
| 
 | |
| 	unsigned int     modern: 1;
 | |
| 	unsigned int     classic: 1;
 | |
| 	int              opton;
 | |
| 	int              optoff;
 | |
| 	int              debug;
 | |
| 
 | |
| 	hawk_uintptr_t   memlimit;
 | |
| };
 | |
| 
 | |
| 
 | |
| /* ---------------------------------------------------------------------- */
 | |
| 
 | |
| static void stop_run (int signo)
 | |
| {
 | |
| #if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__)
 | |
| 	int e = errno;
 | |
| #endif
 | |
| 	/*hawk_haltall(hawk_rtx_gethawk(app_rtx));*/
 | |
| 	hawk_rtx_halt(app_rtx);
 | |
| #if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__)
 | |
| 	errno = e;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void set_intr_pipe (void)
 | |
| {
 | |
| #if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__) && defined(SIGPIPE)
 | |
| 	hawk_main_set_signal_handler(SIGPIPE, hawk_main_do_nothing_on_signal, 0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void unset_intr_pipe (void)
 | |
| {
 | |
| #if !defined(_WIN32) && !defined(__OS2__) && !defined(__DOS__) && defined(SIGPIPE)
 | |
| 	hawk_main_unset_signal_handler(SIGPIPE);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void set_intr_run (void)
 | |
| {
 | |
| #if defined(SIGTERM)
 | |
| 	hawk_main_set_signal_handler(SIGTERM, stop_run, 0);
 | |
| #endif
 | |
| #if defined(SIGHUP)
 | |
| 	hawk_main_set_signal_handler(SIGHUP, stop_run, 0);
 | |
| #endif
 | |
| #if defined(SIGINT)
 | |
| 	hawk_main_set_signal_handler(SIGINT, stop_run, 0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void unset_intr_run (void)
 | |
| {
 | |
| #if defined(SIGTERM)
 | |
| 	hawk_main_unset_signal_handler(SIGTERM);
 | |
| #endif
 | |
| #if defined(SIGHUP)
 | |
| 	hawk_main_unset_signal_handler(SIGHUP);
 | |
| #endif
 | |
| #if defined(SIGINT)
 | |
| 	hawk_main_unset_signal_handler(SIGINT);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static hawk_htb_walk_t print_awk_value (hawk_htb_t* map, hawk_htb_pair_t* pair, void* arg)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = (hawk_rtx_t*)arg;
 | |
| 	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | |
| 	hawk_ooch_t* str;
 | |
| 	hawk_oow_t len;
 | |
| 	hawk_errinf_t oerrinf;
 | |
| 
 | |
| 	hawk_rtx_geterrinf (rtx, &oerrinf);
 | |
| 
 | |
| 	str = hawk_rtx_getvaloocstr(rtx, HAWK_HTB_VPTR(pair), &len);
 | |
| 	if (HAWK_UNLIKELY(!str))
 | |
| 	{
 | |
| 		if (hawk_rtx_geterrnum(rtx) == HAWK_EVALTOSTR)
 | |
| 		{
 | |
| 			hawk_logfmt(hawk, HAWK_LOG_STDERR, HAWK_T("%.*js = [not printable]\n"), HAWK_HTB_KLEN(pair), HAWK_HTB_KPTR(pair));
 | |
| 			hawk_rtx_seterrinf(rtx, &oerrinf);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			hawk_logfmt(hawk, HAWK_LOG_STDERR, HAWK_T("***OUT OF MEMORY***\n"));
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		hawk_logfmt(hawk, HAWK_LOG_STDERR, HAWK_T("%.*js = %.*js\n"), HAWK_HTB_KLEN(pair), HAWK_HTB_KPTR(pair), len, str);
 | |
| 		hawk_rtx_freevaloocstr(rtx, HAWK_HTB_VPTR(pair), str);
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_HTB_WALK_FORWARD;
 | |
| }
 | |
| 
 | |
| static int add_gvs_to_hawk (hawk_t* hawk, arg_t* arg)
 | |
| {
 | |
| 	if (arg->gvm.size > 0)
 | |
| 	{
 | |
| 		hawk_oow_t i;
 | |
| 
 | |
| 		for (i = 0; i < arg->gvm.size; i++)
 | |
| 		{
 | |
| 			/* search includes the builtin variables in case an existing variable name is given. */
 | |
| 			arg->gvm.ptr[i].idx = arg->gvm.ptr[i].uc? hawk_findgblwithucstr(hawk, arg->gvm.ptr[i].name, 1):
 | |
| 			                                          hawk_findgblwithbcstr(hawk, arg->gvm.ptr[i].name, 1);
 | |
| 			if (arg->gvm.ptr[i].idx <= -1)
 | |
| 			{
 | |
| 				/* if it doesn't exist, add it */
 | |
| 				arg->gvm.ptr[i].idx = arg->gvm.ptr[i].uc? hawk_addgblwithucstr(hawk, arg->gvm.ptr[i].name):
 | |
| 				                                          hawk_addgblwithbcstr(hawk, arg->gvm.ptr[i].name);
 | |
| 				if (arg->gvm.ptr[i].idx <= -1) return -1;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int apply_fs_and_gvs_to_rtx (hawk_rtx_t* rtx, const arg_t* arg)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (arg->fs)
 | |
| 	{
 | |
| 		hawk_val_t* fs;
 | |
| 
 | |
| 		/* compose a string value to use to set FS to */
 | |
| 		fs = hawk_rtx_makestrvalwithbcstr(rtx, arg->fs);
 | |
| 		if (HAWK_UNLIKELY(!fs)) return -1;
 | |
| 
 | |
| 		/* change FS according to the command line argument */
 | |
| 		hawk_rtx_refupval(rtx, fs);
 | |
| 		hawk_rtx_setgbl(rtx, HAWK_GBL_FS, fs);
 | |
| 		hawk_rtx_refdownval(rtx, fs);
 | |
| 	}
 | |
| 
 | |
| 	if (arg->gvm.capa > 0)
 | |
| 	{
 | |
| 		/* set the value of user-defined global variables
 | |
| 		 * to a runtime context */
 | |
| 		for (i = 0; i < arg->gvm.size; i++)
 | |
| 		{
 | |
| 			hawk_val_t* v;
 | |
| 
 | |
| 			v = (arg->gvm.ptr[i].uc)? hawk_rtx_makenumorstrvalwithuchars(rtx, arg->gvm.ptr[i].value.ptr, arg->gvm.ptr[i].value.len):
 | |
| 			                          hawk_rtx_makenumorstrvalwithbchars(rtx, arg->gvm.ptr[i].value.ptr, arg->gvm.ptr[i].value.len);
 | |
| 			if (HAWK_UNLIKELY(!v)) return -1;
 | |
| 
 | |
| 			hawk_rtx_refupval(rtx, v);
 | |
| 			hawk_rtx_setgbl(rtx, arg->gvm.ptr[i].idx, v);
 | |
| 			hawk_rtx_refdownval(rtx, v);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ret = 0;
 | |
| 	for (i = 0; arg->psin[i].type != HAWK_PARSESTD_NULL; i++)
 | |
| 	{
 | |
| 		/* set the first file name as a script name if available */
 | |
| 		if (arg->psin[i].type == HAWK_PARSESTD_FILE)
 | |
| 		{
 | |
| 			ret = hawk_rtx_setscriptnamewithoochars(rtx, arg->psin[i].u.file.path, hawk_count_oocstr(arg->psin[i].u.file.path));
 | |
| 			break;
 | |
| 		}
 | |
| 		else if (arg->psin[i].type == HAWK_PARSESTD_FILEB)
 | |
| 		{
 | |
| 			ret = hawk_rtx_setscriptnamewithbchars(rtx, arg->psin[i].u.fileb.path, hawk_count_bcstr(arg->psin[i].u.fileb.path));
 | |
| 			break;
 | |
| 		}
 | |
| 		else if (arg->psin[i].type == HAWK_PARSESTD_FILEU)
 | |
| 		{
 | |
| 			ret = hawk_rtx_setscriptnamewithuchars(rtx, arg->psin[i].u.fileu.path, hawk_count_ucstr(arg->psin[i].u.fileu.path));
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static void dprint_return (hawk_rtx_t* rtx, hawk_val_t* ret)
 | |
| {
 | |
| 	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | |
| 	hawk_oow_t len;
 | |
| 	hawk_ooch_t* str;
 | |
| 
 | |
| 
 | |
| 	if (hawk_rtx_isnilval(rtx, ret))
 | |
| 	{
 | |
| 		hawk_logfmt (hawk, HAWK_LOG_STDERR,HAWK_T("[RETURN] - ***nil***\n"));
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		str = hawk_rtx_valtooocstrdup(rtx, ret, &len);
 | |
| 		if (str == HAWK_NULL)
 | |
| 		{
 | |
| 			hawk_logfmt (hawk, HAWK_LOG_STDERR,HAWK_T("[RETURN] - ***OUT OF MEMORY***\n"));
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			hawk_logfmt (hawk, HAWK_LOG_STDERR, HAWK_T("[RETURN] - [%.*js]\n"), len, str);
 | |
| 			hawk_freemem(hawk_rtx_gethawk(rtx), str);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	hawk_logfmt (hawk, HAWK_LOG_STDERR, HAWK_T("[NAMED VARIABLES]\n"));
 | |
| 	hawk_htb_walk (hawk_rtx_getnvmap(rtx), print_awk_value, rtx);
 | |
| 	hawk_logfmt (hawk, HAWK_LOG_STDERR, HAWK_T("[END NAMED VARIABLES]\n"));
 | |
| }
 | |
| 
 | |
| #if defined(ENABLE_CALLBACK)
 | |
| static void on_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
 | |
| {
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("running %d at line %zu\n"), (int)nde->type, (hawk_oow_t)nde->loc.line);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| struct opttab_t
 | |
| {
 | |
| 	const hawk_bch_t* name;
 | |
| 	int opt;
 | |
| 	const hawk_bch_t* desc;
 | |
| } opttab[] =
 | |
| {
 | |
| 	{ "implicit",     HAWK_IMPLICIT,       "allow undeclared variables" },
 | |
| 	{ "multilinestr", HAWK_MULTILINESTR,   "allow raw multiline string and regular expression literals" },
 | |
| 	{ "nextofile",    HAWK_NEXTOFILE,      "enable nextofile & OFILENAME" },
 | |
| 	{ "rio",          HAWK_RIO,            "enable builtin I/O including getline & print" },
 | |
| 	{ "rwpipe",       HAWK_RWPIPE,         "allow a dual-directional pipe" },
 | |
| 	{ "newline",      HAWK_NEWLINE,        "enable a newline to terminate a statement" },
 | |
| 	{ "striprecspc",  HAWK_STRIPRECSPC,    "strip spaces in splitting a record" },
 | |
| 	{ "stripstrspc",  HAWK_STRIPSTRSPC,    "strip spaces in string-to-number conversion" },
 | |
| 	{ "blankconcat",  HAWK_BLANKCONCAT,    "enable concatenation by blanks" },
 | |
| 	{ "crlf",         HAWK_CRLF,           "use CRLF for a newline" },
 | |
| 	{ "flexmap",      HAWK_FLEXMAP,        "allow a map to be assigned or returned" },
 | |
| 	{ "pablock",      HAWK_PABLOCK,        "enable pattern-action loop" },
 | |
| 	{ "rexbound",     HAWK_REXBOUND,       "enable {n,m} in a regular expression" },
 | |
| 	{ "ncmponstr",    HAWK_NCMPONSTR,      "perform numeric comparsion on numeric strings" },
 | |
| 	{ "numstrdetect", HAWK_NUMSTRDETECT,   "detect a numeric string and convert it to a number" },
 | |
| 	{ "strictnaming", HAWK_STRICTNAMING,   "enable the strict naming rule" },
 | |
| 	{ "tolerant",     HAWK_TOLERANT,       "make more fault-tolerant" },
 | |
| 	{ HAWK_NULL,      0,                   HAWK_NULL }
 | |
| };
 | |
| 
 | |
| static void print_usage (FILE* out, const hawk_bch_t* argv0, const hawk_bch_t* real_argv0)
 | |
| {
 | |
| 	int j;
 | |
| 	const hawk_bch_t* b1 = hawk_get_base_name_bcstr(real_argv0? real_argv0: argv0);
 | |
| 	const hawk_bch_t* b2 = (real_argv0? " ": "");
 | |
| 	const hawk_bch_t* b3 = (real_argv0? argv0: "");
 | |
| 
 | |
| 	fprintf (out, "USAGE: %s%s%s [options] -f sourcefile [ -- ] [datafile]*\n", b1, b2, b3);
 | |
| 	fprintf (out, "       %s%s%s [options] [ -- ] sourcestring [datafile]*\n", b1, b2, b3);
 | |
| 	fprintf (out, "Options as follows:\n");
 | |
| 	fprintf (out, " -h/--help                         print this message\n");
 | |
| 	fprintf (out, " -D                                show extra information\n");
 | |
| 	fprintf (out, " -c/--call            name         call a function instead of entering\n");
 | |
| 	fprintf (out, "                                   the pattern-action loop. [datafile]* is\n");
 | |
| 	fprintf (out, "                                   passed to the function as parameters\n");
 | |
| 	fprintf (out, " -f/--file            file         set the source script file\n");
 | |
| 	fprintf (out, " -d/--deparsed-file   file         set the deparsed script file to produce\n");
 | |
| 	fprintf (out, " -t/--console-output  file         set the console output file\n");
 | |
| 	fprintf (out, "                                   multiple -t options are allowed\n");
 | |
| 	fprintf (out, " -F/--field-separator string       set a field separator(FS)\n");
 | |
| 	fprintf (out, " -v/--assign          var=value    add a global variable with a value\n");
 | |
| 	fprintf (out, " -m/--memory-limit    number       limit the memory usage (bytes)\n");
 | |
| 	fprintf (out, " -w                                expand datafile wildcards\n");
 | |
| 
 | |
| #if defined(HAWK_OOCH_IS_UCH)
 | |
| 	fprintf (out, " --script-encoding    string       specify script file encoding name\n");
 | |
| 	fprintf (out, " --console-encoding   string       specify console encoding name\n");
 | |
| #endif
 | |
| 
 | |
| 	fprintf (out, " -I/--includedirs     string       specify directories to look for includes files in\n");
 | |
| 	fprintf (out, " --modlibdirs         string       specify directories to look for module files in\n");
 | |
| 	fprintf (out, " --modern                          run in the modern mode(default)\n");
 | |
| 	fprintf (out, " --classic                         run in the classic mode\n");
 | |
| 
 | |
| 	for (j = 0; opttab[j].name; j++)
 | |
| 	{
 | |
| 		fprintf (out, " --%-18s on/off       %s\n", opttab[j].name, opttab[j].desc);
 | |
| 	}
 | |
| 
 | |
| 	if (!real_argv0)
 | |
| 	{
 | |
| 		fprintf (out, "\n");
 | |
| 		fprintf (out, "Special mode switching options(must be specified first to take effect):\n");
 | |
| 		fprintf (out, " --hawk/--awk                      run in the hawk mode\n");
 | |
| 		fprintf (out, " --cut                             run in the cut  mode\n");
 | |
| 		fprintf (out, " --sed                             run in the sed mode\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* ---------------------------------------------------------------------- */
 | |
| 
 | |
| static int process_argv (int argc, hawk_bch_t* argv[], const hawk_bch_t* real_argv0, struct arg_t* arg)
 | |
| {
 | |
| 	static hawk_bcli_lng_t lng[] =
 | |
| 	{
 | |
| 		{ ":implicit",         '\0' },
 | |
| 		{ ":multilinestr",     '\0' },
 | |
| 		{ ":nextofile",        '\0' },
 | |
| 		{ ":rio",              '\0' },
 | |
| 		{ ":rwpipe",           '\0' },
 | |
| 		{ ":newline",          '\0' },
 | |
| 		{ ":striprecspc",      '\0' },
 | |
| 		{ ":stripstrspc",      '\0' },
 | |
| 		{ ":blankconcat",      '\0' },
 | |
| 		{ ":crlf",             '\0' },
 | |
| 		{ ":flexmap",          '\0' },
 | |
| 		{ ":pablock",          '\0' },
 | |
| 		{ ":rexbound",         '\0' },
 | |
| 		{ ":ncmponstr",        '\0' },
 | |
| 		{ ":numstrdetect",     '\0' },
 | |
| 		{ ":strictnaming",     '\0' },
 | |
| 		{ ":tolerant",         '\0' },
 | |
| 
 | |
| 		{ ":call",             'c' },
 | |
| 		{ ":file",             'f' },
 | |
| 		{ ":deparsed-file",    'd' },
 | |
| 		{ ":console-output",   't' },
 | |
| 		{ ":field-separator",  'F' },
 | |
| 		{ ":assign",           'v' },
 | |
| 		{ ":memory-limit",     'm' },
 | |
| 
 | |
| 		{ ":script-encoding",  '\0' },
 | |
| 		{ ":console-encoding", '\0' },
 | |
| 		{ ":includedirs",      'I' },
 | |
| 		{ ":modlibdirs",       '\0' },
 | |
| 
 | |
| 		{ "modern",            '\0' },
 | |
| 		{ "classic",           '\0' },
 | |
| 
 | |
| 		{ "help",              'h' },
 | |
| 		{ HAWK_NULL,           '\0' }
 | |
| 	};
 | |
| 
 | |
| 	static hawk_bcli_t opt =
 | |
| 	{
 | |
| 		"hDc:f:d:t:F:v:m:I:w",
 | |
| 		lng
 | |
| 	};
 | |
| 
 | |
| 	hawk_bci_t c;
 | |
| 
 | |
| 	hawk_oow_t i;
 | |
| 	hawk_oow_t isfc = 16; /* the capacity of isf */
 | |
| 	hawk_oow_t isfl = 0; /* number of input source files */
 | |
| 	hawk_parsestd_t* isf = HAWK_NULL; /* input source files */
 | |
| 
 | |
| 	int oops_ret = -1;
 | |
| 	int do_glob = 0;
 | |
| 
 | |
| 	memset (arg, 0, HAWK_SIZEOF(*arg));
 | |
| 
 | |
| 	isf = (hawk_parsestd_t*)malloc(HAWK_SIZEOF(*isf) * isfc);
 | |
| 	if (!isf)
 | |
| 	{
 | |
| 		hawk_main_print_error("out of memory\n");
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	while ((c = hawk_get_bcli(argc, argv, &opt)) != HAWK_BCI_EOF)
 | |
| 	{
 | |
| 		switch (c)
 | |
| 		{
 | |
| 			case 'h':
 | |
| 				oops_ret = 0;
 | |
| 				goto oops;
 | |
| 
 | |
| 			case 'D':
 | |
| 				arg->debug = 1;
 | |
| 				break;
 | |
| 
 | |
| 			case 'c':
 | |
| 				arg->call = opt.arg; /* function name to call */
 | |
| 				break;
 | |
| 
 | |
| 			case 'f':
 | |
| 			{
 | |
| 				if (isfl >= isfc - 1) /* -1 for last HAWK_NULL */
 | |
| 				{
 | |
| 					hawk_parsestd_t* tmp;
 | |
| 					tmp = (hawk_parsestd_t*)realloc(isf, HAWK_SIZEOF(*isf) * (isfc + 16));
 | |
| 					if (tmp == HAWK_NULL)
 | |
| 					{
 | |
| 						hawk_main_print_error("out of memory\n");
 | |
| 						goto oops;
 | |
| 					}
 | |
| 
 | |
| 					isf = tmp;
 | |
| 					isfc = isfc + 16;
 | |
| 				}
 | |
| 
 | |
| 				isf[isfl].type = HAWK_PARSESTD_FILEB;
 | |
| 				isf[isfl].u.fileb.path = opt.arg;
 | |
| 				isf[isfl].u.fileb.cmgr = HAWK_NULL;
 | |
| 				isfl++;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 'd':
 | |
| 			{
 | |
| 				arg->osf = opt.arg; /* output source file */
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 't':
 | |
| 			{
 | |
| 				hawk_bcs_t tmp;
 | |
| 				tmp.ptr = opt.arg;
 | |
| 				tmp.len = hawk_count_bcstr(opt.arg);
 | |
| 				if (hawk_main_collect_into_xarg(&tmp, &arg->ocf) <= -1)
 | |
| 				{
 | |
| 					hawk_main_print_error("out of memory\n");
 | |
| 					goto oops;
 | |
| 				}
 | |
| 				arg->ocf.ptr[arg->ocf.size] = HAWK_NULL;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 'F':
 | |
| 			{
 | |
| 				arg->fs = opt.arg; /* field seperator */
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 'v':
 | |
| 			{
 | |
| 				hawk_bch_t* eq;
 | |
| 
 | |
| 				eq = hawk_find_bchar_in_bcstr(opt.arg, HAWK_T('='));
 | |
| 				if (eq == HAWK_NULL)
 | |
| 				{
 | |
| 					if (opt.lngopt)
 | |
| 						hawk_main_print_error("no value for '%s' in '%s'\n", opt.arg, opt.lngopt);
 | |
| 					else
 | |
| 						hawk_main_print_error("no value for '%s' in '%c'\n", opt.arg, opt.opt);
 | |
| 					goto oops;
 | |
| 				}
 | |
| 
 | |
| 				*eq = '\0';
 | |
| 
 | |
| 				if (arg->gvm.size <= arg->gvm.capa)
 | |
| 				{
 | |
| 					gv_t* tmp;
 | |
| 					hawk_oow_t newcapa;
 | |
| 
 | |
| 					newcapa = arg->gvm.capa + argc;
 | |
| 					tmp = realloc(arg->gvm.ptr, HAWK_SIZEOF(*tmp) * newcapa);
 | |
| 					if (!tmp)
 | |
| 					{
 | |
| 						hawk_main_print_error("out of memory\n");
 | |
| 						goto oops;
 | |
| 					}
 | |
| 
 | |
| 					arg->gvm.capa = newcapa;
 | |
| 					arg->gvm.ptr = tmp;
 | |
| 				}
 | |
| 
 | |
| 				arg->gvm.ptr[arg->gvm.size].idx = -1;
 | |
| 				arg->gvm.ptr[arg->gvm.size].uc = 0;
 | |
| 				arg->gvm.ptr[arg->gvm.size].name = opt.arg;
 | |
| 				arg->gvm.ptr[arg->gvm.size].value.ptr = ++eq;
 | |
| 				arg->gvm.ptr[arg->gvm.size].value.len = hawk_count_bcstr(eq);
 | |
| 				arg->gvm.size++;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 'm':
 | |
| 			{
 | |
| 				arg->memlimit = strtoul(opt.arg, HAWK_NULL, 10);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case 'w':
 | |
| 			{
 | |
| 				do_glob = 1;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			case 'I':
 | |
| 			{
 | |
| 				arg->includedirs = opt.arg;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case '\0':
 | |
| 			{
 | |
| 				/* a long option with no corresponding short option */
 | |
| 				if (hawk_comp_bcstr(opt.lngopt, "script-encoding", 0) == 0)
 | |
| 				{
 | |
| 					arg->script_cmgr = hawk_get_cmgr_by_bcstr(opt.arg);
 | |
| 					if (arg->script_cmgr == HAWK_NULL)
 | |
| 					{
 | |
| 						hawk_main_print_error("unknown script encoding - %s\n", opt.arg);
 | |
| 						oops_ret = 3;
 | |
| 						goto oops;
 | |
| 					}
 | |
| 				}
 | |
| 				else if (hawk_comp_bcstr(opt.lngopt, "console-encoding", 0) == 0)
 | |
| 				{
 | |
| 					arg->console_cmgr = hawk_get_cmgr_by_bcstr(opt.arg);
 | |
| 					if (arg->console_cmgr == HAWK_NULL)
 | |
| 					{
 | |
| 						hawk_main_print_error("unknown console encoding - %s\n", opt.arg);
 | |
| 						oops_ret = 3;
 | |
| 						goto oops;
 | |
| 					}
 | |
| 				}
 | |
| 				else if (hawk_comp_bcstr(opt.lngopt, "modern", 0) == 0)
 | |
| 				{
 | |
| 					arg->modern = 1;
 | |
| 				}
 | |
| 				else if (hawk_comp_bcstr(opt.lngopt, "classic", 0) == 0)
 | |
| 				{
 | |
| 					arg->classic = 1;
 | |
| 				}
 | |
| 				else if (hawk_comp_bcstr(opt.lngopt, "modlibdirs", 0) == 0)
 | |
| 				{
 | |
| 					arg->modlibdirs = opt.arg;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					for (i = 0; opttab[i].name; i++)
 | |
| 					{
 | |
| 						if (hawk_comp_bcstr(opt.lngopt, opttab[i].name, 0) == 0)
 | |
| 						{
 | |
| 							if (hawk_comp_bcstr(opt.arg, "off", 1) == 0)
 | |
| 								arg->optoff |= opttab[i].opt;
 | |
| 							else if (hawk_comp_bcstr(opt.arg, "on", 1) == 0)
 | |
| 								arg->opton |= opttab[i].opt;
 | |
| 							else
 | |
| 							{
 | |
| 								hawk_main_print_error("invalid value '%s' for '%s' - use 'on' or 'off'\n", opt.arg, opt.lngopt);
 | |
| 								oops_ret = 3;
 | |
| 								goto oops;
 | |
| 							}
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case '?':
 | |
| 			{
 | |
| 				if (opt.lngopt)
 | |
| 					hawk_main_print_error("illegal option - '%s'\n", opt.lngopt);
 | |
| 				else
 | |
| 					hawk_main_print_error("illegal option - '%c'\n", opt.opt);
 | |
| 
 | |
| 				goto oops;
 | |
| 			}
 | |
| 
 | |
| 			case ':':
 | |
| 			{
 | |
| 				if (opt.lngopt)
 | |
| 					hawk_main_print_error("bad argument for '%s'\n", opt.lngopt);
 | |
| 				else
 | |
| 					hawk_main_print_error("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 = HAWK_PARSESTD_BCS;
 | |
| 		isf[isfl].u.bcs.ptr = argv[opt.ind++];
 | |
| 		isf[isfl].u.bcs.len = hawk_count_bcstr(isf[isfl].u.bcs.ptr);
 | |
| 
 | |
| 		isfl++;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < isfl ; i++)
 | |
| 	{
 | |
| 		if (isf[i].type == HAWK_PARSESTD_FILE) isf[i].u.file.cmgr = arg->script_cmgr;
 | |
| 	}
 | |
| 
 | |
| 	isf[isfl].type = HAWK_PARSESTD_NULL;
 | |
| 	arg->psin = isf;
 | |
| 
 | |
| 	if (opt.ind < argc)
 | |
| 	{
 | |
| 		/* the remaining arguments are input console file names */
 | |
| 		if (hawk_main_expand_wildcard(argc - opt.ind, &argv[opt.ind], do_glob, &arg->icf) <= -1)
 | |
| 		{
 | |
| 			hawk_main_print_error("failed to expand wildcard\n");
 | |
| 			goto oops;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 1;
 | |
| 
 | |
| oops:
 | |
| 	if (arg->gvm.ptr) free(arg->gvm.ptr);
 | |
| 	hawk_main_purge_xarg(&arg->icf);
 | |
| 	hawk_main_purge_xarg(&arg->ocf);
 | |
| 	if (isf) free(isf);
 | |
| 	return oops_ret;
 | |
| }
 | |
| 
 | |
| static void freearg (struct arg_t* arg)
 | |
| {
 | |
| 	if (arg->psin) free(arg->psin);
 | |
| 	/*if (arg->osf) free(arg->osf);*/
 | |
| 	hawk_main_purge_xarg(&arg->icf);
 | |
| 	hawk_main_purge_xarg(&arg->ocf);
 | |
| 	if (arg->gvm.ptr) free(arg->gvm.ptr);
 | |
| }
 | |
| 
 | |
| static void print_hawk_error(hawk_t* hawk)
 | |
| {
 | |
| 	const hawk_loc_t* loc = hawk_geterrloc(hawk);
 | |
| 
 | |
| 	hawk_logfmt(hawk, HAWK_LOG_STDERR,
 | |
| 		HAWK_T("ERROR: CODE %d LINE %zu COLUMN %zu %js%js%js- %js\n"),
 | |
| 		(int)hawk_geterrnum(hawk),
 | |
| 		(hawk_oow_t)loc->line,
 | |
| 		(hawk_oow_t)loc->colm,
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): HAWK_T("FILE ")),
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): loc->file),
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): HAWK_T(" ")),
 | |
| 		hawk_geterrmsg(hawk)
 | |
| 	);
 | |
| }
 | |
| 
 | |
| static void print_hawk_rtx_error(hawk_rtx_t* rtx)
 | |
| {
 | |
| 	const hawk_loc_t* loc = hawk_rtx_geterrloc(rtx);
 | |
| 
 | |
| 	hawk_logfmt(hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR,
 | |
| 		HAWK_T("ERROR: CODE %d LINE %zu COLUMN %zu %js%js%js- %js\n"),
 | |
| 		(int)hawk_rtx_geterrnum(rtx),
 | |
| 		(hawk_oow_t)loc->line,
 | |
| 		(hawk_oow_t)loc->colm,
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): HAWK_T("FILE ")),
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): loc->file),
 | |
| 		((loc->file == HAWK_NULL)? HAWK_T(""): HAWK_T(" ")),
 | |
| 		hawk_rtx_geterrmsg(rtx)
 | |
| 	);
 | |
| }
 | |
| 
 | |
| int main_hawk(int argc, hawk_bch_t* argv[], const hawk_bch_t* real_argv0)
 | |
| {
 | |
| 	hawk_t* hawk = HAWK_NULL;
 | |
| 	hawk_rtx_t* rtx = HAWK_NULL;
 | |
| 	hawk_val_t* retv;
 | |
| 	hawk_mmgr_t xma_mmgr;
 | |
| 	hawk_cmgr_t* cmgr;
 | |
| 	hawk_errinf_t errinf;
 | |
| 	int i;
 | |
| 	struct arg_t arg;
 | |
| 	int ret = -1;
 | |
| 
 | |
| #if defined(ENABLE_CALLBACK)
 | |
| 	static hawk_rtx_ecb_t rtx_ecb =
 | |
| 	{
 | |
| 		HAWK_FV(.close,  HAWK_NULL),
 | |
| 		HAWK_FV(.stmt,   on_statement),
 | |
| 		HAWK_FV(.gblset, HAWK_NULL)
 | |
| 		HAWK_FV(.ctx,    HAWK_NULL)
 | |
| 	};
 | |
| #endif
 | |
| 
 | |
| 	/* TODO: change it to support multiple source files */
 | |
| 	hawk_parsestd_t psout;
 | |
| 	hawk_mmgr_t* mmgr = hawk_get_sys_mmgr();
 | |
| 
 | |
| 	i = process_argv(argc, argv, real_argv0, &arg);
 | |
| 	if (i <= 0)
 | |
| 	{
 | |
| 		print_usage (((i == 0)? stdout: stderr), argv[0], real_argv0);
 | |
| 		return i;
 | |
| 	}
 | |
| 	if (i == 2) return 0;
 | |
| 	if (i == 3) return -1;
 | |
| 
 | |
| 	if (arg.osf)
 | |
| 	{
 | |
| 		psout.type = HAWK_PARSESTD_FILEB;
 | |
| 		psout.u.fileb.path = arg.osf;
 | |
| 		psout.u.fileb.cmgr = arg.script_cmgr;
 | |
| 	}
 | |
| 
 | |
| 	if (arg.memlimit > 0)
 | |
| 	{
 | |
| 		if (hawk_init_xma_mmgr(&xma_mmgr, arg.memlimit) <= -1)
 | |
| 		{
 | |
| 			hawk_main_print_error("cannot open memory heap\n");
 | |
| 			goto oops;
 | |
| 		}
 | |
| 		mmgr = &xma_mmgr;
 | |
| 	}
 | |
| 
 | |
| 	set_intr_pipe();
 | |
| 
 | |
| 	cmgr = hawk_get_cmgr_by_id(HAWK_CMGR_UTF8);
 | |
| 	hawk = hawk_openstdwithmmgr(mmgr, 0, cmgr, &errinf);
 | |
| 	if (HAWK_UNLIKELY(!hawk))
 | |
| 	{
 | |
| 		const hawk_bch_t* msg;
 | |
| 	#if defined(HAWK_OOCH_IS_UCH)
 | |
| 		hawk_bch_t msgbuf[HAWK_ERRMSG_CAPA];
 | |
| 		hawk_oow_t msglen, wcslen;
 | |
| 		msglen = HAWK_COUNTOF(msgbuf);
 | |
| 		hawk_conv_ucstr_to_bcstr_with_cmgr(errinf.msg, &wcslen, msgbuf, &msglen, cmgr);
 | |
| 		msg = msgbuf;
 | |
| 	#else
 | |
| 		msg = errinf.msg;
 | |
| 	#endif
 | |
| 		hawk_main_print_error("cannot open hawk - %s\n", msg);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (arg.modern) i = HAWK_MODERN;
 | |
| 	else if (arg.classic) i = HAWK_CLASSIC;
 | |
| 	else hawk_getopt(hawk, HAWK_OPT_TRAIT, &i);
 | |
| 	if (arg.opton) i |= arg.opton;
 | |
| 	if (arg.optoff) i &= ~arg.optoff;
 | |
| 	hawk_setopt(hawk, HAWK_OPT_TRAIT, &i);
 | |
| 
 | |
| 	/* TODO: get depth from command line */
 | |
| 	{
 | |
| 		hawk_oow_t tmp;
 | |
| 		tmp = 50;
 | |
| 		hawk_setopt(hawk, HAWK_OPT_DEPTH_BLOCK_PARSE, &tmp);
 | |
| 		hawk_setopt(hawk, HAWK_OPT_DEPTH_EXPR_PARSE, &tmp);
 | |
| 		tmp = 500;
 | |
| 		hawk_setopt(hawk, HAWK_OPT_DEPTH_BLOCK_RUN, &tmp);
 | |
| 		hawk_setopt(hawk, HAWK_OPT_DEPTH_EXPR_RUN, &tmp);
 | |
| 		tmp = 64;
 | |
| 		hawk_setopt(hawk, HAWK_OPT_DEPTH_INCLUDE, &tmp);
 | |
| 	}
 | |
| 
 | |
| 	if (arg.includedirs)
 | |
| 	{
 | |
| 	#if defined(HAWK_OOCH_IS_UCH)
 | |
| 		hawk_ooch_t* tmp;
 | |
| 		tmp = hawk_dupbtoucstr(hawk, arg.includedirs, HAWK_NULL, 1);
 | |
| 		if (HAWK_UNLIKELY(!tmp))
 | |
| 		{
 | |
| 			print_hawk_error(hawk);
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		hawk_setopt(hawk, HAWK_OPT_INCLUDEDIRS, tmp);
 | |
| 		hawk_freemem(hawk, tmp);
 | |
| 	#else
 | |
| 		hawk_setopt(hawk, HAWK_OPT_INCLUDEDIRS, arg.includedirs);
 | |
| 	#endif
 | |
| 	}
 | |
| 
 | |
| 	if (arg.modlibdirs)
 | |
| 	{
 | |
| 	#if defined(HAWK_OOCH_IS_UCH)
 | |
| 		hawk_ooch_t* tmp;
 | |
| 		tmp = hawk_dupbtoucstr(hawk, arg.modlibdirs, HAWK_NULL, 1);
 | |
| 		if (HAWK_UNLIKELY(!tmp))
 | |
| 		{
 | |
| 			print_hawk_error(hawk);
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		hawk_setopt(hawk, HAWK_OPT_MODLIBDIRS, tmp);
 | |
| 		hawk_freemem(hawk, tmp);
 | |
| 	#else
 | |
| 		hawk_setopt(hawk, HAWK_OPT_MODLIBDIRS, arg.modlibdirs);
 | |
| 	#endif
 | |
| 	}
 | |
| 
 | |
| 	if (add_gvs_to_hawk(hawk, &arg) <= -1)
 | |
| 	{
 | |
| 		print_hawk_error(hawk);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (hawk_parsestd(hawk, arg.psin, ((arg.osf == HAWK_NULL)? HAWK_NULL: &psout)) <= -1)
 | |
| 	{
 | |
| 		print_hawk_error(hawk);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	rtx = hawk_rtx_openstdwithbcstr(
 | |
| 		hawk, 0, argv[0],
 | |
| 		(arg.call? HAWK_NULL: arg.icf.ptr), /* console input */
 | |
| 		arg.ocf.ptr, /* console output */
 | |
| 		arg.console_cmgr
 | |
| 	);
 | |
| 	if (HAWK_UNLIKELY(!rtx))
 | |
| 	{
 | |
| 		print_hawk_error(hawk);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	if (apply_fs_and_gvs_to_rtx(rtx, &arg) <= -1)
 | |
| 	{
 | |
| 		print_hawk_rtx_error(rtx);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| 	app_rtx = rtx;
 | |
| #if defined(ENABLE_CALLBACK)
 | |
| 	hawk_rtx_pushecb(rtx, &rtx_ecb);
 | |
| #endif
 | |
| 
 | |
| 	set_intr_run();
 | |
| 
 | |
| #if 0
 | |
| 	retv = arg.call?
 | |
| 		hawk_rtx_callwithbcstrarr(rtx, arg.call, (const hawk_bch_t**)arg.icf.ptr, arg.icf.size):
 | |
| 		hawk_rtx_loop(rtx); /* this doesn't support @pragma startup ... */
 | |
| #else
 | |
| 	/* note about @pragma entry ...
 | |
| 	 * hawk_rtx_execwithbcstrarr() invokes the specified function if '@pragma entry' is set
 | |
| 	 * in the source code. because arg.icf.ptr has been passed to hawk_rtx_openstdwithbcstr() when
 | |
| 	 * arg.call is HAWK_NULL, arg.icf.ptr serves as parameters to the startup function and
 | |
| 	 * affects input consoles */
 | |
| 	retv = arg.call?
 | |
| 		hawk_rtx_callwithbcstrarr(rtx, arg.call, (const hawk_bch_t**)arg.icf.ptr, arg.icf.size):
 | |
| 		hawk_rtx_execwithbcstrarr(rtx, (const hawk_bch_t**)arg.icf.ptr, arg.icf.size);
 | |
| #endif
 | |
| 
 | |
| 	unset_intr_run();
 | |
| 
 | |
| 	if (retv)
 | |
| 	{
 | |
| 		hawk_int_t tmp;
 | |
| 
 | |
| 		hawk_rtx_refdownval(rtx, retv);
 | |
| 		if (arg.debug) dprint_return(rtx, retv);
 | |
| 
 | |
| 		ret = 0;
 | |
| 		if (hawk_rtx_valtoint(rtx, retv, &tmp) >= 0) ret = tmp;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		print_hawk_rtx_error(rtx);
 | |
| 		goto oops;
 | |
| 	}
 | |
| 
 | |
| oops:
 | |
| 	if (rtx) hawk_rtx_close(rtx);
 | |
| 	if (hawk) hawk_close(hawk);
 | |
| 
 | |
| 	unset_intr_pipe();
 | |
| 
 | |
| 	if (arg.memlimit > 0)
 | |
| 	{
 | |
| 		if (arg.debug) hawk_xma_dump(xma_mmgr.ctx, hawk_main_print_xma, HAWK_NULL);
 | |
| 		hawk_fini_xma_mmgr(&xma_mmgr);
 | |
| 	}
 | |
| 	freearg(&arg);
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 |