-added Awk::Value::getFirstIndex() & Awk::Value::getNextIndex()

-fixed a few bugs in the Awk::Value class
This commit is contained in:
2009-07-14 02:51:23 +00:00
parent 814ed89e53
commit 9b6eb94664
11 changed files with 1077 additions and 730 deletions

View File

@ -11,13 +11,15 @@ awk03_SOURCES = awk03.c
awk04_SOURCES = awk04.c
if ENABLE_CXX
bin_PROGRAMS += awk05 awk06 awk07
bin_PROGRAMS += awk05 awk06 awk07 awk08
awk05_SOURCES = awk05.cpp
awk06_SOURCES = awk06.cpp
awk07_SOURCES = awk07.cpp
awk08_SOURCES = awk08.cpp
awk05_LDADD = -lqseawk++ $(LDADD)
awk06_LDADD = -lqseawk++ $(LDADD)
awk07_LDADD = -lqseawk++ $(LDADD)
awk08_LDADD = -lqseawk++ $(LDADD)
endif

View File

@ -34,7 +34,7 @@ build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = awk01$(EXEEXT) awk02$(EXEEXT) awk03$(EXEEXT) \
awk04$(EXEEXT) $(am__EXEEXT_1)
@ENABLE_CXX_TRUE@am__append_1 = awk05 awk06 awk07
@ENABLE_CXX_TRUE@am__append_1 = awk05 awk06 awk07 awk08
subdir = samples/awk
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -49,7 +49,7 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/qse/config.h
CONFIG_CLEAN_FILES =
@ENABLE_CXX_TRUE@am__EXEEXT_1 = awk05$(EXEEXT) awk06$(EXEEXT) \
@ENABLE_CXX_TRUE@ awk07$(EXEEXT)
@ENABLE_CXX_TRUE@ awk07$(EXEEXT) awk08$(EXEEXT)
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
@ -83,6 +83,10 @@ am__awk07_SOURCES_DIST = awk07.cpp
@ENABLE_CXX_TRUE@am_awk07_OBJECTS = awk07.$(OBJEXT)
awk07_OBJECTS = $(am_awk07_OBJECTS)
@ENABLE_CXX_TRUE@awk07_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__awk08_SOURCES_DIST = awk08.cpp
@ENABLE_CXX_TRUE@am_awk08_OBJECTS = awk08.$(OBJEXT)
awk08_OBJECTS = $(am_awk08_OBJECTS)
@ENABLE_CXX_TRUE@awk08_DEPENDENCIES = $(am__DEPENDENCIES_2)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/qse
depcomp = $(SHELL) $(top_srcdir)/ac/au/depcomp
am__depfiles_maybe = depfiles
@ -106,10 +110,11 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \
$(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \
$(awk07_SOURCES)
$(awk07_SOURCES) $(awk08_SOURCES)
DIST_SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \
$(awk04_SOURCES) $(am__awk05_SOURCES_DIST) \
$(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST)
$(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST) \
$(am__awk08_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -258,9 +263,11 @@ awk04_SOURCES = awk04.c
@ENABLE_CXX_TRUE@awk05_SOURCES = awk05.cpp
@ENABLE_CXX_TRUE@awk06_SOURCES = awk06.cpp
@ENABLE_CXX_TRUE@awk07_SOURCES = awk07.cpp
@ENABLE_CXX_TRUE@awk08_SOURCES = awk08.cpp
@ENABLE_CXX_TRUE@awk05_LDADD = -lqseawk++ $(LDADD)
@ENABLE_CXX_TRUE@awk06_LDADD = -lqseawk++ $(LDADD)
@ENABLE_CXX_TRUE@awk07_LDADD = -lqseawk++ $(LDADD)
@ENABLE_CXX_TRUE@awk08_LDADD = -lqseawk++ $(LDADD)
all: all-am
.SUFFIXES:
@ -343,6 +350,9 @@ awk06$(EXEEXT): $(awk06_OBJECTS) $(awk06_DEPENDENCIES)
awk07$(EXEEXT): $(awk07_OBJECTS) $(awk07_DEPENDENCIES)
@rm -f awk07$(EXEEXT)
$(CXXLINK) $(awk07_OBJECTS) $(awk07_LDADD) $(LIBS)
awk08$(EXEEXT): $(awk08_OBJECTS) $(awk08_DEPENDENCIES)
@rm -f awk08$(EXEEXT)
$(CXXLINK) $(awk08_OBJECTS) $(awk08_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -357,6 +367,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk05.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk06.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk07.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk08.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -17,652 +17,103 @@
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/str.h>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <stdlib.h>
#include <math.h>
#if defined(_WIN32)
# include <windows.h>
#else
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
class MyAwk;
#ifdef _WIN32
static BOOL WINAPI stop_run (DWORD ctrl_type);
#else
static void stop_run (int sig);
#endif
static void set_intr_run (void);
static void unset_intr_run (void);
MyAwk* app_awk = QSE_NULL;
static bool verbose = false;
class MyAwk: public QSE::StdAwk
static void print_error (unsigned long line, const qse_char_t* msg)
{
public:
MyAwk (): srcInName(QSE_NULL), srcOutName(QSE_NULL)
{
#ifdef _WIN32
heap = QSE_NULL;
#endif
}
~MyAwk ()
{
close ();
}
int open ()
{
#ifdef _WIN32
QSE_ASSERT (heap == QSE_NULL);
heap = ::HeapCreate (0, 1000000, 1000000);
if (heap == QSE_NULL) return -1;
#endif
int n = StdAwk::open ();
if (n <= -1)
{
#ifdef _WIN32
HeapDestroy (heap);
heap = QSE_NULL;
#endif
return -1;
}
idLastSleep = addGlobal (QSE_T("LAST_SLEEP"));
if (idLastSleep <= -1) goto failure;
if (addFunction (QSE_T("sleep"), 1, 1,
(FunctionHandler)&MyAwk::sleep) <= -1) goto failure;
if (addFunction (QSE_T("sumintarray"), 1, 1,
(FunctionHandler)&MyAwk::sumintarray) <= -1) goto failure;
if (addFunction (QSE_T("arrayindices"), 1, 1,
(FunctionHandler)&MyAwk::arrayindices) <= -1) goto failure;
return 0;
failure:
StdAwk::close ();
#ifdef _WIN32
HeapDestroy (heap);
heap = QSE_NULL;
#endif
return -1;
}
void close ()
{
StdAwk::close ();
#ifdef _WIN32
if (heap != QSE_NULL)
{
HeapDestroy (heap);
heap = QSE_NULL;
}
#endif
}
int sleep (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
if (args[0].isIndexed())
{
run.setError (ERR_INVAL);
return -1;
}
long_t x = args[0].toInt();
/*Argument arg;
if (run.getGlobal(idLastSleep, arg) == 0)
qse_printf (QSE_T("GOOD: [%d]\n"), (int)arg.toInt());
else { qse_printf (QSE_T("BAD:\n")); }
*/
if (run.setGlobal (idLastSleep, x) <= -1) return -1;
#ifdef _WIN32
::Sleep ((DWORD)(x * 1000));
return ret.set ((long_t)0);
#else
return ret.set ((long_t)::sleep (x));
#endif
}
int sumintarray (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
long_t x = 0;
if (args[0].isIndexed())
{
Argument idx(run), val(run);
int n = args[0].getFirstIndex (idx);
while (n > 0)
{
size_t len;
const char_t* ptr = idx.toStr(&len);
if (args[0].getIndexed(ptr, len, val) <= -1) return -1;
x += val.toInt ();
n = args[0].getNextIndex (idx);
}
if (n != 0) return -1;
}
else x += args[0].toInt();
return ret.set (x);
}
int arrayindices (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
if (!args[0].isIndexed()) return 0;
Argument idx (run);
long_t i;
int n = args[0].getFirstIndex (idx);
for (i = 0; n > 0; i++)
{
size_t len;
const char_t* ptr = idx.toStr(&len);
n = args[0].getNextIndex (idx);
if (ret.setIndexed (i, ptr, len) <= -1) return -1;
}
if (n != 0) return -1;
return 0;
}
Run* parse (const char_t* in, const char_t* out)
{
srcInName = in;
srcOutName = out;
return StdAwk::parse ();
}
protected:
bool onLoopEnter (Run& run)
{
set_intr_run ();
return true;
}
void onLoopExit (Run& run, const Argument& ret)
{
unset_intr_run ();
if (verbose)
{
size_t len;
const char_t* ptr = ret.toStr (&len);
qse_printf (QSE_T("*** return [%.*s] ***\n"), (int)len, ptr);
}
}
int openSource (Source& io)
{
Source::Mode mode = io.getMode();
FILE* fp = QSE_NULL;
// TODO: use sio instead of stdio
if (mode == Source::READ)
{
if (srcInName == QSE_NULL)
{
io.setHandle (stdin);
return 0;
}
if (srcInName[0] == QSE_T('\0')) fp = stdin;
else fp = qse_fopen (srcInName, QSE_T("r"));
}
else if (mode == Source::WRITE)
{
if (srcOutName == QSE_NULL)
{
io.setHandle (stdout);
return 0;
}
if (srcOutName[0] == QSE_T('\0')) fp = stdout;
else fp = qse_fopen (srcOutName, QSE_T("w"));
}
if (fp == QSE_NULL) return -1;
io.setHandle (fp);
return 1;
}
int closeSource (Source& io)
{
FILE* fp = (FILE*)io.getHandle();
if (fp == stdout || fp == stderr) fflush (fp);
if (fp != stdin && fp != stdout && fp != stderr) fclose (fp);
io.setHandle (QSE_NULL);
return 0;
}
ssize_t readSource (Source& io, char_t* buf, size_t len)
{
FILE* fp = (FILE*)io.getHandle();
ssize_t n = 0;
while (n < (ssize_t)len)
{
qse_cint_t c = qse_fgetc (fp);
if (c == QSE_CHAR_EOF)
{
if (qse_ferror(fp)) n = -1;
break;
}
buf[n++] = c;
if (c == QSE_T('\n')) break;
}
return n;
}
ssize_t writeSource (Source& io, char_t* buf, size_t len)
{
FILE* fp = (FILE*)io.getHandle();
size_t left = len;
while (left > 0)
{
if (*buf == QSE_T('\0'))
{
if (qse_fputc(*buf,fp) == QSE_CHAR_EOF) return -1;
left -= 1; buf += 1;
}
else
{
int chunk = (left > QSE_TYPE_MAX(int))? QSE_TYPE_MAX(int): (int)left;
int n = qse_fprintf (fp, QSE_T("%.*s"), chunk, buf);
if (n < 0 || n > chunk) return -1;
left -= n; buf += n;
}
}
return len;
}
void* allocMem (size_t n) throw ()
{
#ifdef _WIN32
return ::HeapAlloc (heap, 0, n);
#else
return ::malloc (n);
#endif
}
void* reallocMem (void* ptr, size_t n) throw ()
{
#ifdef _WIN32
if (ptr == NULL)
return ::HeapAlloc (heap, 0, n);
else
return ::HeapReAlloc (heap, 0, ptr, n);
#else
return ::realloc (ptr, n);
#endif
}
void freeMem (void* ptr) throw ()
{
#ifdef _WIN32
::HeapFree (heap, 0, ptr);
#else
::free (ptr);
#endif
}
private:
const char_t* srcInName;
const char_t* srcOutName;
int idLastSleep;
#ifdef _WIN32
void* heap;
#endif
};
#ifdef _WIN32
static BOOL WINAPI stop_run (DWORD ctrl_type)
{
if (ctrl_type == CTRL_C_EVENT ||
ctrl_type == CTRL_CLOSE_EVENT)
{
if (app_awk) app_awk->stop ();
return TRUE;
}
return FALSE;
}
#else
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)
{
#ifdef SA_RESTART
sa_int.sa_flags |= SA_RESTART;
#endif
}
if (line > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu\n"), msg, line);
else
{
#ifdef SA_INTERRUPT
sa_int.sa_flags |= SA_INTERRUPT;
#endif
}
return sigaction (sig, &sa_int, NULL);
}
static void stop_run (int sig)
{
int e = errno;
if (app_awk) app_awk->stop ();
errno = e;
}
#endif
static void set_intr_run (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, TRUE);
#else
/*setsignal (SIGINT, stop_run, 1); TO BE MORE COMPATIBLE WITH WIN32*/
setsignal (SIGINT, stop_run, 0);
#endif
}
static void unset_intr_run (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, FALSE);
#else
setsignal (SIGINT, SIG_DFL, 1);
#endif
}
static void print_error (const qse_char_t* msg)
{
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
static struct
{
const qse_char_t* name;
MyAwk::Option opt;
} otab[] =
{
{ QSE_T("implicit"), MyAwk::OPT_IMPLICIT },
{ QSE_T("explicit"), MyAwk::OPT_EXPLICIT },
{ QSE_T("bxor"), MyAwk::OPT_BXOR },
{ QSE_T("shift"), MyAwk::OPT_SHIFT },
{ QSE_T("idiv"), MyAwk::OPT_IDIV },
{ QSE_T("rio"), MyAwk::OPT_RIO },
{ QSE_T("rwpipe"), MyAwk::OPT_RWPIPE },
{ QSE_T("newline"), MyAwk::OPT_NEWLINE },
{ QSE_T("stripspaces"), MyAwk::OPT_STRIPSPACES },
{ QSE_T("nextofile"), MyAwk::OPT_NEXTOFILE },
{ QSE_T("crlf"), MyAwk::OPT_CRLF },
{ QSE_T("reset"), MyAwk::OPT_RESET },
{ QSE_T("maptovar"), MyAwk::OPT_MAPTOVAR },
{ QSE_T("pablock"), MyAwk::OPT_PABLOCK }
};
static void print_usage (const qse_char_t* argv0)
{
const qse_char_t* base;
int j;
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
base = qse_strrchr(argv0, QSE_T('/'));
if (base == QSE_NULL) base = qse_strrchr(argv0, QSE_T('\\'));
if (base == QSE_NULL) base = argv0; else base++;
}
qse_printf (QSE_T("Usage: %s [-si file]? [-so file]? [-ci file]* [-co file]* [-w o:n]* \n"), base);
qse_printf (QSE_T(" -si file Specify the input source file\n"));
qse_printf (QSE_T(" The source code is read from stdin when it is not specified\n"));
qse_printf (QSE_T(" -so file Specify the output source file\n"));
qse_printf (QSE_T(" The deparsed code is not output when is it not specified\n"));
qse_printf (QSE_T(" -ci file Specify the input console file\n"));
qse_printf (QSE_T(" -co file Specify the output console file\n"));
qse_printf (QSE_T(" -w o:n Specify an old and new word pair\n"));
qse_printf (QSE_T(" o - an original word\n"));
qse_printf (QSE_T(" n - the new word to replace the original\n"));
qse_printf (QSE_T(" -v Print extra messages\n"));
static int run_awk (QSE::StdAwk& awk)
{
QSE::StdAwk::Run* run;
const qse_char_t* script = QSE_T(
"function pa (x) {\n"
" reset ret;\n"
" for (i in x) { print i, \"=>\", x[i]; ret += x[i]; }\n"
" return ret;\n"
"}\n"
"function pb (x) {\n"
" reset ret;\n"
" for (i in x) { ret[-i] = -x[i]; }\n"
" return ret;\n"
"}"
);
qse_printf (QSE_T("\nYou may specify the following options to change the behavior of the interpreter.\n"));
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
QSE::StdAwk::SourceString in (script);
QSE::StdAwk::SourceFile out (QSE_T("awk07.out"));
// parse the script and deparse it to awk07.out
run = awk.parse (&in, &out);
if (run == QSE_NULL) return -1;
QSE::StdAwk::Value arg[1];
for (int i = 1; i <= 5; i++)
{
qse_printf (QSE_T(" -%-20s -no%-20s\n"), otab[j].name, otab[j].name);
if (arg[0].setIndexedInt (
run, QSE::StdAwk::Value::IntIndex(i), i*20) <= -1) return -1;
}
QSE::StdAwk::Value r;
// call the 'pa' function
if (awk.call (QSE_T("pa"), &r, arg, QSE_COUNTOF(arg)) <= -1) return -1;
// output the result in various types
qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)r.toInt());
qse_printf (QSE_T(" (real) [%Lf]\n"), (long double)r.toReal());
qse_printf (QSE_T(" (str) [%s]\n"), r.toStr(QSE_NULL));
// call the 'pb' function
if (awk.call (QSE_T("pb"), &r, arg, QSE_COUNTOF(arg)) <= -1) return -1;
// output the returned map.
QSE_ASSERT (r.isIndexed());
QSE::StdAwk::Value::IndexIterator iter;
QSE::StdAwk::Value::Index idx;
QSE::StdAwk::Value v;
qse_printf (QSE_T("RESULT:\n"));
iter = r.getFirstIndex (&idx);
while (iter != QSE::StdAwk::Value::IndexIterator::END)
{
if (r.getIndexed (idx, &v) <= -1) return -1;
qse_printf (QSE_T("\t[%.*s]=>[%lld]\n"),
(int)idx.len, idx.ptr, (long long)v.toInt());
iter = r.getNextIndex (&idx, iter);
}
return 0;
}
static int awk_main (int argc, qse_char_t* argv[])
{
MyAwk awk;
MyAwk::Run* run;
QSE::StdAwk awk;
int mode = 0;
const qse_char_t* srcin = QSE_T("");
const qse_char_t* srcout = NULL;
qse_size_t nsrcins = 0;
qse_size_t nsrcouts = 0;
int ret = awk.open();
if (awk.open() <= -1)
{
print_error (awk.getErrorMessage());
return -1;
}
// allow returning a map from a function and enable 'reset'
awk.setOption (
awk.getOption() |
QSE::StdAwk::OPT_MAPTOVAR |
QSE::StdAwk::OPT_RESET);
// ARGV[0]
if (awk.addArgument (QSE_T("awk05")) <= -1)
{
print_error (awk.getErrorMessage());
awk.close ();
return -1;
}
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1) print_error (awk.getErrorLine(), awk.getErrorMessage());
for (int i = 1; i < argc; i++)
{
if (mode == 0)
{
if (qse_strcmp(argv[i], QSE_T("-si")) == 0) mode = 1;
else if (qse_strcmp(argv[i], QSE_T("-so")) == 0) mode = 2;
else if (qse_strcmp(argv[i], QSE_T("-ci")) == 0) mode = 3;
else if (qse_strcmp(argv[i], QSE_T("-co")) == 0) mode = 4;
else if (qse_strcmp(argv[i], QSE_T("-w")) == 0) mode = 5;
else if (qse_strcmp(argv[i], QSE_T("-v")) == 0)
{
verbose = true;
}
else
{
if (argv[i][0] == QSE_T('-'))
{
int j;
if (argv[i][1] == QSE_T('n') && argv[i][2] == QSE_T('o'))
{
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
{
if (qse_strcmp(&argv[i][3], otab[j].name) == 0)
{
awk.setOption (awk.getOption() & ~otab[j].opt);
goto ok_valid;
}
}
}
else
{
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
{
if (qse_strcmp(&argv[i][1], otab[j].name) == 0)
{
awk.setOption (awk.getOption() | otab[j].opt);
goto ok_valid;
}
}
}
}
print_usage (argv[0]);
return -1;
ok_valid:
;
}
}
else
{
if (argv[i][0] == QSE_T('-'))
{
print_usage (argv[0]);
return -1;
}
if (mode == 1) // source input
{
if (nsrcins != 0)
{
print_usage (argv[0]);
return -1;
}
srcin = argv[i];
nsrcins++;
mode = 0;
}
else if (mode == 2) // source output
{
if (nsrcouts != 0)
{
print_usage (argv[0]);
return -1;
}
srcout = argv[i];
nsrcouts++;
mode = 0;
}
else if (mode == 3) // console input
{
if (awk.addArgument (argv[i]) <= -1)
{
print_error (QSE_T("too many console inputs"));
return -1;
}
mode = 0;
}
else if (mode == 4) // console output
{
if (awk.addConsoleOutput (argv[i]) <= -1)
{
print_error (QSE_T("too many console outputs"));
return -1;
}
mode = 0;
}
else if (mode == 5) // word replacement
{
const qse_char_t* p;
qse_size_t l;
p = qse_strchr(argv[i], QSE_T(':'));
if (p == QSE_NULL)
{
print_usage (argv[0]);
return -1;
}
l = qse_strlen (argv[i]);
awk.setWord (
argv[i], p - argv[i],
p + 1, l - (p - argv[i] + 1));
mode = 0;
}
}
}
if (mode != 0)
{
print_usage (argv[0]);
awk.close ();
return -1;
}
run = awk.parse (srcin, srcout);
if (run == QSE_NULL)
{
qse_fprintf (stderr, QSE_T("cannot parse: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
awk.enableRunCallback ();
app_awk = &awk;
if (awk.loop () <= -1)
{
qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
#if 0
MyAwk::Return args[2];
args[0].setRun (run);
args[1].setRun (run);
if (awk.call (QSE_T("add"), args, 2) <= -1)
{
qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
}
#endif
app_awk = QSE_NULL;
awk.close ();
return 0;
return -1;
}
int qse_main (int argc, qse_achar_t* argv[])

671
qse/samples/awk/awk08.cpp Normal file
View File

@ -0,0 +1,671 @@
/*
* $Id: Awk.cpp 341 2008-08-20 10:58:19Z baconevi $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/str.h>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <stdlib.h>
#include <math.h>
#if defined(_WIN32)
# include <windows.h>
#else
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
class MyAwk;
#ifdef _WIN32
static BOOL WINAPI stop_run (DWORD ctrl_type);
#else
static void stop_run (int sig);
#endif
static void set_intr_run (void);
static void unset_intr_run (void);
MyAwk* app_awk = QSE_NULL;
static bool verbose = false;
class MyAwk: public QSE::StdAwk
{
public:
MyAwk (): srcInName(QSE_NULL), srcOutName(QSE_NULL)
{
#ifdef _WIN32
heap = QSE_NULL;
#endif
}
~MyAwk ()
{
close ();
}
int open ()
{
#ifdef _WIN32
QSE_ASSERT (heap == QSE_NULL);
heap = ::HeapCreate (0, 1000000, 1000000);
if (heap == QSE_NULL) return -1;
#endif
int n = StdAwk::open ();
if (n <= -1)
{
#ifdef _WIN32
HeapDestroy (heap);
heap = QSE_NULL;
#endif
return -1;
}
idLastSleep = addGlobal (QSE_T("LAST_SLEEP"));
if (idLastSleep <= -1) goto failure;
if (addFunction (QSE_T("sleep"), 1, 1,
(FunctionHandler)&MyAwk::sleep) <= -1) goto failure;
if (addFunction (QSE_T("sumintarray"), 1, 1,
(FunctionHandler)&MyAwk::sumintarray) <= -1) goto failure;
if (addFunction (QSE_T("arrayindices"), 1, 1,
(FunctionHandler)&MyAwk::arrayindices) <= -1) goto failure;
return 0;
failure:
StdAwk::close ();
#ifdef _WIN32
HeapDestroy (heap);
heap = QSE_NULL;
#endif
return -1;
}
void close ()
{
StdAwk::close ();
#ifdef _WIN32
if (heap != QSE_NULL)
{
HeapDestroy (heap);
heap = QSE_NULL;
}
#endif
}
int sleep (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
if (args[0].isIndexed())
{
run.setError (ERR_INVAL);
return -1;
}
long_t x = args[0].toInt();
/*Argument arg;
if (run.getGlobal(idLastSleep, arg) == 0)
qse_printf (QSE_T("GOOD: [%d]\n"), (int)arg.toInt());
else { qse_printf (QSE_T("BAD:\n")); }
*/
if (run.setGlobal (idLastSleep, x) <= -1) return -1;
#ifdef _WIN32
::Sleep ((DWORD)(x * 1000));
return ret.set ((long_t)0);
#else
return ret.set ((long_t)::sleep (x));
#endif
}
int sumintarray (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
long_t x = 0;
if (args[0].isIndexed())
{
Argument idx(run), val(run);
int n = args[0].getFirstIndex (idx);
while (n > 0)
{
size_t len;
const char_t* ptr = idx.toStr(&len);
if (args[0].getIndexed(ptr, len, val) <= -1) return -1;
x += val.toInt ();
n = args[0].getNextIndex (idx);
}
if (n != 0) return -1;
}
else x += args[0].toInt();
return ret.set (x);
}
int arrayindices (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
if (!args[0].isIndexed()) return 0;
Argument idx (run);
long_t i;
int n = args[0].getFirstIndex (idx);
for (i = 0; n > 0; i++)
{
size_t len;
const char_t* ptr = idx.toStr(&len);
n = args[0].getNextIndex (idx);
if (ret.setIndexed (i, ptr, len) <= -1) return -1;
}
if (n != 0) return -1;
return 0;
}
Run* parse (const char_t* in, const char_t* out)
{
srcInName = in;
srcOutName = out;
return StdAwk::parse ();
}
protected:
bool onLoopEnter (Run& run)
{
set_intr_run ();
return true;
}
void onLoopExit (Run& run, const Argument& ret)
{
unset_intr_run ();
if (verbose)
{
size_t len;
const char_t* ptr = ret.toStr (&len);
qse_printf (QSE_T("*** return [%.*s] ***\n"), (int)len, ptr);
}
}
int openSource (Source& io)
{
Source::Mode mode = io.getMode();
FILE* fp = QSE_NULL;
// TODO: use sio instead of stdio
if (mode == Source::READ)
{
if (srcInName == QSE_NULL)
{
io.setHandle (stdin);
return 0;
}
if (srcInName[0] == QSE_T('\0')) fp = stdin;
else fp = qse_fopen (srcInName, QSE_T("r"));
}
else if (mode == Source::WRITE)
{
if (srcOutName == QSE_NULL)
{
io.setHandle (stdout);
return 0;
}
if (srcOutName[0] == QSE_T('\0')) fp = stdout;
else fp = qse_fopen (srcOutName, QSE_T("w"));
}
if (fp == QSE_NULL) return -1;
io.setHandle (fp);
return 1;
}
int closeSource (Source& io)
{
FILE* fp = (FILE*)io.getHandle();
if (fp == stdout || fp == stderr) fflush (fp);
if (fp != stdin && fp != stdout && fp != stderr) fclose (fp);
io.setHandle (QSE_NULL);
return 0;
}
ssize_t readSource (Source& io, char_t* buf, size_t len)
{
FILE* fp = (FILE*)io.getHandle();
ssize_t n = 0;
while (n < (ssize_t)len)
{
qse_cint_t c = qse_fgetc (fp);
if (c == QSE_CHAR_EOF)
{
if (qse_ferror(fp)) n = -1;
break;
}
buf[n++] = c;
if (c == QSE_T('\n')) break;
}
return n;
}
ssize_t writeSource (Source& io, char_t* buf, size_t len)
{
FILE* fp = (FILE*)io.getHandle();
size_t left = len;
while (left > 0)
{
if (*buf == QSE_T('\0'))
{
if (qse_fputc(*buf,fp) == QSE_CHAR_EOF) return -1;
left -= 1; buf += 1;
}
else
{
int chunk = (left > QSE_TYPE_MAX(int))? QSE_TYPE_MAX(int): (int)left;
int n = qse_fprintf (fp, QSE_T("%.*s"), chunk, buf);
if (n < 0 || n > chunk) return -1;
left -= n; buf += n;
}
}
return len;
}
void* allocMem (size_t n) throw ()
{
#ifdef _WIN32
return ::HeapAlloc (heap, 0, n);
#else
return ::malloc (n);
#endif
}
void* reallocMem (void* ptr, size_t n) throw ()
{
#ifdef _WIN32
if (ptr == NULL)
return ::HeapAlloc (heap, 0, n);
else
return ::HeapReAlloc (heap, 0, ptr, n);
#else
return ::realloc (ptr, n);
#endif
}
void freeMem (void* ptr) throw ()
{
#ifdef _WIN32
::HeapFree (heap, 0, ptr);
#else
::free (ptr);
#endif
}
private:
const char_t* srcInName;
const char_t* srcOutName;
int idLastSleep;
#ifdef _WIN32
void* heap;
#endif
};
#ifdef _WIN32
static BOOL WINAPI stop_run (DWORD ctrl_type)
{
if (ctrl_type == CTRL_C_EVENT ||
ctrl_type == CTRL_CLOSE_EVENT)
{
if (app_awk) app_awk->stop ();
return TRUE;
}
return FALSE;
}
#else
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)
{
#ifdef SA_RESTART
sa_int.sa_flags |= SA_RESTART;
#endif
}
else
{
#ifdef SA_INTERRUPT
sa_int.sa_flags |= SA_INTERRUPT;
#endif
}
return sigaction (sig, &sa_int, NULL);
}
static void stop_run (int sig)
{
int e = errno;
if (app_awk) app_awk->stop ();
errno = e;
}
#endif
static void set_intr_run (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, TRUE);
#else
/*setsignal (SIGINT, stop_run, 1); TO BE MORE COMPATIBLE WITH WIN32*/
setsignal (SIGINT, stop_run, 0);
#endif
}
static void unset_intr_run (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, FALSE);
#else
setsignal (SIGINT, SIG_DFL, 1);
#endif
}
static void print_error (const qse_char_t* msg)
{
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
static struct
{
const qse_char_t* name;
MyAwk::Option opt;
} otab[] =
{
{ QSE_T("implicit"), MyAwk::OPT_IMPLICIT },
{ QSE_T("explicit"), MyAwk::OPT_EXPLICIT },
{ QSE_T("bxor"), MyAwk::OPT_BXOR },
{ QSE_T("shift"), MyAwk::OPT_SHIFT },
{ QSE_T("idiv"), MyAwk::OPT_IDIV },
{ QSE_T("rio"), MyAwk::OPT_RIO },
{ QSE_T("rwpipe"), MyAwk::OPT_RWPIPE },
{ QSE_T("newline"), MyAwk::OPT_NEWLINE },
{ QSE_T("stripspaces"), MyAwk::OPT_STRIPSPACES },
{ QSE_T("nextofile"), MyAwk::OPT_NEXTOFILE },
{ QSE_T("crlf"), MyAwk::OPT_CRLF },
{ QSE_T("reset"), MyAwk::OPT_RESET },
{ QSE_T("maptovar"), MyAwk::OPT_MAPTOVAR },
{ QSE_T("pablock"), MyAwk::OPT_PABLOCK }
};
static void print_usage (const qse_char_t* argv0)
{
const qse_char_t* base;
int j;
base = qse_strrchr(argv0, QSE_T('/'));
if (base == QSE_NULL) base = qse_strrchr(argv0, QSE_T('\\'));
if (base == QSE_NULL) base = argv0; else base++;
qse_printf (QSE_T("Usage: %s [-si file]? [-so file]? [-ci file]* [-co file]* [-w o:n]* \n"), base);
qse_printf (QSE_T(" -si file Specify the input source file\n"));
qse_printf (QSE_T(" The source code is read from stdin when it is not specified\n"));
qse_printf (QSE_T(" -so file Specify the output source file\n"));
qse_printf (QSE_T(" The deparsed code is not output when is it not specified\n"));
qse_printf (QSE_T(" -ci file Specify the input console file\n"));
qse_printf (QSE_T(" -co file Specify the output console file\n"));
qse_printf (QSE_T(" -w o:n Specify an old and new word pair\n"));
qse_printf (QSE_T(" o - an original word\n"));
qse_printf (QSE_T(" n - the new word to replace the original\n"));
qse_printf (QSE_T(" -v Print extra messages\n"));
qse_printf (QSE_T("\nYou may specify the following options to change the behavior of the interpreter.\n"));
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
{
qse_printf (QSE_T(" -%-20s -no%-20s\n"), otab[j].name, otab[j].name);
}
}
static int awk_main (int argc, qse_char_t* argv[])
{
MyAwk awk;
MyAwk::Run* run;
int mode = 0;
const qse_char_t* srcin = QSE_T("");
const qse_char_t* srcout = NULL;
qse_size_t nsrcins = 0;
qse_size_t nsrcouts = 0;
if (awk.open() <= -1)
{
print_error (awk.getErrorMessage());
return -1;
}
// ARGV[0]
if (awk.addArgument (QSE_T("awk05")) <= -1)
{
print_error (awk.getErrorMessage());
awk.close ();
return -1;
}
for (int i = 1; i < argc; i++)
{
if (mode == 0)
{
if (qse_strcmp(argv[i], QSE_T("-si")) == 0) mode = 1;
else if (qse_strcmp(argv[i], QSE_T("-so")) == 0) mode = 2;
else if (qse_strcmp(argv[i], QSE_T("-ci")) == 0) mode = 3;
else if (qse_strcmp(argv[i], QSE_T("-co")) == 0) mode = 4;
else if (qse_strcmp(argv[i], QSE_T("-w")) == 0) mode = 5;
else if (qse_strcmp(argv[i], QSE_T("-v")) == 0)
{
verbose = true;
}
else
{
if (argv[i][0] == QSE_T('-'))
{
int j;
if (argv[i][1] == QSE_T('n') && argv[i][2] == QSE_T('o'))
{
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
{
if (qse_strcmp(&argv[i][3], otab[j].name) == 0)
{
awk.setOption (awk.getOption() & ~otab[j].opt);
goto ok_valid;
}
}
}
else
{
for (j = 0; j < (int)QSE_COUNTOF(otab); j++)
{
if (qse_strcmp(&argv[i][1], otab[j].name) == 0)
{
awk.setOption (awk.getOption() | otab[j].opt);
goto ok_valid;
}
}
}
}
print_usage (argv[0]);
return -1;
ok_valid:
;
}
}
else
{
if (argv[i][0] == QSE_T('-'))
{
print_usage (argv[0]);
return -1;
}
if (mode == 1) // source input
{
if (nsrcins != 0)
{
print_usage (argv[0]);
return -1;
}
srcin = argv[i];
nsrcins++;
mode = 0;
}
else if (mode == 2) // source output
{
if (nsrcouts != 0)
{
print_usage (argv[0]);
return -1;
}
srcout = argv[i];
nsrcouts++;
mode = 0;
}
else if (mode == 3) // console input
{
if (awk.addArgument (argv[i]) <= -1)
{
print_error (QSE_T("too many console inputs"));
return -1;
}
mode = 0;
}
else if (mode == 4) // console output
{
if (awk.addConsoleOutput (argv[i]) <= -1)
{
print_error (QSE_T("too many console outputs"));
return -1;
}
mode = 0;
}
else if (mode == 5) // word replacement
{
const qse_char_t* p;
qse_size_t l;
p = qse_strchr(argv[i], QSE_T(':'));
if (p == QSE_NULL)
{
print_usage (argv[0]);
return -1;
}
l = qse_strlen (argv[i]);
awk.setWord (
argv[i], p - argv[i],
p + 1, l - (p - argv[i] + 1));
mode = 0;
}
}
}
if (mode != 0)
{
print_usage (argv[0]);
awk.close ();
return -1;
}
run = awk.parse (srcin, srcout);
if (run == QSE_NULL)
{
qse_fprintf (stderr, QSE_T("cannot parse: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
awk.enableRunCallback ();
app_awk = &awk;
if (awk.loop () <= -1)
{
qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
#if 0
MyAwk::Return args[2];
args[0].setRun (run);
args[1].setRun (run);
if (awk.call (QSE_T("add"), args, 2) <= -1)
{
qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
}
#endif
app_awk = QSE_NULL;
awk.close ();
return 0;
}
int qse_main (int argc, qse_achar_t* argv[])
{
return qse_runmain (argc,argv,awk_main);
}