added -v var=val to cmd/awk/awk.c
This commit is contained in:
		@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: awk.c 204 2009-06-18 12:08:06Z hyunghwan.chung $
 | 
			
		||||
 * $Id: awk.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -42,10 +42,10 @@
 | 
			
		||||
#	include <errno.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static qse_awk_rtx_t* app_rtx = NULL;
 | 
			
		||||
static qse_awk_rtx_t* app_rtx = QSE_NULL;
 | 
			
		||||
static int app_debug = 0;
 | 
			
		||||
 | 
			
		||||
struct argout_t
 | 
			
		||||
struct arg_t
 | 
			
		||||
{
 | 
			
		||||
	qse_awk_parsestd_type_t ist;  /* input source type */
 | 
			
		||||
	union
 | 
			
		||||
@ -58,14 +58,19 @@ struct argout_t
 | 
			
		||||
	qse_awk_parsestd_type_t ost;  /* output source type */
 | 
			
		||||
	qse_char_t*  osf;  /* output source file */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	qse_char_t** arg;
 | 
			
		||||
	qse_char_t** icf;  /* input console files */
 | 
			
		||||
	qse_size_t   icfl; /* the number of input console files */
 | 
			
		||||
	qse_map_t*   vm;   /* global variable map */
 | 
			
		||||
	qse_map_t*   gvm;  /* global variable map */
 | 
			
		||||
	qse_char_t*  fs;   /* field separator */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gvmv_t
 | 
			
		||||
{
 | 
			
		||||
	int         idx;
 | 
			
		||||
	qse_char_t* ptr;
 | 
			
		||||
	qse_size_t  len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void dprint (const qse_char_t* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	if (app_debug)
 | 
			
		||||
@ -185,16 +190,33 @@ static void on_run_statement (
 | 
			
		||||
	/*dprint (L"running %d\n", (int)line);*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static qse_map_walk_t set_global (
 | 
			
		||||
	qse_map_t* map, qse_map_pair_t* pair, void* arg)
 | 
			
		||||
{
 | 
			
		||||
	qse_awk_val_t* v;
 | 
			
		||||
	qse_awk_rtx_t* rtx = (qse_awk_rtx_t*)arg;
 | 
			
		||||
	struct gvmv_t* gvmv = (struct gvmv_t*)QSE_MAP_VPTR(pair);
 | 
			
		||||
 | 
			
		||||
	v = qse_awk_rtx_makenstrval (rtx, gvmv->ptr, gvmv->len);
 | 
			
		||||
	if (v == QSE_NULL) return QSE_MAP_WALK_STOP;
 | 
			
		||||
 | 
			
		||||
	qse_awk_rtx_refupval (rtx, v);
 | 
			
		||||
	qse_awk_rtx_setgbl (rtx, gvmv->idx, v);
 | 
			
		||||
	qse_awk_rtx_refdownval (rtx, v);
 | 
			
		||||
 | 
			
		||||
	return QSE_MAP_WALK_FORWARD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int on_run_enter (qse_awk_rtx_t* rtx, void* data)
 | 
			
		||||
{
 | 
			
		||||
	struct argout_t* ao = (struct argout_t*)data;
 | 
			
		||||
	struct arg_t* arg = (struct arg_t*)data;
 | 
			
		||||
 | 
			
		||||
	if (ao->fs != QSE_NULL)
 | 
			
		||||
	if (arg->fs != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		qse_awk_val_t* fs;
 | 
			
		||||
 | 
			
		||||
		/* compose a string value to use to set FS to */
 | 
			
		||||
		fs = qse_awk_rtx_makestrval0 (rtx, ao->fs);
 | 
			
		||||
		fs = qse_awk_rtx_makestrval0 (rtx, arg->fs);
 | 
			
		||||
		if (fs == QSE_NULL) return -1;
 | 
			
		||||
 | 
			
		||||
		/* change FS according to the command line argument */
 | 
			
		||||
@ -203,6 +225,15 @@ static int on_run_enter (qse_awk_rtx_t* rtx, void* data)
 | 
			
		||||
		qse_awk_rtx_refdownval (rtx, fs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg->gvm != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		/* set the value of user-defined global variables 
 | 
			
		||||
		 * to a runtime context */
 | 
			
		||||
		qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOERR);
 | 
			
		||||
		qse_map_walk (arg->gvm, set_global, rtx);
 | 
			
		||||
		if (qse_awk_rtx_geterrnum(rtx) != QSE_AWK_ENOERR) return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -270,11 +301,12 @@ static void print_usage (const qse_char_t* argv0)
 | 
			
		||||
	qse_printf (QSE_T(" -f/--file            sourcefile   set the source script file\n"));
 | 
			
		||||
	qse_printf (QSE_T(" -o/--deparsed-file   deparsedfile set the deparsing output file\n"));
 | 
			
		||||
	qse_printf (QSE_T(" -F/--field-separator string       set a field separator(FS)\n"));
 | 
			
		||||
	qse_printf (QSE_T(" -v/--assign          var=value    add a global variable with a value\n"));
 | 
			
		||||
 | 
			
		||||
	qse_printf (QSE_T("\nYou may specify the following options to change the behavior of the interpreter.\n"));
 | 
			
		||||
	for (j = 0; j < QSE_COUNTOF(otab); j++)
 | 
			
		||||
	{
 | 
			
		||||
		qse_printf (QSE_T("    -%-20s -no%-20s\n"), otab[j].name, otab[j].name);
 | 
			
		||||
		qse_printf (QSE_T("    --%-20s --no%-20s\n"), otab[j].name, otab[j].name);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -320,7 +352,7 @@ static void out_of_memory (void)
 | 
			
		||||
	qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n"));	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
 | 
			
		||||
{
 | 
			
		||||
	static qse_opt_lng_t lng[] = 
 | 
			
		||||
	{
 | 
			
		||||
@ -331,11 +363,9 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
		{ QSE_T("idiv"),             0 },
 | 
			
		||||
		{ QSE_T("extio"),            0 },
 | 
			
		||||
		{ QSE_T("newline"),          0 },
 | 
			
		||||
		{ QSE_T("baseone"),          0 },
 | 
			
		||||
		{ QSE_T("stripspaces"),      0 },
 | 
			
		||||
		{ QSE_T("nextofile"),        0 },
 | 
			
		||||
		{ QSE_T("crlf"),             0 },
 | 
			
		||||
		{ QSE_T("argstomain"),       0 },
 | 
			
		||||
		{ QSE_T("reset"),            0 },
 | 
			
		||||
		{ QSE_T("maptovar"),         0 },
 | 
			
		||||
		{ QSE_T("pablock"),          0 },
 | 
			
		||||
@ -368,42 +398,43 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
	qse_char_t*  osf = QSE_NULL; /* output source file */
 | 
			
		||||
	qse_char_t** icf = QSE_NULL; /* input console files */
 | 
			
		||||
 | 
			
		||||
	qse_map_t* vm = QSE_NULL;  /* global variable map */
 | 
			
		||||
	qse_map_t* gvm = QSE_NULL;  /* global variable map */
 | 
			
		||||
	qse_char_t* fs = QSE_NULL; /* field separator */
 | 
			
		||||
 | 
			
		||||
	memset (ao, 0, QSE_SIZEOF(*ao));
 | 
			
		||||
	memset (arg, 0, QSE_SIZEOF(*arg));
 | 
			
		||||
 | 
			
		||||
	isf = (qse_char_t**) malloc (QSE_SIZEOF(*isf) * isfc);
 | 
			
		||||
	if (isf == QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		out_of_memory ();
 | 
			
		||||
		ABORT (oops);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vm = qse_map_open (QSE_NULL, 0, 30, 70); 
 | 
			
		||||
	if (vm == QSE_NULL)
 | 
			
		||||
	gvm = qse_map_open (QSE_NULL, 0, 30, 70); 
 | 
			
		||||
	if (gvm == QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		out_of_memory ();
 | 
			
		||||
		ABORT (oops);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	qse_map_setcopier (vm, QSE_MAP_KEY, QSE_MAP_COPIER_INLINE);
 | 
			
		||||
	qse_map_setcopier (vm, QSE_MAP_VAL, QSE_MAP_COPIER_INLINE);
 | 
			
		||||
	qse_map_setscale (vm, QSE_MAP_KEY, QSE_SIZEOF(qse_char_t));
 | 
			
		||||
	qse_map_setscale (vm, QSE_MAP_VAL, QSE_SIZEOF(qse_char_t));
 | 
			
		||||
	/*qse_map_setcopier (gvm, QSE_MAP_KEY, QSE_MAP_COPIER_INLINE);*/
 | 
			
		||||
	qse_map_setscale (gvm, QSE_MAP_KEY, QSE_SIZEOF(qse_char_t));
 | 
			
		||||
	qse_map_setcopier (gvm, QSE_MAP_VAL, QSE_MAP_COPIER_INLINE);
 | 
			
		||||
	qse_map_setscale (gvm, QSE_MAP_VAL, QSE_SIZEOF(struct gvmv_t));
 | 
			
		||||
 | 
			
		||||
	while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
 | 
			
		||||
	{
 | 
			
		||||
		switch (c)
 | 
			
		||||
		{
 | 
			
		||||
			case 0:
 | 
			
		||||
				/* TODO: handle long options ... */
 | 
			
		||||
				qse_printf (QSE_T(">>> [%s] [%s]\n"), opt.lngopt, opt.arg);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case QSE_T('h'):
 | 
			
		||||
				print_usage (argv[0]);
 | 
			
		||||
				if (isf != QSE_NULL) free (isf);
 | 
			
		||||
				if (vm != QSE_NULL) qse_map_close (vm);
 | 
			
		||||
				return 1;
 | 
			
		||||
				if (gvm != QSE_NULL) qse_map_close (gvm);
 | 
			
		||||
				return 0;
 | 
			
		||||
 | 
			
		||||
			case QSE_T('d'):
 | 
			
		||||
			{
 | 
			
		||||
@ -420,7 +451,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
					if (tmp == QSE_NULL)
 | 
			
		||||
					{
 | 
			
		||||
						out_of_memory ();
 | 
			
		||||
						ABORT (oops);
 | 
			
		||||
						goto oops;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					isf = tmp;
 | 
			
		||||
@ -445,19 +476,26 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
 | 
			
		||||
			case QSE_T('v'):
 | 
			
		||||
			{
 | 
			
		||||
				qse_char_t* eq = qse_strchr(opt.arg, QSE_T('='));
 | 
			
		||||
				struct gvmv_t gvmv;
 | 
			
		||||
				qse_char_t* eq;
 | 
			
		||||
 | 
			
		||||
				eq = qse_strchr(opt.arg, QSE_T('='));
 | 
			
		||||
				if (eq == QSE_NULL)
 | 
			
		||||
				{
 | 
			
		||||
					/* INVALID VALUE... */
 | 
			
		||||
					ABORT (oops);
 | 
			
		||||
					goto oops;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				*eq = QSE_T('\0');
 | 
			
		||||
 | 
			
		||||
				if (qse_map_upsert (vm, opt.arg, qse_strlen(opt.arg)+1, eq, qse_strlen(eq)+1) == QSE_NULL)
 | 
			
		||||
				gvmv.idx = -1;
 | 
			
		||||
				gvmv.ptr = ++eq;
 | 
			
		||||
				gvmv.len = qse_strlen(eq);
 | 
			
		||||
 | 
			
		||||
				if (qse_map_upsert (gvm, opt.arg, qse_strlen(opt.arg), &gvmv, 1) == QSE_NULL)
 | 
			
		||||
				{
 | 
			
		||||
					out_of_memory ();
 | 
			
		||||
					ABORT (oops);
 | 
			
		||||
					goto oops;
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
@ -473,7 +511,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
					qse_printf (QSE_T("Error: illegal option - %c\n"), opt.opt);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				ABORT (oops);
 | 
			
		||||
				goto oops;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case QSE_T(':'):
 | 
			
		||||
@ -487,11 +525,11 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
					qse_printf (QSE_T("Error: bad argument for %c\n"), opt.opt);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				ABORT (oops);
 | 
			
		||||
				goto oops;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				ABORT (oops);
 | 
			
		||||
				goto oops;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -502,19 +540,19 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
		if (opt.ind >= argc)
 | 
			
		||||
		{
 | 
			
		||||
			/* no source code specified */
 | 
			
		||||
			ABORT (oops);
 | 
			
		||||
			goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* the source code is the string, not from the file */
 | 
			
		||||
		ao->ist = QSE_AWK_PARSESTD_CP;
 | 
			
		||||
		ao->isp.str = argv[opt.ind++];
 | 
			
		||||
		arg->ist = QSE_AWK_PARSESTD_CP;
 | 
			
		||||
		arg->isp.str = argv[opt.ind++];
 | 
			
		||||
 | 
			
		||||
		free (isf);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		ao->ist = QSE_AWK_PARSESTD_FILE;
 | 
			
		||||
		ao->isp.files = isf;
 | 
			
		||||
		arg->ist = QSE_AWK_PARSESTD_FILE;
 | 
			
		||||
		arg->isp.files = isf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (opt.ind < argc) 
 | 
			
		||||
@ -526,7 +564,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
		if (icf == QSE_NULL)
 | 
			
		||||
		{
 | 
			
		||||
			out_of_memory ();
 | 
			
		||||
			ABORT (oops);
 | 
			
		||||
			goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (opt.ind >= argc)
 | 
			
		||||
@ -542,32 +580,105 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao)
 | 
			
		||||
		icf[icfl] = QSE_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ao->ost = QSE_AWK_PARSESTD_FILE;
 | 
			
		||||
	ao->osf = osf;
 | 
			
		||||
	arg->ost = QSE_AWK_PARSESTD_FILE;
 | 
			
		||||
	arg->osf = osf;
 | 
			
		||||
 | 
			
		||||
	ao->icf = icf;
 | 
			
		||||
	ao->icfl = icfl;
 | 
			
		||||
	ao->vm = vm;
 | 
			
		||||
	ao->fs = fs;
 | 
			
		||||
	arg->icf = icf;
 | 
			
		||||
	arg->icfl = icfl;
 | 
			
		||||
	arg->gvm = gvm;
 | 
			
		||||
	arg->fs = fs;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return 1;
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	if (vm != QSE_NULL) qse_map_close (vm);
 | 
			
		||||
	if (gvm != QSE_NULL) qse_map_close (gvm);
 | 
			
		||||
	if (icf != QSE_NULL) free (icf);
 | 
			
		||||
	if (isf != QSE_NULL) free (isf);
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static qse_awk_t* open_awk (void)
 | 
			
		||||
static void freearg (struct arg_t* arg)
 | 
			
		||||
{
 | 
			
		||||
	if (arg->ist == QSE_AWK_PARSESTD_FILE &&
 | 
			
		||||
	    arg->isp.files != QSE_NULL) free (arg->isp.files);
 | 
			
		||||
	/*if (arg->osf != QSE_NULL) free (arg->osf);*/
 | 
			
		||||
	if (arg->icf != QSE_NULL) free (arg->icf);
 | 
			
		||||
	if (arg->gvm != QSE_NULL) qse_map_close (arg->gvm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_awkerr (qse_awk_t* awk)
 | 
			
		||||
{
 | 
			
		||||
	qse_printf (
 | 
			
		||||
		QSE_T("ERROR: CODE [%d] LINE [%u] %s\n"), 
 | 
			
		||||
		qse_awk_geterrnum(awk),
 | 
			
		||||
		(unsigned int)qse_awk_geterrlin(awk), 
 | 
			
		||||
		qse_awk_geterrmsg(awk)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_rtxerr (qse_awk_rtx_t* rtx)
 | 
			
		||||
{
 | 
			
		||||
	qse_printf (
 | 
			
		||||
		QSE_T("ERROR: CODE [%d] LINE [%u] %s\n"),
 | 
			
		||||
		qse_awk_rtx_geterrnum(rtx),
 | 
			
		||||
		(unsigned int)qse_awk_rtx_geterrlin(rtx),
 | 
			
		||||
		qse_awk_rtx_geterrmsg(rtx)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qse_map_walk_t add_global (qse_map_t* map, qse_map_pair_t* pair, void* arg)
 | 
			
		||||
{
 | 
			
		||||
	qse_awk_t* awk = (qse_awk_t*)arg;
 | 
			
		||||
	struct gvmv_t* gvmv = (struct gvmv_t*)QSE_MAP_VPTR(pair);
 | 
			
		||||
 | 
			
		||||
	gvmv->idx = qse_awk_addgbl (awk, QSE_MAP_KPTR(pair), QSE_MAP_KLEN(pair));
 | 
			
		||||
	if (gvmv->idx <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		return QSE_MAP_WALK_STOP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return QSE_MAP_WALK_FORWARD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int awk_main (int argc, qse_char_t* argv[])
 | 
			
		||||
{
 | 
			
		||||
	qse_awk_t* awk;
 | 
			
		||||
	qse_awk_rtx_t* rtx;
 | 
			
		||||
	qse_awk_rcb_t rcb;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	struct arg_t arg;
 | 
			
		||||
	int ret = -1;
 | 
			
		||||
 | 
			
		||||
	/* TODO: change it to support multiple source files */
 | 
			
		||||
	qse_awk_parsestd_in_t psin;
 | 
			
		||||
	qse_awk_parsestd_out_t psout;
 | 
			
		||||
 | 
			
		||||
	qse_memset (&arg, 0, QSE_SIZEOF(arg));
 | 
			
		||||
 | 
			
		||||
	i = comparg (argc, argv, &arg);
 | 
			
		||||
	if (i <= -1)
 | 
			
		||||
	{
 | 
			
		||||
		print_usage (argv[0]);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (i == 0) return 0;
 | 
			
		||||
 | 
			
		||||
	psin.type = arg.ist;
 | 
			
		||||
	if (arg.ist == QSE_AWK_PARSESTD_CP) psin.u.cp = arg.isp.str;
 | 
			
		||||
	else psin.u.file = arg.isp.files[0];
 | 
			
		||||
 | 
			
		||||
	if (arg.osf != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		psout.type = arg.ost;
 | 
			
		||||
		psout.u.file = arg.osf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	awk = qse_awk_openstd (0);
 | 
			
		||||
	if (awk == QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		qse_printf (QSE_T("ERROR: cannot open awk\n"));
 | 
			
		||||
		return QSE_NULL;
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: get depth from command line */
 | 
			
		||||
@ -580,118 +691,55 @@ static qse_awk_t* open_awk (void)
 | 
			
		||||
		QSE_T("sleep"), 5, 0,
 | 
			
		||||
		1, 1, QSE_NULL, fnc_sleep) == QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		qse_awk_close (awk);
 | 
			
		||||
		qse_printf (QSE_T("ERROR: cannot add function 'sleep'\n"));
 | 
			
		||||
		return QSE_NULL;
 | 
			
		||||
		print_awkerr (awk);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return awk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int awk_main (int argc, qse_char_t* argv[])
 | 
			
		||||
{
 | 
			
		||||
	qse_awk_t* awk;
 | 
			
		||||
	qse_awk_rtx_t* rtx;
 | 
			
		||||
	qse_awk_rcb_t rcb;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	int runarg_count = 0;
 | 
			
		||||
	qse_cstr_t runarg[128];
 | 
			
		||||
	struct argout_t ao;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* TODO: change it to support multiple source files */
 | 
			
		||||
	qse_awk_parsestd_in_t psin;
 | 
			
		||||
	qse_awk_parsestd_out_t psout;
 | 
			
		||||
 | 
			
		||||
	qse_memset (&ao, 0, QSE_SIZEOF(ao));
 | 
			
		||||
 | 
			
		||||
	i = handle_args (argc, argv, &ao);
 | 
			
		||||
	if (i == -1)
 | 
			
		||||
	qse_awk_seterrnum (awk, QSE_AWK_ENOERR);
 | 
			
		||||
	qse_map_walk (arg.gvm, add_global, awk);
 | 
			
		||||
	if (qse_awk_geterrnum(awk) != QSE_AWK_ENOERR)
 | 
			
		||||
	{
 | 
			
		||||
		print_usage (argv[0]);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (i == 1) return 0;
 | 
			
		||||
 | 
			
		||||
	runarg[runarg_count].ptr = NULL;
 | 
			
		||||
	runarg[runarg_count].len = 0;
 | 
			
		||||
 | 
			
		||||
	awk = open_awk ();
 | 
			
		||||
	if (awk == QSE_NULL) return -1;
 | 
			
		||||
	
 | 
			
		||||
	psin.type = ao.ist;
 | 
			
		||||
	if (ao.ist == QSE_AWK_PARSESTD_CP) psin.u.cp = ao.isp.str;
 | 
			
		||||
	else psin.u.file = ao.isp.files[0];
 | 
			
		||||
 | 
			
		||||
	if (ao.osf != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		psout.type = ao.ost;
 | 
			
		||||
		psout.u.file = ao.osf;
 | 
			
		||||
		print_awkerr (awk);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (qse_awk_parsestd (awk, &psin, 
 | 
			
		||||
		((ao.osf == QSE_NULL)? QSE_NULL: &psout)) == -1)
 | 
			
		||||
		((arg.osf == QSE_NULL)? QSE_NULL: &psout)) == -1)
 | 
			
		||||
	{
 | 
			
		||||
		qse_printf (
 | 
			
		||||
			QSE_T("PARSE ERROR: CODE [%d] LINE [%u] %s\n"), 
 | 
			
		||||
			qse_awk_geterrnum(awk),
 | 
			
		||||
			(unsigned int)qse_awk_geterrlin(awk), 
 | 
			
		||||
			qse_awk_geterrmsg(awk)
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		ret = -1;
 | 
			
		||||
		print_awkerr (awk);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rcb.on_enter = on_run_enter;
 | 
			
		||||
	rcb.on_statement = on_run_statement;
 | 
			
		||||
	rcb.on_exit = on_run_exit;
 | 
			
		||||
	rcb.data = &ao;
 | 
			
		||||
	rcb.data = &arg;
 | 
			
		||||
 | 
			
		||||
	rtx = qse_awk_rtx_openstd (awk, 0, QSE_T("qseawk"), ao.icf, QSE_NULL);
 | 
			
		||||
	rtx = qse_awk_rtx_openstd (awk, 0, QSE_T("qseawk"), arg.icf, QSE_NULL);
 | 
			
		||||
	if (rtx == QSE_NULL) 
 | 
			
		||||
	{
 | 
			
		||||
		qse_printf (
 | 
			
		||||
			QSE_T("PARSE ERROR: CODE [%d] LINE [%u] %s\n"), 
 | 
			
		||||
			qse_awk_geterrnum(awk),
 | 
			
		||||
			(unsigned int)qse_awk_geterrlin(awk), 
 | 
			
		||||
			qse_awk_geterrmsg(awk)
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		ret = -1;
 | 
			
		||||
		print_awkerr (awk);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
 | 
			
		||||
	app_rtx = rtx;
 | 
			
		||||
	qse_awk_rtx_setrcb (rtx, &rcb);
 | 
			
		||||
 | 
			
		||||
	set_intr_run ();
 | 
			
		||||
	ret = qse_awk_rtx_loop (rtx);
 | 
			
		||||
	unset_intr_run ();
 | 
			
		||||
 | 
			
		||||
	if (ret == -1)
 | 
			
		||||
	{
 | 
			
		||||
		app_rtx = rtx;
 | 
			
		||||
		set_intr_run ();
 | 
			
		||||
 | 
			
		||||
		qse_awk_rtx_setrcb (rtx, &rcb);
 | 
			
		||||
		ret = qse_awk_rtx_loop (rtx);
 | 
			
		||||
 | 
			
		||||
		unset_intr_run ();
 | 
			
		||||
 | 
			
		||||
		if (ret == -1)
 | 
			
		||||
		{
 | 
			
		||||
			qse_printf (QSE_T("RUN ERROR: CODE [%d] LINE [%u] %s\n"),
 | 
			
		||||
				(unsigned int)qse_awk_rtx_geterrnum(rtx),
 | 
			
		||||
				(unsigned int)qse_awk_rtx_geterrlin(rtx),
 | 
			
		||||
				qse_awk_rtx_geterrmsg(rtx)
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		qse_awk_rtx_close (rtx);
 | 
			
		||||
		print_rtxerr (rtx);
 | 
			
		||||
		goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
oops:
 | 
			
		||||
	qse_awk_close (awk);
 | 
			
		||||
 | 
			
		||||
	if (ao.ist == QSE_AWK_PARSESTD_FILE && 
 | 
			
		||||
	    ao.isp.files != QSE_NULL) free (ao.isp.files);
 | 
			
		||||
	/*if (ao.osf != QSE_NULL) free (ao.osf);*/
 | 
			
		||||
	if (ao.icf != QSE_NULL) free (ao.icf);
 | 
			
		||||
	if (ao.vm != QSE_NULL) qse_map_close (ao.vm);
 | 
			
		||||
	if (rtx != QSE_NULL) qse_awk_rtx_close (rtx);
 | 
			
		||||
	if (awk != QSE_NULL) qse_awk_close (awk);
 | 
			
		||||
 | 
			
		||||
	freearg (&arg);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: Awk.hpp 204 2009-06-18 12:08:06Z hyunghwan.chung $
 | 
			
		||||
 * $Id: Awk.hpp 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -462,6 +462,7 @@ public:
 | 
			
		||||
		ERR_BLKEND = QSE_AWK_EBLKEND,
 | 
			
		||||
		ERR_DUPBEG = QSE_AWK_EDUPBEG,
 | 
			
		||||
		ERR_DUPEND = QSE_AWK_EDUPEND,
 | 
			
		||||
		ERR_KWRED = QSE_AWK_EKWRED,
 | 
			
		||||
		ERR_FNCRED = QSE_AWK_EFNCRED,
 | 
			
		||||
		ERR_FUNRED = QSE_AWK_EFUNRED,
 | 
			
		||||
		ERR_GBLRED = QSE_AWK_EGBLRED,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: awk.h 204 2009-06-18 12:08:06Z hyunghwan.chung $
 | 
			
		||||
 * $Id: awk.h 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -495,6 +495,7 @@ enum qse_awk_errnum_t
 | 
			
		||||
	QSE_AWK_EBLKEND,        /* END requires an action block */
 | 
			
		||||
	QSE_AWK_EDUPBEG,        /* duplicate BEGIN */
 | 
			
		||||
	QSE_AWK_EDUPEND,        /* duplicate END */
 | 
			
		||||
	QSE_AWK_EKWRED,         /* keyword redefined */
 | 
			
		||||
	QSE_AWK_EFNCRED,        /* intrinsic function redefined */
 | 
			
		||||
	QSE_AWK_EFUNRED,        /* function redefined */
 | 
			
		||||
	QSE_AWK_EGBLRED,        /* global variable redefined */
 | 
			
		||||
@ -1026,78 +1027,59 @@ void qse_awk_clrfnc (
 | 
			
		||||
/*****/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_parse
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_awk_parse - parse source code
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_parse() function parses the source script.
 | 
			
		||||
 * @return 0 on success, -1 on failure.
 | 
			
		||||
 */
 | 
			
		||||
int qse_awk_parse (
 | 
			
		||||
	qse_awk_t*     awk,
 | 
			
		||||
	qse_awk_sio_t* sio
 | 
			
		||||
	qse_awk_t*     awk, /**< an awk object */
 | 
			
		||||
	qse_awk_sio_t* sio  /**< source stream I/O handler */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_alloc
 | 
			
		||||
 * NAME 
 | 
			
		||||
 *  qse_awk_alloc - allocate dynamic memory
 | 
			
		||||
 * RETURN
 | 
			
		||||
 *   the pointer to the memory space allocated on success, QSE_NULL on failure
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_alloc() function allocates dynamic memory.
 | 
			
		||||
 * @return a pointer to memory space allocated on success, QSE_NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
void* qse_awk_alloc (
 | 
			
		||||
	qse_awk_t* awk /* the pointer to a qse_awk_t instance */,
 | 
			
		||||
	qse_size_t size /* the size of memory to allocate in bytes */
 | 
			
		||||
	qse_awk_t* awk,  /**< an awk object */
 | 
			
		||||
	qse_size_t size  /**< size of memory to allocate in bytes */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_free
 | 
			
		||||
 * NAME 
 | 
			
		||||
 *  qse_awk_free - free dynamic memory
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_free() function frees dynamic memory allocated.
 | 
			
		||||
 */
 | 
			
		||||
void qse_awk_free (
 | 
			
		||||
	qse_awk_t* awk /* the pointer to a qse_awk_t instance */,
 | 
			
		||||
	void*      ptr /* the pointer to the memory space to free */
 | 
			
		||||
	qse_awk_t* awk, /**< an awk object */
 | 
			
		||||
	void*      ptr  /**< memory space to free */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_strdup
 | 
			
		||||
 * NAME 
 | 
			
		||||
 *  qse_awk_strdup - duplicate a null-terminated string
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  The qse_awk_strdup() function is used to duplicate a string using
 | 
			
		||||
 *  the memory manager used by the associated qse_awk_t instance.
 | 
			
		||||
 *  The new string should be freed using the qse_awk_free() function.
 | 
			
		||||
 * RETURN
 | 
			
		||||
 *  The qse_awk_strdup() function returns the pointer to a new string which
 | 
			
		||||
 *  is a duplicate of the string s. It returns QSE_NULL on failure.
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_strdup() function is used to duplicate a string using
 | 
			
		||||
 * the memory manager used by the associated qse_awk_t instance.
 | 
			
		||||
 * The new string should be freed using the qse_awk_free() function.
 | 
			
		||||
 *
 | 
			
		||||
 * @return a pointer to a new string duplicated of @a s on success, 
 | 
			
		||||
 *         QSE_NULL on failure.
 | 
			
		||||
 */
 | 
			
		||||
qse_char_t* qse_awk_strdup (
 | 
			
		||||
	qse_awk_t*        awk /* the pointer to a qse_awk_t instance */,
 | 
			
		||||
	const qse_char_t* str /* the pointer to a string */
 | 
			
		||||
	qse_awk_t*        awk, /**< an awk object */
 | 
			
		||||
	const qse_char_t* str  /**< a string pointer */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_strxdup 
 | 
			
		||||
 * NAME 
 | 
			
		||||
 *  qse_awk_strxdup - duplicate a length-delimited string
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  The qse_awk_strxdup() function is used to duplicate a string whose length
 | 
			
		||||
 *  is as long as len characters using the memory manager used by the 
 | 
			
		||||
 *  qse_awk_t instance. The new string should be freed using the qse_awk_free()
 | 
			
		||||
 *  function.
 | 
			
		||||
 * RETURN
 | 
			
		||||
 *  The qse_awk_strxdup() function returns the pointer to a new string which 
 | 
			
		||||
 *  is a duplicate of the string s on success. It returns QSE_NULL on failure.
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_strxdup() function is used to duplicate a string whose length
 | 
			
		||||
 * is as long as len characters using the memory manager used by the 
 | 
			
		||||
 * qse_awk_t instance. The new string should be freed using the qse_awk_free()
 | 
			
		||||
 * function.
 | 
			
		||||
 *
 | 
			
		||||
 * @return a pointer to a new string duplicated of @a s on success, 
 | 
			
		||||
 *         QSE_NULL on failure.
 | 
			
		||||
 */
 | 
			
		||||
qse_char_t* qse_awk_strxdup (
 | 
			
		||||
	qse_awk_t*        awk,
 | 
			
		||||
	const qse_char_t* str,
 | 
			
		||||
	qse_size_t        len
 | 
			
		||||
	qse_awk_t*        awk, /**< an awk object */
 | 
			
		||||
	const qse_char_t* str, /**< a string pointer */
 | 
			
		||||
	qse_size_t        len  /**< the number of character in a string */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
qse_long_t qse_awk_strxtolong (
 | 
			
		||||
	qse_awk_t*         awk,
 | 
			
		||||
@ -1476,6 +1458,12 @@ qse_awk_val_t* qse_awk_rtx_makestrval2 (
 | 
			
		||||
	qse_size_t        len2
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
qse_awk_val_t* qse_awk_rtx_makenstrval (
 | 
			
		||||
	qse_awk_rtx_t*    rtx,
 | 
			
		||||
	const qse_char_t* str,
 | 
			
		||||
	qse_size_t        len
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
qse_awk_val_t* qse_awk_rtx_makerexval (
 | 
			
		||||
	qse_awk_rtx_t*    rtx,
 | 
			
		||||
	const qse_char_t* buf,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: std.h 196 2009-06-11 07:44:44Z hyunghwan.chung $
 | 
			
		||||
 * $Id: std.h 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,15 @@
 | 
			
		||||
#include <qse/awk/awk.h>
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 * Standard AWK Interpreter
 | 
			
		||||
 * This file defines functions and data types that help you create
 | 
			
		||||
 * an awk interpreter with less effort. It is designed to be as close
 | 
			
		||||
 * to conventional awk implementations as possible.
 | 
			
		||||
 * 
 | 
			
		||||
 * The source script handler does not evaluate a file name of the "var=val"
 | 
			
		||||
 * form as an assignment expression. Instead, it just treats it as a
 | 
			
		||||
 * normal file name.
 | 
			
		||||
 *
 | 
			
		||||
 * @todo
 | 
			
		||||
 * - console name handling an empty string("") and assignment (v=yyyy)
 | 
			
		||||
 * - StdAwk ARGV and console name handling
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -121,8 +127,8 @@ int qse_awk_parsestd (
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_rtx_openstd() function creates a standard runtime context.
 | 
			
		||||
 * The caller should keep the contents of icf and ocf valid throughout
 | 
			
		||||
 * the lifetime of the runtime context created. The runtime context 
 | 
			
		||||
 * The caller should keep the contents of @a icf and @a ocf valid throughout
 | 
			
		||||
 * the lifetime of the runtime context created. 
 | 
			
		||||
 */
 | 
			
		||||
qse_awk_rtx_t* qse_awk_rtx_openstd (
 | 
			
		||||
	qse_awk_t*              awk,
 | 
			
		||||
@ -132,15 +138,12 @@ qse_awk_rtx_t* qse_awk_rtx_openstd (
 | 
			
		||||
	const qse_char_t*const* ocf
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/****f* AWK/qse_awk_rtx_getxtnstd
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_awk_rtx_getxtnstd - get the pointer to extension space
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_awk_rtx_getxtnstd() gets the pointer to extension space.
 | 
			
		||||
 */
 | 
			
		||||
void* qse_awk_rtx_getxtnstd (
 | 
			
		||||
	qse_awk_rtx_t* rtx
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: map.h 101 2009-03-15 14:36:05Z hyunghwan.chung $
 | 
			
		||||
 * $Id: map.h 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -22,13 +22,9 @@
 | 
			
		||||
#include <qse/types.h>
 | 
			
		||||
#include <qse/macros.h>
 | 
			
		||||
 | 
			
		||||
/****o* Common/Hash Map
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  A hash map maintains buckets for key/value pairs with the same key hash
 | 
			
		||||
 *  chained under the same bucket.
 | 
			
		||||
 *
 | 
			
		||||
 *  #include <qse/cmn/map.h>
 | 
			
		||||
 ******
 | 
			
		||||
/**@file
 | 
			
		||||
 * A hash map maintains buckets for key/value pairs with the same key hash
 | 
			
		||||
 * chained under the same bucket.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* values that can be returned by qse_map_walker_t */
 | 
			
		||||
@ -49,29 +45,23 @@ typedef struct qse_map_pair_t qse_map_pair_t;
 | 
			
		||||
typedef enum qse_map_walk_t qse_map_walk_t;
 | 
			
		||||
typedef enum qse_map_id_t   qse_map_id_t;
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_copier_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_copier_t - define a pair contruction callback
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_copier_t type defines a pair contruction callback
 | 
			
		||||
 */
 | 
			
		||||
typedef void* (*qse_map_copier_t) (
 | 
			
		||||
	qse_map_t* map  /* a map */,
 | 
			
		||||
	void*      dptr /* the pointer to a key or a value */, 
 | 
			
		||||
	qse_size_t dlen /* the length of a key or a value */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_freeer_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_freeer_t - define a key/value destruction callback
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_freeer_t defines a key/value destruction callback
 | 
			
		||||
 */
 | 
			
		||||
typedef void (*qse_map_freeer_t) (
 | 
			
		||||
	qse_map_t* map  /* a map */,
 | 
			
		||||
	void*      dptr /* the pointer to a key or a value */, 
 | 
			
		||||
	qse_size_t dlen /* the length of a key or a value */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/* key hasher */
 | 
			
		||||
typedef qse_size_t (*qse_map_hasher_t) (
 | 
			
		||||
@ -80,108 +70,70 @@ typedef qse_size_t (*qse_map_hasher_t) (
 | 
			
		||||
	qse_size_t klen  /* the length of a key in bytes */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_comper_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_comper_t - define a key comparator
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_comper_t type defines a key comparator that is called when
 | 
			
		||||
 * the map needs to compare keys. A map is created with a default comparator
 | 
			
		||||
 * which performs bitwise comparison between two keys.
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  The qse_map_comper_t type defines a key comparator that is called when
 | 
			
		||||
 *  the map needs to compare keys. A map is created with a default comparator
 | 
			
		||||
 *  which performs bitwise comparison between two keys.
 | 
			
		||||
 *
 | 
			
		||||
 *  The comparator should return 0 if the keys are the same and a non-zero
 | 
			
		||||
 *  integer otherwise.
 | 
			
		||||
 *
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
 * The comparator should return 0 if the keys are the same and a non-zero
 | 
			
		||||
 * integer otherwise.
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*qse_map_comper_t) (
 | 
			
		||||
	qse_map_t*  map    /* a map */, 
 | 
			
		||||
	const void* kptr1  /* the pointer to a key */, 
 | 
			
		||||
	qse_size_t  klen1  /* the length of a key */, 
 | 
			
		||||
	const void* kptr2  /* the pointer to a key */, 
 | 
			
		||||
	qse_size_t  klen2  /* the length of a key */
 | 
			
		||||
	qse_map_t*  map,    /**< a map */ 
 | 
			
		||||
	const void* kptr1,  /**< the pointer to a key */
 | 
			
		||||
	qse_size_t  klen1,  /**< the length of a key */ 
 | 
			
		||||
	const void* kptr2,  /**< the pointer to a key */ 
 | 
			
		||||
	qse_size_t  klen2   /**< the length of a key */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_keeper_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_keeper_t - define a value keeper
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  The qse_map_keeper_t type defines a value keeper that is called when 
 | 
			
		||||
 *  a value is retained in the context that it should be destroyed because
 | 
			
		||||
 *  it is identical to a new value. Two values are identical if their beginning
 | 
			
		||||
 *  pointers and their lengths are equal.
 | 
			
		||||
 *
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_keeper_t type defines a value keeper that is called when 
 | 
			
		||||
 * a value is retained in the context that it should be destroyed because
 | 
			
		||||
 * it is identical to a new value. Two values are identical if their beginning
 | 
			
		||||
 * pointers and their lengths are equal.
 | 
			
		||||
 */
 | 
			
		||||
typedef void (*qse_map_keeper_t) (
 | 
			
		||||
	qse_map_t* map     /* a map */,
 | 
			
		||||
	void*      vptr    /* the pointer to a value */,
 | 
			
		||||
	qse_size_t vlen    /* the length of a value */	
 | 
			
		||||
	qse_map_t* map,    /**< a map */
 | 
			
		||||
	void*      vptr,   /**< value pointer */
 | 
			
		||||
	qse_size_t vlen    /**< value length */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_sizer_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_sizer_t - define a bucket size calculator
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  The qse_map_sizer_T type defines a bucket size claculator that is called
 | 
			
		||||
 *  when a map should resize the bucket. The current bucket size +1 is passed
 | 
			
		||||
 *  as the hint.
 | 
			
		||||
 * 
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_sizer_T type defines a bucket size claculator that is called
 | 
			
		||||
 * when a map should resize the bucket. The current bucket size +1 is passed
 | 
			
		||||
 * as the hint.
 | 
			
		||||
 */
 | 
			
		||||
typedef qse_size_t (*qse_map_sizer_t) (
 | 
			
		||||
	qse_map_t* map,  /* a map */
 | 
			
		||||
	qse_size_t hint  /* a sizing hint */
 | 
			
		||||
	qse_map_t* map,  /**< a map */
 | 
			
		||||
	qse_size_t hint  /**< a sizing hint */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****t* Common/qse_map_walker_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_walker_t - define a pair visitor
 | 
			
		||||
 *
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_walker_t defines a pair visitor.
 | 
			
		||||
 */
 | 
			
		||||
typedef qse_map_walk_t (*qse_map_walker_t) (
 | 
			
		||||
	qse_map_t*      map   /* a map */, 
 | 
			
		||||
	qse_map_pair_t* pair  /* the pointer to a key/value pair */, 
 | 
			
		||||
	void*           arg   /* the pointer to user-defined data */
 | 
			
		||||
	qse_map_t*      map,   /**< a map */
 | 
			
		||||
	qse_map_pair_t* pair,  /**< the pointer to a key/value pair */
 | 
			
		||||
	void*           arg    /**< the pointer to user-defined data */
 | 
			
		||||
);
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
/****s* Common/qse_map_pair_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_pair_t - define a pair
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *  A pair is composed of a key and a value. It maintains pointers to the 
 | 
			
		||||
 *  beginning of a key and a value plus their length. The length is scaled
 | 
			
		||||
 *  down with the scale factor specified in an owning map. Use macros defined
 | 
			
		||||
 *  in the SEE ALSO section below to access individual fields.
 | 
			
		||||
 *
 | 
			
		||||
 * SEE ALSO
 | 
			
		||||
 *  QSE_MAP_KPTR, QSE_MAP_KLEN, QSE_MAP_VPTR, QSE_MAP_VLEN
 | 
			
		||||
 *
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_pair_t type defines a map pair. A pair is composed of a key
 | 
			
		||||
 * and a value. It maintains pointers to the beginning of a key and a value
 | 
			
		||||
 * plus their length. The length is scaled down with the scale factor 
 | 
			
		||||
 * specified in an owning map. Use macros defined in the 
 | 
			
		||||
 */
 | 
			
		||||
struct qse_map_pair_t
 | 
			
		||||
{
 | 
			
		||||
	void*           kptr;  /* the pointer to a key */
 | 
			
		||||
	qse_size_t      klen;  /* the length of a key */
 | 
			
		||||
	void*           vptr;  /* the pointer to a value */
 | 
			
		||||
	qse_size_t      vlen;  /* the length of a value */
 | 
			
		||||
	qse_map_pair_t* next;  /* the next pair under the same slot */
 | 
			
		||||
	void*           kptr;  /**< the pointer to a key */
 | 
			
		||||
	qse_size_t      klen;  /**< the length of a key */
 | 
			
		||||
	void*           vptr;  /**< the pointer to a value */
 | 
			
		||||
	qse_size_t      vlen;  /**< the length of a value */
 | 
			
		||||
	qse_map_pair_t* next;  /**< the next pair under the same slot */
 | 
			
		||||
};
 | 
			
		||||
/*****/
 | 
			
		||||
 | 
			
		||||
/****s* Common/qse_map_t
 | 
			
		||||
 * NAME
 | 
			
		||||
 *  qse_map_t - define a hash map
 | 
			
		||||
 *
 | 
			
		||||
 * SYNOPSIS
 | 
			
		||||
/**
 | 
			
		||||
 * The qse_map_t type defines a hash map.
 | 
			
		||||
 */
 | 
			
		||||
struct qse_map_t
 | 
			
		||||
{
 | 
			
		||||
@ -201,7 +153,6 @@ struct qse_map_t
 | 
			
		||||
	qse_size_t       threshold;
 | 
			
		||||
	qse_map_pair_t** bucket;
 | 
			
		||||
};
 | 
			
		||||
/******/
 | 
			
		||||
 | 
			
		||||
#define QSE_MAP_COPIER_SIMPLE ((qse_map_copier_t)1)
 | 
			
		||||
#define QSE_MAP_COPIER_INLINE ((qse_map_copier_t)2)
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: err.c 199 2009-06-14 08:40:52Z hyunghwan.chung $
 | 
			
		||||
 * $Id: err.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -88,6 +88,7 @@ const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum)
 | 
			
		||||
		QSE_T("END not followed by a left bracket on the same line"),
 | 
			
		||||
		QSE_T("duplicate BEGIN"),
 | 
			
		||||
		QSE_T("duplicate END"),
 | 
			
		||||
		QSE_T("keyword '${0}' redefined"),
 | 
			
		||||
		QSE_T("intrinsic function '${0}' redefined"),
 | 
			
		||||
		QSE_T("function '${0}' redefined"),
 | 
			
		||||
		QSE_T("global variable '${0}' redefined"),
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: parse.c 204 2009-06-18 12:08:06Z hyunghwan.chung $
 | 
			
		||||
 * $Id: parse.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -1403,12 +1403,10 @@ static void adjust_static_globals (qse_awk_t* awk)
 | 
			
		||||
		if (gtab[id].valid != 0 && 
 | 
			
		||||
		    (awk->option & gtab[id].valid) != gtab[id].valid)
 | 
			
		||||
		{
 | 
			
		||||
			/*awk->parse.gbls.buf[id].name.len = 0;*/
 | 
			
		||||
			QSE_LDA_DLEN(awk->parse.gbls,id) = 0;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/*awk->parse.gbls.buf[id].name.len = gtab[id].name_len;*/
 | 
			
		||||
			QSE_LDA_DLEN(awk->parse.gbls,id) = gtab[id].name_len;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@ -1487,6 +1485,15 @@ static int add_global (
 | 
			
		||||
{
 | 
			
		||||
	qse_size_t ngbls;
 | 
			
		||||
 | 
			
		||||
	/* check if it is a keyword */
 | 
			
		||||
	if (classify_ident (awk, name, len) != TOKEN_IDENT)
 | 
			
		||||
	{
 | 
			
		||||
		SETERRARG (
 | 
			
		||||
			awk, QSE_AWK_EKWRED, awk->token.line,
 | 
			
		||||
			name, len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* check if it conflict with a builtin function name */
 | 
			
		||||
	if (qse_awk_getfnc (awk, name, len) != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
@ -1563,14 +1570,14 @@ int qse_awk_addgbl (
 | 
			
		||||
 | 
			
		||||
	if (awk->tree.ngbls > awk->tree.ngbls_base) 
 | 
			
		||||
	{
 | 
			
		||||
		/* this function is not allow after qse_awk_parse is called */
 | 
			
		||||
		/* this function is not allowed after qse_awk_parse is called */
 | 
			
		||||
		SETERR (awk, QSE_AWK_ENOPER);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n = add_global (awk, name, len, 0, 0);
 | 
			
		||||
 | 
			
		||||
	/* update the count of the static gbls. 
 | 
			
		||||
	/* update the count of the static globals. 
 | 
			
		||||
	 * the total global count has been updated inside add_global. */
 | 
			
		||||
	if (n >= 0) awk->tree.ngbls_base++; 
 | 
			
		||||
 | 
			
		||||
@ -4662,7 +4669,7 @@ static int get_token (qse_awk_t* awk)
 | 
			
		||||
		}
 | 
			
		||||
		*/
 | 
			
		||||
	}
 | 
			
		||||
	else if (QSE_AWK_ISALPHA (awk, c) || c == QSE_T('_')) 
 | 
			
		||||
	else if (c == QSE_T('_') || QSE_AWK_ISALPHA (awk, c))
 | 
			
		||||
	{
 | 
			
		||||
		int type;
 | 
			
		||||
 | 
			
		||||
@ -4672,8 +4679,9 @@ static int get_token (qse_awk_t* awk)
 | 
			
		||||
			ADD_TOKEN_CHAR (awk, c);
 | 
			
		||||
			GET_CHAR_TO (awk, c);
 | 
			
		||||
		} 
 | 
			
		||||
		while (QSE_AWK_ISALPHA (awk, c) || 
 | 
			
		||||
		       c == QSE_T('_') || QSE_AWK_ISDIGIT(awk,c));
 | 
			
		||||
		while (c == QSE_T('_') || 
 | 
			
		||||
		       QSE_AWK_ISALPHA (awk, c) || 
 | 
			
		||||
		       QSE_AWK_ISDIGIT (awk, c));
 | 
			
		||||
 | 
			
		||||
		type = classify_ident (awk, 
 | 
			
		||||
			QSE_STR_PTR(awk->token.name), 
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: rec.c 200 2009-06-14 13:22:00Z hyunghwan.chung $
 | 
			
		||||
 * $Id: rec.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -31,10 +31,6 @@ int qse_awk_rtx_setrec (
 | 
			
		||||
 | 
			
		||||
	if (idx == 0)
 | 
			
		||||
	{
 | 
			
		||||
		qse_long_t l;
 | 
			
		||||
		qse_real_t r;
 | 
			
		||||
		int x;
 | 
			
		||||
 | 
			
		||||
		if (str == QSE_STR_PTR(&run->inrec.line) &&
 | 
			
		||||
		    len == QSE_STR_LEN(&run->inrec.line))
 | 
			
		||||
		{
 | 
			
		||||
@ -53,8 +49,7 @@ int qse_awk_rtx_setrec (
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		x = qse_awk_rtx_strtonum (run, 1, str, len, &l, &r);
 | 
			
		||||
		v = qse_awk_rtx_makestrval (run, str, len);
 | 
			
		||||
		v = qse_awk_rtx_makenstrval (run, str, len);
 | 
			
		||||
 | 
			
		||||
		if (v == QSE_NULL)
 | 
			
		||||
		{
 | 
			
		||||
@ -62,14 +57,6 @@ int qse_awk_rtx_setrec (
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (x >= 0) 
 | 
			
		||||
		{
 | 
			
		||||
			/* set the numeric string flag if a string
 | 
			
		||||
			 * can be converted to a number */
 | 
			
		||||
			QSE_ASSERT (x == 0 || x == 1);
 | 
			
		||||
			v->nstr = x + 1; /* long -> 1, real -> 2 */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		QSE_ASSERT (run->inrec.d0->type == QSE_AWK_VAL_NIL);
 | 
			
		||||
		/* d0 should be cleared before the next line is reached
 | 
			
		||||
		 * as it doesn't call qse_awk_rtx_refdownval on run->inrec.d0 */
 | 
			
		||||
@ -215,10 +202,6 @@ static int split_record (qse_awk_rtx_t* run)
 | 
			
		||||
 | 
			
		||||
	while (p != QSE_NULL)
 | 
			
		||||
	{
 | 
			
		||||
		qse_long_t l;
 | 
			
		||||
		qse_real_t r;
 | 
			
		||||
		int x;
 | 
			
		||||
 | 
			
		||||
		if (fs_len <= 1)
 | 
			
		||||
		{
 | 
			
		||||
			p = qse_awk_rtx_strxntok (
 | 
			
		||||
@ -247,25 +230,18 @@ static int split_record (qse_awk_rtx_t* run)
 | 
			
		||||
		run->inrec.flds[run->inrec.nflds].ptr = tok;
 | 
			
		||||
		run->inrec.flds[run->inrec.nflds].len = tok_len;
 | 
			
		||||
 | 
			
		||||
		x = qse_awk_rtx_strtonum (run, 1, tok, tok_len, &l, &r);
 | 
			
		||||
		run->inrec.flds[run->inrec.nflds].val =
 | 
			
		||||
			qse_awk_rtx_makestrval (run, tok, tok_len);
 | 
			
		||||
			qse_awk_rtx_makenstrval (run, tok, tok_len);
 | 
			
		||||
 | 
			
		||||
		if (run->inrec.flds[run->inrec.nflds].val == QSE_NULL)
 | 
			
		||||
		{
 | 
			
		||||
			if (fs_free != QSE_NULL) QSE_AWK_FREE (run->awk, fs_free);
 | 
			
		||||
			if (fs_free != QSE_NULL) 
 | 
			
		||||
				QSE_AWK_FREE (run->awk, fs_free);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (x >= 0)
 | 
			
		||||
		{
 | 
			
		||||
			/* set the numeric string flags if a string
 | 
			
		||||
			 * can be converted to a number */
 | 
			
		||||
			QSE_ASSERT (x == 0 || x == 1);
 | 
			
		||||
			run->inrec.flds[run->inrec.nflds].val->nstr = x + 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		qse_awk_rtx_refupval (run, run->inrec.flds[run->inrec.nflds].val);
 | 
			
		||||
		qse_awk_rtx_refupval (
 | 
			
		||||
			run, run->inrec.flds[run->inrec.nflds].val);
 | 
			
		||||
		run->inrec.nflds++;
 | 
			
		||||
 | 
			
		||||
		len = QSE_STR_LEN(&run->inrec.line) - 
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: std.c 204 2009-06-18 12:08:06Z hyunghwan.chung $
 | 
			
		||||
 * $Id: std.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -599,6 +599,7 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
 | 
			
		||||
			qse_sio_t* sio;
 | 
			
		||||
			const qse_char_t* file;
 | 
			
		||||
 | 
			
		||||
		retry:
 | 
			
		||||
			file = rxtn->c.in.files[rxtn->c.in.index];
 | 
			
		||||
 | 
			
		||||
			if (file == QSE_NULL)
 | 
			
		||||
@ -726,6 +727,7 @@ static qse_ssize_t awk_rio_console (
 | 
			
		||||
			qse_sio_t* sio;
 | 
			
		||||
			const qse_char_t* file;
 | 
			
		||||
 | 
			
		||||
		retry:
 | 
			
		||||
			/* it has reached the end of the current file.
 | 
			
		||||
			 * open the next file if available */
 | 
			
		||||
			if (rxtn->c.in.files == QSE_NULL ||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id: val.c 200 2009-06-14 13:22:00Z hyunghwan.chung $
 | 
			
		||||
 * $Id: val.c 205 2009-06-20 12:47:34Z hyunghwan.chung $
 | 
			
		||||
 *
 | 
			
		||||
   Copyright 2006-2009 Chung, Hyung-Hwan.
 | 
			
		||||
 | 
			
		||||
@ -348,6 +348,30 @@ init:
 | 
			
		||||
	return (qse_awk_val_t*)val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qse_awk_val_t* qse_awk_rtx_makenstrval (
 | 
			
		||||
	qse_awk_rtx_t* run, const qse_char_t* str, qse_size_t len)
 | 
			
		||||
{
 | 
			
		||||
	int x;
 | 
			
		||||
	qse_awk_val_t* v;
 | 
			
		||||
	qse_long_t l;
 | 
			
		||||
	qse_real_t r;
 | 
			
		||||
 | 
			
		||||
	x = qse_awk_rtx_strtonum (run, 1, str, len, &l, &r);
 | 
			
		||||
	v = qse_awk_rtx_makestrval (run, str, len);
 | 
			
		||||
 | 
			
		||||
	if (v == QSE_NULL) return QSE_NULL;
 | 
			
		||||
 | 
			
		||||
	if (x >= 0) 
 | 
			
		||||
	{
 | 
			
		||||
		/* set the numeric string flag if a string
 | 
			
		||||
		 * can be converted to a number */
 | 
			
		||||
		QSE_ASSERT (x == 0 || x == 1);
 | 
			
		||||
		v->nstr = x + 1; /* long -> 1, real -> 2 */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
qse_awk_val_t* qse_awk_rtx_makerexval (
 | 
			
		||||
	qse_awk_rtx_t* run, const qse_char_t* buf, qse_size_t len, void* code)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user