updated documentation

This commit is contained in:
hyung-hwan 2013-01-09 08:03:21 +00:00
parent 19b4e697af
commit 6e94d324ef
20 changed files with 1143 additions and 1317 deletions

View File

@ -9,7 +9,6 @@ EXTRA_DIST = \
page/mem.doc \
page/cenc.doc \
page/io.doc \
page/awk.doc \
page/awk-embed.md \
page/awk-lang.md \
page/sed.doc \

View File

@ -234,7 +234,6 @@ EXTRA_DIST = \
page/mem.doc \
page/cenc.doc \
page/io.doc \
page/awk.doc \
page/awk-embed.md \
page/awk-lang.md \
page/sed.doc \
@ -432,6 +431,9 @@ uninstall-am:
mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
all:
doxygen
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -62,23 +62,31 @@ functions like *gsub* or *index*.
\includelineno awk03.c
If you want to pass arguments to the function you call with qse_awk_rtx_call(),
you must create values with value creation functions, updates their reference
count, and pass them to qse_awk_rtx_call(). The sample below creates 2 integer
values with qse_awk_rtx_makeintval() and pass them to the *pow* function.
If you want to pass arguments to the function, you must create values with
value creation functions, updates their reference count, and pass them to
qse_awk_rtx_call(). The sample below creates 2 integer values with
qse_awk_rtx_makeintval() and pass them to the *pow* function.
\includelineno awk04.c
While qse_awk_rtx_call() looks up a function in the function table by name,
you can find the function in advance and use the information found when
calling a function. qse_awk_rtx_findfun() and qse_awk_rtx_callfun() come
to play a role in this situation. qse_awk_rtx_call() in the sample above
can be translated into 2 separate calls to qse_awk_rtx_findfun() and
qse_awk_rtx_callfun(). You can reduce look-up overhead via these 2
functions if you have to execute the same function multiple times.
calling it. qse_awk_rtx_findfun() and qse_awk_rtx_callfun() come to play a role
in this situation. qse_awk_rtx_call() in the sample above can be translated
into 2 separate calls to qse_awk_rtx_findfun() and qse_awk_rtx_callfun().
You can reduce look-up overhead via these 2 functions if you are to execute
the same function multiple times.
\includelineno awk05.c
Similarly, you can pass a more complex value than a number. You can compose
a map value with qse_awk_rtx_makemapval() or qse_awk_rtx_makemapvalwithdata().
The sample below demonstrates how to use qse_awk_rtx_makemapvalwithdata(),
pass a created map value to qse_awk_rtx_call(), and traverse a map value
returned with qse_awk_rtx_getfirstmapvalitr() and qse_awk_rtx_getnextmapvalitr().
\includelineno awk06.c
Global Variables
----------------
@ -91,6 +99,29 @@ Built-in Functions
You can add built-in functions with qse_awk_addfnc().
On the other hand, modular built-in functions reside in a shared object.
Single Script over Multiple Data Streams
----------------------------------------
Customizing Language Features
-----------------------------
Creating multiple awk objects
-----------------------------
Memory Pool
-----------
Embedding in C++
-----------------
The QSE::Awk class and QSE::StdAwk classe wrap the underlying C library routines
for better object-orientation. These two classes are defined in <qse/awk/Awk.hpp>
and <qse/awk/StdAwk.hpp> respectively. The embedding task can be simplified despite
slight performance overhead. The hello-world sample in C can be rewritten with
less numbers of lines in C++.
\includelineno awk21.cpp
Changes in 0.6.0
----------------

View File

@ -1,180 +0,0 @@
/** @page awk AWK
@section awk-content CONTENTS
- @ref awk-intro "INTRODUCTION"
@section awk-intro INTRODUCTION
QSEAWK is an AWK interpreter and is a part of the @ref qse_intro "QSE" library.
Its design focuses on building a flexible and robust embedding API with minimal
platform dependency. An embedding application is capable of:
- adding new global variables and functions.
- getting and set the value of a global variable.
- calling a function with or without parameters and getting its return value.
- customizing I/O handlers for file, pipe, console I/O.
- creating multiple interpreters independent of each other.
- running a single script with different I/O streams independently.
- changing language features by setting options.
- and more
The library implements AWK in multiple levels:
- base interpreter
- standard interpreter
- parallel interpreter
The base interpreter provides most core language features while minimizing
platform dependence. When working with the base interpreter, you're required
to write primtive operation handlers like I/O and pass them in to make it
useful. The standard interpreter is usable immediately since it implements
all the primitive operations required by the base interpreter and adds
standard AWK functions. The parallel interpreter enables parallel processing
by adding various MPI variables and functions to the standard interpreter.
Embedding a standard interpreter typically involves the following steps.
- open a new interpreter
- parse in a source script
- open a new runtime context
- execute pattern-action blocks or call a function
- close the runtime context
- close the interpter
The code example below demonstrates the steps in C. It executes the one liner
<b>BEGIN { print "hello, world" }</b>.
@code
/* cc -o hello hello.c -lqseawk -lqsecmn -lm */
#include <qse/awk/std.h>
#include <qse/cmn/stdio.h>
#define FAIL(msg) do { qse_printf(QSE_T("ERR: %s\n"),msg); goto oops; } while(0)
int main ()
{
qse_awk_t* awk = QSE_NULL;
qse_awk_rtx_t* rtx = QSE_NULL;
qse_awk_val_t* retv;
qse_awk_parsestd_t psin;
int ret = -1;
awk = qse_awk_openstd (0); /* open a new interpreter */
if (!awk) FAIL ("cannot open awk");
/* parse the hello world script from a string */
psin.type = QSE_AWK_PARSESTD_STR;
psin.u.str.ptr = QSE_T("BEGIN { print \"hello, world\" }");
psin.u.str.len = qse_strlen(psin.u.str.ptr);
if (qse_awk_parsestd (awk, &psin, QSE_NULL) <= -1)
FAIL (qse_awk_geterrmsg(awk));
rtx = qse_awk_rtx_openstd ( /* open a runtime context */
awk, 0, /* no extension */
QSE_T("hello"), /* ARGV[0] */
QSE_NULL, /* stdin */
QSE_NULL, /* stdout */
QSE_NULL /* default cmgr */
);
if (!rtx) FAIL (qse_awk_geterrmsg(awk));
/* exeucte pattern-action blocks */
retv = qse_awk_rtx_loop (rtx);
if (!retv) FAIL (qse_awk_rtx_geterrmsg(rtx));
qse_awk_rtx_refdownval (rtx, retv); /* destroy the return value */
ret = 0;
oops:
if (rtx) qse_awk_rtx_close (rtx); /* close the runtime context */
if (awk) qse_awk_close (awk); /* close the interpreter */
return ret;
}
@endcode
Things can get simpler when you use C++ API. Note that the C++ API supports
1 single runtime context for each interpreter.
@code
/* c++ -o hello hello.cpp -lqseawkxx -lqseawk -lqsecmnxx -lqsecmn -lm */
#include <qse/awk/StdAwk.hpp>
#include <iostream>
#ifdef QSE_CHAR_IS_MCHAR
# define xcout std::cout
#else
# define xcout std::wcout
#endif
struct MyAwk: public QSE::StdAwk { ~MyAwk () { QSE::StdAwk::close (); } };
#define FAIL(awk) do { \
xcout << QSE_T("ERR: ") << awk.getErrorMessage() << std::endl; \
return -1; \
} while (0)
int main (int argc, char* argv[])
{
MyAwk awk;
// open a new interpreter
if (awk.open () <= -1) FAIL (awk);
// set ARGV[0]
if (awk.addArgument (QSE_T("hello")) <= -1) FAIL (awk);
// parse the source script string
MyAwk::SourceString in(QSE_T("BEGIN { print \"hello, world\" }"));
if (awk.parse (in, MyAwk::Source::NONE) == QSE_NULL) FAIL (awk);
// execute pattern-action blocks.
MyAwk::Value r;
if (awk.loop (&r) <= -1) FAIL (awk);
return 0;
}
@endcode
This library also provides a stand-alone AWK interpreter that you can use
in a console environment. The source code is located under the
<project-root>/cmd/awk subdirectory. See the usage below.
@code
$ qseawk
USAGE: qseawk [options] -f sourcefile [ -- ] [datafile]*
qseawk [options] [ -- ] sourcestring [datafile]*
Where options are:
-h/--help print this message
--version print version
-D show extra information
-c/--call name call a function instead of entering
the pattern-action loop
-f/--file sourcefile set the source script file
-d/--deparsed-file deparsedfile set the deparsing output file
-F/--field-separator string set a field separator(FS)
-v/--assign var=value add a global variable with a value
-m/--memory-limit number limit the memory usage (bytes)
-X number fail the number'th memory allocation
--script-encoding string specify script file encoding name
--console-encoding string specify console encoding name
--implicit on/off allow undeclared variables
--explicit on/off allow declared variables(local,global)
--extraops on/off enable extra operators(<<,>>,^^,\)
--rio on/off enable builtin I/O including getline & print
--rwpipe on/off allow a dual-directional pipe
--newline on/off enable a newline to terminate a statement
--striprecspc on/off strip spaces in splitting a record
--stripstrspc on/off strip spaces in converting a string to a number
--nextofile on/off enable 'nextofile'
--reset on/off enable 'reset'
--crlf on/off use CRLF for a newline
--maptovar on/off allow a map to be assigned or returned
--pablock on/off enable pattern-action loop
--rexbound on/off enable {n,m} in a regular expression
--ncmponstr on/off perform numeric comparsion on numeric strings
--strictnaming on/off enable the strict naming rule
--include on/off enable '@include'
--tolerant on/off make more I/O fault-tolerant
--abort on/off enable 'abort'
@endcode
*/

View File

@ -13,7 +13,7 @@ aspects of embedding application and an embedded object from each other.
The library is licensed under the GNU Lesser General Public License version 3:
http://www.gnu.org/licenses/
The project webpage: http://code.abiyo.net/@qse
The project webpage: http://code.abiyo.net/@qse or http://qse.googlecode.com
For further information, contact:
Chung, Hyung-Hwan <hyunghwan.chung@gmail.com>
@ -21,11 +21,10 @@ Chung, Hyung-Hwan <hyunghwan.chung@gmail.com>
See the subpages for more information.
- @ref installation
- @ref awk-lang
- @ref awk-embed
- @subpage mem "Memory Management"
- @subpage cenc "Character Encoding"
- @subpage io "I/O Handling"
- @subpage awk "AWK Interpreter"
- @subpage sed "SED Stream Editor"
- @subpage awk-lang
- @subpage awk-embed

View File

@ -29,7 +29,6 @@
/// @file
/// AWK Interpreter
///
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)

View File

@ -27,33 +27,6 @@
/// @file
/// Standard AWK Interpreter
///
/// @example awk05.cpp
/// This program demonstrates how to use QSE::StdAwk::loop().
///
/// @example awk06.cpp
/// This program demonstrates how to use QSE::StdAwk::call().
///
/// @example awk07.cpp
/// This program demonstrates how to handle an indexed value.
///
/// @example awk08.cpp
/// This program shows how to add intrinsic functions.
///
/// @example awk12.cpp
/// This program shows how to override console methods to use
/// string buffers for console input and output.
///
/// @example awk13.cpp
/// This program shows how to use resetRunContext(). It is similar
/// to awk12.cpp in principle.
///
/// @example awk14.cpp
/// This program shows how to define a console handler to use
/// string buffers for console input and output. It is identical
/// to awk13.cpp except that it relies an external console handler
/// rather than overriding console methods.
///
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@
#include <qse/awk/awk.h>
#include <qse/cmn/sio.h>
/** @file
/** \file
* 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.
@ -34,16 +34,6 @@
* normal file name.
*/
/**
* @example awk09.c
* This programs shows how to specify multiple console output files.
*
* @example awk11.c
* This programs shows how to extend an I/O handler implemented by
* qse_awk_rtx_openstd().
*
*/
/**
* The qse_awk_parsestd_type_t type defines the types of source I/O.
*/
@ -128,7 +118,7 @@ QSE_EXPORT void* qse_awk_getxtnstd (
* The qse_awk_parsestd() functions parses source script.
* The code below shows how to parse a literal string 'BEGIN { print 10; }'
* and deparses it out to a buffer 'buf'.
* @code
* \code
* int n;
* qse_awk_parsestd_t in[2];
* qse_awk_parsestd_t out;
@ -144,7 +134,7 @@ QSE_EXPORT void* qse_awk_getxtnstd (
* qse_printf (QSE_T("%s\n"), out.u.str.ptr);
* QSE_MMGR_FREE (out.u.str.ptr);
* }
* @endcode
* \endcode
*/
QSE_EXPORT int qse_awk_parsestd (
qse_awk_t* awk,
@ -154,9 +144,9 @@ QSE_EXPORT int qse_awk_parsestd (
/**
* The qse_awk_rtx_openstd() function creates a standard runtime context.
* The caller should keep the contents of @a icf and @a ocf valid throughout
* the lifetime of the runtime context created. The @a cmgr is set to the
* streams created with @a icf and @a ocf if it is not #QSE_NULL.
* The caller should keep the contents of \a icf and \a ocf valid throughout
* the lifetime of the runtime context created. The \a cmgr is set to the
* streams created with \a icf and \a ocf if it is not #QSE_NULL.
*/
QSE_EXPORT qse_awk_rtx_t* qse_awk_rtx_openstd (
qse_awk_t* awk,
@ -178,7 +168,7 @@ QSE_EXPORT void* qse_awk_rtx_getxtnstd (
/**
* The qse_awk_rtx_getcmgrstd() function gets the current character
* manager associated with a particular I/O target indicated by the name
* @a ioname if #QSE_CHAR_IS_WCHAR is defined. It always returns #QSE_NULL
* \a ioname if #QSE_CHAR_IS_WCHAR is defined. It always returns #QSE_NULL
* if #QSE_CHAR_IS_MCHAR is defined.
*/
QSE_EXPORT qse_cmgr_t* qse_awk_rtx_getcmgrstd (

View File

@ -5,7 +5,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(includedir)
bin_PROGRAMS = awk01 awk02 awk03 awk04 awk05 awk09 awk10 awk11 awk15
bin_PROGRAMS = awk01 awk02 awk03 awk04 awk05 awk06 awk09 awk11 awk15
LDFLAGS = -L../../lib/awk -L../../lib/cmn
LDADD = -lqseawk -lqsecmn $(LIBM)
@ -21,8 +21,8 @@ awk02_SOURCES = awk02.c
awk03_SOURCES = awk03.c
awk04_SOURCES = awk04.c
awk05_SOURCES = awk05.c
awk06_SOURCES = awk06.c
awk09_SOURCES = awk09.c
awk10_SOURCES = awk10.c
awk11_SOURCES = awk11.c
awk15_SOURCES = awk15.c
@ -30,7 +30,7 @@ if ENABLE_CXX
CXXLIB = -lqseawkxx -lqsecmnxx
bin_PROGRAMS += awk21 awk22 awk23 awk24 awk25 awk26 awk27
bin_PROGRAMS += awk21 awk22 awk23 awk24 awk25 awk26 awk27 awk28
awk21_SOURCES = awk21.cpp
awk22_SOURCES = awk22.cpp
@ -39,6 +39,7 @@ awk24_SOURCES = awk24.cpp
awk25_SOURCES = awk25.cpp
awk26_SOURCES = awk26.cpp
awk27_SOURCES = awk27.cpp
awk28_SOURCES = awk27.cpp
awk21_LDADD = $(CXXLIB) $(LDADD)
awk22_LDADD = $(CXXLIB) $(LDADD)
@ -47,4 +48,5 @@ awk24_LDADD = $(CXXLIB) $(LDADD)
awk25_LDADD = $(CXXLIB) $(LDADD)
awk26_LDADD = $(CXXLIB) $(LDADD)
awk27_LDADD = $(CXXLIB) $(LDADD)
awk28_LDADD = $(CXXLIB) $(LDADD)
endif

View File

@ -35,10 +35,10 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = awk01$(EXEEXT) awk02$(EXEEXT) awk03$(EXEEXT) \
awk04$(EXEEXT) awk05$(EXEEXT) awk09$(EXEEXT) awk10$(EXEEXT) \
awk04$(EXEEXT) awk05$(EXEEXT) awk06$(EXEEXT) awk09$(EXEEXT) \
awk11$(EXEEXT) awk15$(EXEEXT) $(am__EXEEXT_1)
@WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS)
@ENABLE_CXX_TRUE@am__append_2 = awk21 awk22 awk23 awk24 awk25 awk26 awk27
@ENABLE_CXX_TRUE@am__append_2 = awk21 awk22 awk23 awk24 awk25 awk26 awk27 awk28
subdir = samples/awk
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -56,7 +56,7 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
@ENABLE_CXX_TRUE@am__EXEEXT_1 = awk21$(EXEEXT) awk22$(EXEEXT) \
@ENABLE_CXX_TRUE@ awk23$(EXEEXT) awk24$(EXEEXT) awk25$(EXEEXT) \
@ENABLE_CXX_TRUE@ awk26$(EXEEXT) awk27$(EXEEXT)
@ENABLE_CXX_TRUE@ awk26$(EXEEXT) awk27$(EXEEXT) awk28$(EXEEXT)
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_awk01_OBJECTS = awk01.$(OBJEXT)
@ -81,14 +81,14 @@ am_awk05_OBJECTS = awk05.$(OBJEXT)
awk05_OBJECTS = $(am_awk05_OBJECTS)
awk05_LDADD = $(LDADD)
awk05_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_awk06_OBJECTS = awk06.$(OBJEXT)
awk06_OBJECTS = $(am_awk06_OBJECTS)
awk06_LDADD = $(LDADD)
awk06_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_awk09_OBJECTS = awk09.$(OBJEXT)
awk09_OBJECTS = $(am_awk09_OBJECTS)
awk09_LDADD = $(LDADD)
awk09_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_awk10_OBJECTS = awk10.$(OBJEXT)
awk10_OBJECTS = $(am_awk10_OBJECTS)
awk10_LDADD = $(LDADD)
awk10_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_awk11_OBJECTS = awk11.$(OBJEXT)
awk11_OBJECTS = $(am_awk11_OBJECTS)
awk11_LDADD = $(LDADD)
@ -133,6 +133,11 @@ am__awk27_SOURCES_DIST = awk27.cpp
awk27_OBJECTS = $(am_awk27_OBJECTS)
@ENABLE_CXX_TRUE@awk27_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@ENABLE_CXX_TRUE@ $(am__DEPENDENCIES_3)
am__awk28_SOURCES_DIST = awk27.cpp
@ENABLE_CXX_TRUE@am_awk28_OBJECTS = awk27.$(OBJEXT)
awk28_OBJECTS = $(am_awk28_OBJECTS)
@ENABLE_CXX_TRUE@awk28_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@ENABLE_CXX_TRUE@ $(am__DEPENDENCIES_3)
DEFAULT_INCLUDES =
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
am__depfiles_maybe = depfiles
@ -156,18 +161,18 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \
$(awk04_SOURCES) $(awk05_SOURCES) $(awk09_SOURCES) \
$(awk10_SOURCES) $(awk11_SOURCES) $(awk15_SOURCES) \
$(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \
$(awk09_SOURCES) $(awk11_SOURCES) $(awk15_SOURCES) \
$(awk21_SOURCES) $(awk22_SOURCES) $(awk23_SOURCES) \
$(awk24_SOURCES) $(awk25_SOURCES) $(awk26_SOURCES) \
$(awk27_SOURCES)
$(awk27_SOURCES) $(awk28_SOURCES)
DIST_SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \
$(awk04_SOURCES) $(awk05_SOURCES) $(awk09_SOURCES) \
$(awk10_SOURCES) $(awk11_SOURCES) $(awk15_SOURCES) \
$(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \
$(awk09_SOURCES) $(awk11_SOURCES) $(awk15_SOURCES) \
$(am__awk21_SOURCES_DIST) $(am__awk22_SOURCES_DIST) \
$(am__awk23_SOURCES_DIST) $(am__awk24_SOURCES_DIST) \
$(am__awk25_SOURCES_DIST) $(am__awk26_SOURCES_DIST) \
$(am__awk27_SOURCES_DIST)
$(am__awk27_SOURCES_DIST) $(am__awk28_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -354,8 +359,8 @@ awk02_SOURCES = awk02.c
awk03_SOURCES = awk03.c
awk04_SOURCES = awk04.c
awk05_SOURCES = awk05.c
awk06_SOURCES = awk06.c
awk09_SOURCES = awk09.c
awk10_SOURCES = awk10.c
awk11_SOURCES = awk11.c
awk15_SOURCES = awk15.c
@ENABLE_CXX_TRUE@CXXLIB = -lqseawkxx -lqsecmnxx
@ -366,6 +371,7 @@ awk15_SOURCES = awk15.c
@ENABLE_CXX_TRUE@awk25_SOURCES = awk25.cpp
@ENABLE_CXX_TRUE@awk26_SOURCES = awk26.cpp
@ENABLE_CXX_TRUE@awk27_SOURCES = awk27.cpp
@ENABLE_CXX_TRUE@awk28_SOURCES = awk27.cpp
@ENABLE_CXX_TRUE@awk21_LDADD = $(CXXLIB) $(LDADD)
@ENABLE_CXX_TRUE@awk22_LDADD = $(CXXLIB) $(LDADD)
@ENABLE_CXX_TRUE@awk23_LDADD = $(CXXLIB) $(LDADD)
@ -373,6 +379,7 @@ awk15_SOURCES = awk15.c
@ENABLE_CXX_TRUE@awk25_LDADD = $(CXXLIB) $(LDADD)
@ENABLE_CXX_TRUE@awk26_LDADD = $(CXXLIB) $(LDADD)
@ENABLE_CXX_TRUE@awk27_LDADD = $(CXXLIB) $(LDADD)
@ENABLE_CXX_TRUE@awk28_LDADD = $(CXXLIB) $(LDADD)
all: all-am
.SUFFIXES:
@ -465,12 +472,12 @@ awk04$(EXEEXT): $(awk04_OBJECTS) $(awk04_DEPENDENCIES) $(EXTRA_awk04_DEPENDENCIE
awk05$(EXEEXT): $(awk05_OBJECTS) $(awk05_DEPENDENCIES) $(EXTRA_awk05_DEPENDENCIES)
@rm -f awk05$(EXEEXT)
$(LINK) $(awk05_OBJECTS) $(awk05_LDADD) $(LIBS)
awk06$(EXEEXT): $(awk06_OBJECTS) $(awk06_DEPENDENCIES) $(EXTRA_awk06_DEPENDENCIES)
@rm -f awk06$(EXEEXT)
$(LINK) $(awk06_OBJECTS) $(awk06_LDADD) $(LIBS)
awk09$(EXEEXT): $(awk09_OBJECTS) $(awk09_DEPENDENCIES) $(EXTRA_awk09_DEPENDENCIES)
@rm -f awk09$(EXEEXT)
$(LINK) $(awk09_OBJECTS) $(awk09_LDADD) $(LIBS)
awk10$(EXEEXT): $(awk10_OBJECTS) $(awk10_DEPENDENCIES) $(EXTRA_awk10_DEPENDENCIES)
@rm -f awk10$(EXEEXT)
$(LINK) $(awk10_OBJECTS) $(awk10_LDADD) $(LIBS)
awk11$(EXEEXT): $(awk11_OBJECTS) $(awk11_DEPENDENCIES) $(EXTRA_awk11_DEPENDENCIES)
@rm -f awk11$(EXEEXT)
$(LINK) $(awk11_OBJECTS) $(awk11_LDADD) $(LIBS)
@ -498,6 +505,9 @@ awk26$(EXEEXT): $(awk26_OBJECTS) $(awk26_DEPENDENCIES) $(EXTRA_awk26_DEPENDENCIE
awk27$(EXEEXT): $(awk27_OBJECTS) $(awk27_DEPENDENCIES) $(EXTRA_awk27_DEPENDENCIES)
@rm -f awk27$(EXEEXT)
$(CXXLINK) $(awk27_OBJECTS) $(awk27_LDADD) $(LIBS)
awk28$(EXEEXT): $(awk28_OBJECTS) $(awk28_DEPENDENCIES) $(EXTRA_awk28_DEPENDENCIES)
@rm -f awk28$(EXEEXT)
$(CXXLINK) $(awk28_OBJECTS) $(awk28_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -510,8 +520,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk03.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk04.Po@am__quote@
@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)/awk09.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk10.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk11.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk15.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk21.Po@am__quote@

View File

@ -1,23 +1,3 @@
/*
* $Id: awk04.c 441 2011-04-22 14:28:43Z hyunghwan.chung $
*
Copyright 2006-2012 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
#include <qse/awk/std.h>
#include <qse/cmn/stdio.h>
@ -32,20 +12,18 @@ int main ()
qse_awk_parsestd_t psin[2];
qse_awk_val_t* rtv = QSE_NULL;
qse_awk_val_t* arg = QSE_NULL;
int ret, i, opt;
struct
int ret, opt;
/* this structure is passed to qse_awk_rtx_makemapvalwithdata() */
qse_awk_val_map_data_t md[] =
{
const qse_char_t* kptr;
qse_size_t klen;
const qse_char_t* vptr;
} xxx[] =
{
{ QSE_T("f0"), 2, QSE_T("linux") },
{ QSE_T("f1"), 2, QSE_T("openvms") },
{ QSE_T("f2"), 2, QSE_T("hpux") }
{ { QSE_T("f0"), 2 }, QSE_AWK_VAL_MAP_DATA_STR, QSE_T("linux") },
{ { QSE_T("f1"), 2 }, QSE_AWK_VAL_MAP_DATA_STR, QSE_T("openvms") },
{ { QSE_T("f2"), 2 }, QSE_AWK_VAL_MAP_DATA_STR, QSE_T("hpux") },
{ { QSE_NULL, 0 }, 0, QSE_NULL } /* last item */
};
/* create a main processor */
/* create a standard awk object */
awk = qse_awk_openstd (0);
if (awk == QSE_NULL)
{
@ -53,18 +31,20 @@ int main ()
ret = -1; goto oops;
}
/* get the awk's trait */
qse_awk_getopt (awk, QSE_AWK_TRAIT, &opt);
/* don't allow BEGIN, END, pattern-action blocks */
/* change the trait value to disallow BEGIN, END, pattern-action blocks */
opt &= ~QSE_AWK_PABLOCK;
/* can assign a map to a variable */
opt |= QSE_AWK_FLEXMAP;
/* update the trait */
qse_awk_setopt (awk, QSE_AWK_TRAIT, &opt);
/* prepare a script to parse */
psin[0].type = QSE_AWK_PARSESTD_STR;
psin[0].u.str.ptr = src;
psin[0].u.str.len = qse_strlen(src);
psin[1].type = QSE_AWK_PARSESTD_NULL;
/* parse the script */
ret = qse_awk_parsestd (awk, psin, QSE_NULL);
if (ret == -1)
{
@ -73,11 +53,11 @@ int main ()
goto oops;
}
/* create a runtime context */
/* create a standard runtime context */
rtx = qse_awk_rtx_openstd (
awk,
0,
QSE_T("awk10"),
QSE_T("awk06"),
QSE_NULL, /* stdin */
QSE_NULL, /* stdout */
QSE_NULL /* default cmgr */
@ -90,8 +70,8 @@ int main ()
ret = -1; goto oops;
}
/* prepare a argument to be a map */
arg = qse_awk_rtx_makemapval (rtx);
/* create a map value to pass as an argument */
arg = qse_awk_rtx_makemapvalwithdata (rtx, md);
if (arg == QSE_NULL)
{
qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"),
@ -99,31 +79,8 @@ int main ()
ret = -1; goto oops;
}
qse_awk_rtx_refupval (rtx, arg);
/* insert some key/value pairs into the map */
for (i = 0; i < QSE_COUNTOF(xxx); i++)
{
qse_awk_val_t* v, * fv;
fv = qse_awk_rtx_makestrvalwithstr (rtx, xxx[i].vptr);
if (fv == QSE_NULL)
{
qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"),
qse_awk_rtx_geterrmsg(rtx));
ret = -1; goto oops;
}
qse_awk_rtx_refupval (rtx, fv);
v = qse_awk_rtx_setmapvalfld (rtx, arg, xxx[i].kptr, xxx[i].klen, fv);
qse_awk_rtx_refdownval (rtx, fv);
if (v == QSE_NULL)
{
qse_fprintf (QSE_STDERR, QSE_T("error: %s\n"),
qse_awk_rtx_geterrmsg(rtx));
ret = -1; goto oops;
}
}
/* invoke the dump function */
/* execute the dump function in the awk script */
rtv = qse_awk_rtx_call (rtx, QSE_T("dump"), &arg, 1);
if (rtv == QSE_NULL)
{
@ -132,17 +89,21 @@ int main ()
ret = -1; goto oops;
}
/* print the return value */
if (rtv->type == QSE_AWK_VAL_MAP)
{
/* if a returned value is a map,
* traverse the map and print the key/value pairs. */
qse_awk_val_map_itr_t itr;
qse_awk_val_map_itr_t* iptr;
/* get the iterator to the first key/value pair */
iptr = qse_awk_rtx_getfirstmapvalitr (rtx, rtv, &itr);
while (iptr)
{
qse_xstr_t str;
/* #QSE_AWK_VAL_MAP_ITR_VAL returns the value part */
str.ptr = qse_awk_rtx_valtostrdup (
rtx, QSE_AWK_VAL_MAP_ITR_VAL(iptr), &str.len);
if (str.ptr == QSE_NULL)
@ -152,6 +113,7 @@ int main ()
ret = -1; goto oops;
}
/* #QSE_AWK_VAL_MAP_ITR_KEY returns the key part */
qse_printf (QSE_T("ret [%.*s]=[%.*s]\n"),
(int)QSE_AWK_VAL_MAP_ITR_KEY(iptr)->len,
QSE_AWK_VAL_MAP_ITR_KEY(iptr)->ptr,
@ -159,11 +121,14 @@ int main ()
);
qse_awk_rtx_freemem (rtx, str.ptr);
/* get the iterator to the next key/value pair */
iptr = qse_awk_rtx_getnextmapvalitr (rtx, rtv, &itr);
}
}
else
{
/* if it is a plain value, convert it to a string
* and print it */
qse_xstr_t str;
str.ptr = qse_awk_rtx_valtostrdup (rtx, rtv, &str.len);
@ -187,7 +152,9 @@ oops:
/* destroy a runtime context */
if (rtx) qse_awk_rtx_close (rtx);
/* destroy the processor */
if (awk) qse_awk_close (awk);
return ret;
}

View File

@ -1,105 +1,32 @@
/*
* $Id$
*
Copyright 2006-2012 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <qse/cmn/mbwc.h>
#include <iostream>
#include <locale.h>
#if defined(_WIN32)
# include <windows.h>
#endif
static void print_error (
const QSE::StdAwk::loc_t& loc, const QSE::StdAwk::char_t* msg)
{
if (loc.line > 0 || loc.colm > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu COLUMN %lu\n"), msg, loc.line, loc.colm);
else
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
static int run_awk (QSE::StdAwk& awk)
{
// ARGV[0]
if (awk.addArgument (QSE_T("awk05")) <= -1) return -1;
// ARGV[1] and/or the first console input file
if (awk.addArgument (QSE_T("Makefile")) <= -1) return -1;
const qse_char_t* script = QSE_T(
"BEGIN { print \">> PRINT ALL LINES WHOSE LENGTH IS GREATER THAN 0\"; }\n"
"length($0) > 0 { print $0; count++; }\n"
"END { print \">> TOTAL\", count, \"LINES\"; }\n"
);
QSE::StdAwk::SourceString in (script);
QSE::StdAwk::SourceFile out (QSE_T("awk05.out"));
// parse the script string and deparse it to awk05.out.
if (awk.parse (in, out) == QSE_NULL) return -1;
QSE::StdAwk::Value r;
// execute the BEGIN, pattern-action, END blocks.
return awk.loop (&r);
}
static int awk_main (int argc, qse_char_t* argv[])
{
QSE::StdAwk awk;
int ret = awk.open ();
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
{
QSE::StdAwk::loc_t loc = awk.getErrorLocation();
print_error (loc, awk.getErrorMessage());
}
awk.close ();
return ret;
}
int qse_main (int argc, qse_achar_t* argv[])
{
#if defined(_WIN32)
char locale[100];
UINT codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP (CP_UTF8);*/
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
}
else
{
sprintf (locale, ".%u", (unsigned int)codepage);
setlocale (LC_ALL, locale);
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
}
#if defined(QSE_CHAR_IS_MCHAR)
# define xcout std::cout
#else
setlocale (LC_ALL, "");
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
# define xcout std::wcout
#endif
return qse_runmain (argc,argv,awk_main);
struct MyAwk: public QSE::StdAwk
{
~MyAwk () { QSE::StdAwk::close (); }
};
int main (int argc, char* argv[])
{
MyAwk awk;
MyAwk::Value r;
MyAwk::SourceString in (QSE_T("BEGIN { print \"hello, world\" }"));
if (awk.open () <= -1 || // initialize an awk object
awk.addArgument (QSE_T("awk21")) <= -1 || // set ARGV[0]
awk.parse (in, MyAwk::Source::NONE) == QSE_NULL || // parse the script
awk.loop (&r) <= -1) goto oops;
// no need to close anything since the destructor performs it
return 0;
oops:
xcout << QSE_T("ERR: ") << awk.getErrorMessage() << std::endl; \
return -1; \
}

View File

@ -40,63 +40,36 @@ static void print_error (
static int run_awk (QSE::StdAwk& awk)
{
QSE::StdAwk::Run* run;
// ARGV[0]
if (awk.addArgument (QSE_T("awk05")) <= -1) return -1;
// ARGV[1] and/or the first console input file
if (awk.addArgument (QSE_T("Makefile")) <= -1) return -1;
const qse_char_t* script = QSE_T(
"function add (a, b) { return a + b }\n"
"function mul (a, b) { return a * b }\n"
"function div (a, b) { return a / b }\n"
"function sine (a) { return sin(a) }\n"
"BEGIN { print \">> PRINT ALL LINES WHOSE LENGTH IS GREATER THAN 0\"; }\n"
"length($0) > 0 { print $0; count++; }\n"
"END { print \">> TOTAL\", count, \"LINES\"; }\n"
);
QSE::StdAwk::SourceString in (script);
QSE::StdAwk::SourceFile out (QSE_T("awk06.out"));
QSE::StdAwk::SourceFile out (QSE_T("awk05.out"));
// parse the script and deparse it to awk06.out
run = awk.parse (in, out);
if (run == QSE_NULL) return -1;
// parse the script string and deparse it to awk05.out.
if (awk.parse (in, out) == QSE_NULL) return -1;
QSE::StdAwk::Value arg[2];
if (arg[0].setInt (run, -20) <= -1) return -1;
if (arg[1].setStr (run, QSE_T("51")) <= -1) return -1;
// ret = add (-20, 51)
QSE::StdAwk::Value ret;
if (awk.call (QSE_T("add"), &ret, arg, 2) <= -1) return -1;
// ret = mul (ret, 51);
arg[0] = ret;
if (awk.call (QSE_T("mul"), &ret, arg, 2) <= -1) return -1;
// ret = div (ret, 2);
arg[0] = ret;
if (arg[1].setFlt (run, 2) <= -1) return -1;
if (awk.call (QSE_T("div"), &ret, arg, 2) <= -1) return -1;
// output the result in various types
qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)ret.toInt());
qse_printf (QSE_T(" (flt) [%Lf]\n"), (long double)ret.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), ret.toStr(QSE_NULL));
// ret = sine (ret);
arg[0] = ret;
if (awk.call (QSE_T("sine"), &ret, arg, 1) <= -1) return -1;
// output the result in various types
qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)ret.toInt());
qse_printf (QSE_T(" (flt) [%Lf]\n"), (long double)ret.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), ret.toStr(QSE_NULL));
return 0;
QSE::StdAwk::Value r;
// execute the BEGIN, pattern-action, END blocks.
return awk.loop (&r);
}
static int awk_main (int argc, qse_char_t* argv[])
{
QSE::StdAwk awk;
int ret = awk.open();
int ret = awk.open ();
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
{
QSE::StdAwk::loc_t loc = awk.getErrorLocation();
@ -104,7 +77,7 @@ static int awk_main (int argc, qse_char_t* argv[])
}
awk.close ();
return -1;
return ret;
}
int qse_main (int argc, qse_achar_t* argv[])
@ -127,5 +100,6 @@ int qse_main (int argc, qse_achar_t* argv[])
setlocale (LC_ALL, "");
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
#endif
return qse_runmain (argc,argv,awk_main);
}

View File

@ -28,7 +28,6 @@
# include <windows.h>
#endif
static void print_error (
const QSE::StdAwk::loc_t& loc, const QSE::StdAwk::char_t* msg)
{
@ -43,88 +42,50 @@ static int run_awk (QSE::StdAwk& awk)
{
QSE::StdAwk::Run* run;
QSE::StdAwk::SourceString in (QSE_T(
"function pa (x) {\n"
" @reset ret;\n"
" for (i in x) { print i, \"=>\", x[i]; ret += x[i]; }\n"
" return ret + FOO++;\n"
"}\n"
"function pb (x) {\n"
" @reset ret;\n"
" for (i in x) { ret[-i] = -x[i]; }\n"
" return ret;\n"
"}"
));
const qse_char_t* script = QSE_T(
"function add (a, b) { return a + b }\n"
"function mul (a, b) { return a * b }\n"
"function div (a, b) { return a / b }\n"
"function sine (a) { return sin(a) }\n"
);
// add a global variable 'FOO'
int foo = awk.addGlobal (QSE_T("FOO"));
if (foo <= -1) return -1;
QSE::StdAwk::SourceString in (script);
QSE::StdAwk::SourceFile out (QSE_T("awk06.out"));
// parse the script and perform no deparsing
run = awk.parse (in, QSE::StdAwk::Source::NONE);
// parse the script and deparse it to awk06.out
run = awk.parse (in, out);
if (run == QSE_NULL) return -1;
// set 'FOO' to 100000
QSE::StdAwk::Value foov (run);
if (foov.setInt (100000) <= -1) return -1;
if (awk.setGlobal (foo, foov) <= -1) return -1;
QSE::StdAwk::Value arg[2];
if (arg[0].setInt (run, -20) <= -1) return -1;
if (arg[1].setStr (run, QSE_T("51")) <= -1) return -1;
// prepare an indexed parameter
QSE::StdAwk::Value arg[1];
for (int i = 1; i <= 5; i++)
{
if (arg[0].setIndexedInt (run,
QSE::StdAwk::Value::IntIndex(i), i*20) <= -1) return -1;
}
if (arg[0].setIndexedStr (run,
QSE::StdAwk::Value::IntIndex(99), QSE_T("-2345")) <= -1) return -1;
// ret = add (-20, 51)
QSE::StdAwk::Value ret;
if (awk.call (QSE_T("add"), &ret, arg, 2) <= -1) return -1;
QSE::StdAwk::Value dummy;
if (dummy.setStr (run, QSE_T("4567")) <= -1) return -1;
if (arg[0].setIndexedVal (run,
QSE::StdAwk::Value::IntIndex(999), dummy) <= -1) return -1;
// ret = mul (ret, 51);
arg[0] = ret;
if (awk.call (QSE_T("mul"), &ret, arg, 2) <= -1) return -1;
// prepare a variable to hold the return value
QSE::StdAwk::Value r;
// call the 'pa' function
if (awk.call (QSE_T("pa"), &r, arg, 1) <= -1) return -1;
// ret = div (ret, 2);
arg[0] = ret;
if (arg[1].setFlt (run, 2) <= -1) return -1;
if (awk.call (QSE_T("div"), &ret, arg, 2) <= -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(" (flt)[%Lf]\n"), (long double)r.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), r.toStr(QSE_NULL));
qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)ret.toInt());
qse_printf (QSE_T(" (flt) [%Lf]\n"), (long double)ret.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), ret.toStr(QSE_NULL));
// get the value of 'FOO'
if (awk.getGlobal (foo, foov) <= -1) return -1;
qse_printf (QSE_T("FOO: (int) [%lld]\n"), (long long)foov.toInt());
qse_printf (QSE_T(" (flt)[%Lf]\n"), (long double)foov.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), foov.toStr(QSE_NULL));
// ret = sine (ret);
arg[0] = ret;
if (awk.call (QSE_T("sine"), &ret, arg, 1) <= -1) return -1;
// 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.length(), idx.pointer(),
(long long)v.toInt()
);
iter = r.getNextIndex (&idx, iter);
}
// output the result in various types
qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)ret.toInt());
qse_printf (QSE_T(" (flt) [%Lf]\n"), (long double)ret.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), ret.toStr(QSE_NULL));
return 0;
}
@ -135,9 +96,6 @@ static int awk_main (int argc, qse_char_t* argv[])
int ret = awk.open();
// allow returning a map from a function
awk.setTrait (awk.getTrait() | QSE_AWK_FLEXMAP);
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
{

View File

@ -19,402 +19,111 @@
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/opt.h>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/stdio.h>
#include <cstring>
#include <locale.h>
#if defined(_WIN32)
# include <windows.h>
#elif defined(__OS2__)
# define INCL_DOSPROCESS
# include <os2.h>
#else
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
/* these three definitions for doxygen cross-reference */
typedef QSE::StdAwk StdAwk;
typedef QSE::StdAwk::Run Run;
typedef QSE::StdAwk::Value Value;
class MyAwk: public StdAwk
static void print_error (
const QSE::StdAwk::loc_t& loc, const QSE::StdAwk::char_t* msg)
{
public:
MyAwk () { }
~MyAwk () { close (); }
int open ()
{
if (StdAwk::open () <= -1) return -1;
idLastSleep = addGlobal (QSE_T("LAST_SLEEP"));
if (idLastSleep <= -1) goto oops;
/* this is for demonstration only.
* you can use sys::sleep() instead */
if (addFunction (QSE_T("sleep"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sleep) <= -1) goto oops;
if (addFunction (QSE_T("sumintarray"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sumintarray) <= -1) goto oops;
if (addFunction (QSE_T("arrayindices"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::arrayindices) <= -1) goto oops;
return 0;
oops:
StdAwk::close ();
return -1;
}
int sleep (
Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len)
{
if (args[0].isIndexed())
{
run.setError (QSE_AWK_EINVAL);
return -1;
}
long_t x = args[0].toInt();
/*Value 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;
#if defined(_WIN32)
::Sleep ((DWORD)(x * 1000));
return ret.setInt (0);
#elif defined(__OS2__)
::DosSleep ((ULONG)(x * 1000));
return ret.setInt (0);
#else
return ret.setInt (::sleep (x));
#endif
}
int sumintarray (
Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len)
{
// BEGIN {
// for(i=0;i<=10;i++) x[i]=i;
// print sumintarray(x);
// }
long_t x = 0;
if (args[0].isIndexed())
{
Value val(run);
Value::Index idx;
Value::IndexIterator ii;
ii = args[0].getFirstIndex (&idx);
while (ii != ii.END)
{
if (args[0].getIndexed(idx, &val) <= -1) return -1;
x += val.toInt ();
ii = args[0].getNextIndex (&idx, ii);
}
}
else x += args[0].toInt();
return ret.setInt (x);
}
int arrayindices (
Run& run,
Value& ret,
Value* args,
size_t nargs,
const char_t* name,
size_t len)
{
// create another array composed of array indices
// BEGIN {
// for(i=0;i<=10;i++) x[i]=i;
// y=arrayindices(x);
// for (i in y) print y[i];
// }
if (!args[0].isIndexed()) return 0;
Value::Index idx;
Value::IndexIterator ii;
long_t i;
ii = args[0].getFirstIndex (&idx);
for (i = 0; ii != ii.END ; i++)
{
Value::IntIndex iidx (i);
if (ret.setIndexedStr (
iidx, idx.pointer(), idx.length()) <= -1) return -1;
ii = args[0].getNextIndex (&idx, ii);
}
return 0;
}
private:
int idLastSleep;
};
static MyAwk* app_awk = QSE_NULL;
static void print_error (const qse_char_t* fmt, ...)
{
va_list va;
qse_fprintf (QSE_STDERR, QSE_T("ERROR: "));
va_start (va, fmt);
qse_vfprintf (QSE_STDERR, fmt, va);
va_end (va);
}
static void print_error (MyAwk& awk)
{
MyAwk::loc_t loc = awk.getErrorLocation();
if (loc.file)
{
print_error (QSE_T("line %u at %s - %s\n"), (unsigned)loc.line, loc.file, awk.getErrorMessage());
}
if (loc.line > 0 || loc.colm > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu COLUMN %lu\n"), msg, loc.line, loc.colm);
else
{
print_error (QSE_T("line %u - %s\n"), (unsigned)loc.line, awk.getErrorMessage());
}
}
#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);
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
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)
static int run_awk (QSE::StdAwk& awk)
{
int e = errno;
if (app_awk) app_awk->stop ();
errno = e;
}
#endif
QSE::StdAwk::Run* run;
static void set_signal (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
}
QSE::StdAwk::SourceString in (QSE_T(
"function pa (x) {\n"
" @reset ret;\n"
" for (i in x) { print i, \"=>\", x[i]; ret += x[i]; }\n"
" return ret + FOO++;\n"
"}\n"
"function pb (x) {\n"
" @reset ret;\n"
" for (i in x) { ret[-i] = -x[i]; }\n"
" return ret;\n"
"}"
));
static void unset_signal (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, FALSE);
#else
setsignal (SIGINT, SIG_DFL, 1);
#endif
}
// add a global variable 'FOO'
int foo = awk.addGlobal (QSE_T("FOO"));
if (foo <= -1) return -1;
static void print_usage (QSE_FILE* out, const qse_char_t* argv0)
{
qse_fprintf (out, QSE_T("USAGE: %s [options] -f sourcefile [ -- ] [datafile]*\n"), argv0);
qse_fprintf (out, QSE_T(" %s [options] [ -- ] sourcestring [datafile]*\n"), argv0);
qse_fprintf (out, QSE_T("Where options are:\n"));
qse_fprintf (out, QSE_T(" -h print this message\n"));
qse_fprintf (out, QSE_T(" -f sourcefile set the source script file\n"));
qse_fprintf (out, QSE_T(" -d deparsedfile set the deparsing output file\n"));
qse_fprintf (out, QSE_T(" -o outputfile set the console output file\n"));
qse_fprintf (out, QSE_T(" -F string set a field separator(FS)\n"));
}
// parse the script and perform no deparsing
run = awk.parse (in, QSE::StdAwk::Source::NONE);
if (run == QSE_NULL) return -1;
struct cmdline_t
{
qse_char_t* ins;
qse_char_t* inf;
qse_char_t* outf;
qse_char_t* outc;
qse_char_t* fs;
};
// set 'FOO' to 100000
QSE::StdAwk::Value foov (run);
if (foov.setInt (100000) <= -1) return -1;
if (awk.setGlobal (foo, foov) <= -1) return -1;
static int handle_cmdline (
MyAwk& awk, int argc, qse_char_t* argv[], cmdline_t* cmdline)
{
static qse_opt_t opt =
// prepare an indexed parameter
QSE::StdAwk::Value arg[1];
for (int i = 1; i <= 5; i++)
{
QSE_T("hF:f:d:o:"),
QSE_NULL
};
qse_cint_t c;
std::memset (cmdline, 0, QSE_SIZEOF(*cmdline));
while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
{
switch (c)
{
case QSE_T('h'):
print_usage (QSE_STDOUT, argv[0]);
return 0;
case QSE_T('F'):
cmdline->fs = opt.arg;
break;
case QSE_T('f'):
cmdline->inf = opt.arg;
break;
case QSE_T('d'):
cmdline->outf = opt.arg;
break;
case QSE_T('o'):
cmdline->outc = opt.arg;
break;
case QSE_T('?'):
print_error (QSE_T("illegal option - '%c'\n"), opt.opt);
return -1;
case QSE_T(':'):
print_error (QSE_T("bad argument for '%c'\n"), opt.opt);
return -1;
default:
print_usage (QSE_STDERR, argv[0]);
return -1;
}
if (arg[0].setIndexedInt (run,
QSE::StdAwk::Value::IntIndex(i), i*20) <= -1) return -1;
}
if (arg[0].setIndexedStr (run,
QSE::StdAwk::Value::IntIndex(99), QSE_T("-2345")) <= -1) return -1;
if (opt.ind < argc && !cmdline->inf)
cmdline->ins = argv[opt.ind++];
QSE::StdAwk::Value dummy;
if (dummy.setStr (run, QSE_T("4567")) <= -1) return -1;
if (arg[0].setIndexedVal (run,
QSE::StdAwk::Value::IntIndex(999), dummy) <= -1) return -1;
while (opt.ind < argc)
// prepare a variable to hold the return value
QSE::StdAwk::Value r;
// call the 'pa' function
if (awk.call (QSE_T("pa"), &r, arg, 1) <= -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(" (flt)[%Lf]\n"), (long double)r.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), r.toStr(QSE_NULL));
// get the value of 'FOO'
if (awk.getGlobal (foo, foov) <= -1) return -1;
qse_printf (QSE_T("FOO: (int) [%lld]\n"), (long long)foov.toInt());
qse_printf (QSE_T(" (flt)[%Lf]\n"), (long double)foov.toFlt());
qse_printf (QSE_T(" (str) [%s]\n"), foov.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 (awk.addArgument (argv[opt.ind++]) <= -1)
{
print_error (awk);
return -1;
}
}
if (!cmdline->ins && !cmdline->inf)
{
print_usage (QSE_STDERR, argv[0]);
return -1;
}
return 1;
}
static int awk_main_2 (MyAwk& awk, int argc, qse_char_t* argv[])
{
MyAwk::Run* run;
cmdline_t cmdline;
int n;
awk.setTrait (awk.getTrait() | QSE_AWK_EXTRAKWS | QSE_AWK_FLEXMAP | QSE_AWK_RWPIPE);
// ARGV[0]
if (awk.addArgument (QSE_T("awk08")) <= -1)
{
print_error (awk);
return -1;
}
if ((n = handle_cmdline (awk, argc, argv, &cmdline)) <= 0) return n;
MyAwk::Source* in, * out;
MyAwk::SourceString in_str (cmdline.ins);
MyAwk::SourceFile in_file (cmdline.inf);
MyAwk::SourceFile out_file (cmdline.outf);
in = (cmdline.ins)? (MyAwk::Source*)&in_str: (MyAwk::Source*)&in_file;
out = (cmdline.outf)? (MyAwk::Source*)&out_file: &MyAwk::Source::NONE;
run = awk.parse (*in, *out);
if (run == QSE_NULL)
{
print_error (awk);
return -1;
}
if (cmdline.fs)
{
MyAwk::Value fs (run);
if (fs.setStr (cmdline.fs) <= -1)
{
print_error (awk);
return -1;
}
if (awk.setGlobal (QSE_AWK_GBL_FS, fs) <= -1)
{
print_error (awk);
return -1;
}
}
if (cmdline.outc)
{
if (awk.addConsoleOutput (cmdline.outc) <= -1)
{
print_error (awk);
return -1;
}
}
MyAwk::Value ret;
if (awk.loop (&ret) <= -1)
{
print_error (awk);
return -1;
if (r.getIndexed (idx, &v) <= -1) return -1;
qse_printf (QSE_T("\t[%.*s]=>[%lld]\n"),
(int)idx.length(), idx.pointer(),
(long long)v.toInt()
);
iter = r.getNextIndex (&idx, iter);
}
return 0;
@ -422,34 +131,29 @@ static int awk_main_2 (MyAwk& awk, int argc, qse_char_t* argv[])
static int awk_main (int argc, qse_char_t* argv[])
{
MyAwk awk;
QSE::StdAwk awk;
if (awk.open() <= -1)
int ret = awk.open();
// allow returning a map from a function
awk.setTrait (awk.getTrait() | QSE_AWK_FLEXMAP);
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
{
print_error (awk);
return -1;
QSE::StdAwk::loc_t loc = awk.getErrorLocation();
print_error (loc, awk.getErrorMessage());
}
app_awk = &awk;
set_signal ();
int n = awk_main_2 (awk, argc, argv);
unset_signal ();
app_awk = QSE_NULL;
awk.close ();
return n;
return -1;
}
int qse_main (int argc, qse_achar_t* argv[])
{
int ret;
#if defined(_WIN32)
char locale[100];
UINT codepage;
WSADATA wsadata;
codepage = GetConsoleOutputCP();
UINT codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP (CP_UTF8);*/
@ -461,23 +165,9 @@ int qse_main (int argc, qse_achar_t* argv[])
setlocale (LC_ALL, locale);
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
}
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
{
print_error (QSE_T("Failed to start up winsock\n"));
return -1;
}
#else
setlocale (LC_ALL, "");
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
#endif
ret = qse_runmain (argc, argv, awk_main);
#if defined(_WIN32)
WSACleanup ();
#endif
return ret;
return qse_runmain (argc,argv,awk_main);
}

View File

@ -19,23 +19,26 @@
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/stdio.h>
#include <qse/cmn/opt.h>
#include <qse/cmn/main.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/str.h>
#include <qse/cmn/stdio.h>
#include <cstring>
#include <locale.h>
#if defined(_WIN32)
# include <windows.h>
#endif
#include <string>
#if defined(QSE_CHAR_IS_WCHAR)
typedef std::wstring String;
#elif defined(__OS2__)
# define INCL_DOSPROCESS
# include <os2.h>
#else
typedef std::string String;
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
/* these three definitions for doxygen cross-reference */
typedef QSE::StdAwk StdAwk;
typedef QSE::StdAwk::Run Run;
typedef QSE::StdAwk::Value Value;
@ -43,159 +46,410 @@ typedef QSE::StdAwk::Value Value;
class MyAwk: public StdAwk
{
public:
//
// this class overrides console methods to use
// string buffers for console input and output.
//
MyAwk () { }
~MyAwk () { close (); }
void setInput (const char_t* instr)
int open ()
{
this->input = instr;
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
if (StdAwk::open () <= -1) return -1;
idLastSleep = addGlobal (QSE_T("LAST_SLEEP"));
if (idLastSleep <= -1) goto oops;
/* this is for demonstration only.
* you can use sys::sleep() instead */
if (addFunction (QSE_T("sleep"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sleep) <= -1) goto oops;
if (addFunction (QSE_T("sumintarray"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sumintarray) <= -1) goto oops;
if (addFunction (QSE_T("arrayindices"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::arrayindices) <= -1) goto oops;
return 0;
oops:
StdAwk::close ();
return -1;
}
void clearOutput () { this->output.clear (); }
const char_t* getOutput () { return this->output.c_str(); }
protected:
String input; // console input buffer
const char_t* inptr;
const char_t* inend;
String output; // console output buffer
int openConsole (Console& io)
{
return 1; // return open-success
}
int closeConsole (Console& io)
{
return 0; // return success
}
int flushConsole (Console& io)
int sleep (
Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len)
{
// there is nothing to flush since a string buffer
// is used for a console output. just return success.
return 0;
}
int nextConsole (Console& io)
{
// this stripped-down awk doesn't honor the nextfile statement
// or the nextofile statement. just return success.
return 0;
}
ssize_t readConsole (Console& io, char_t* data, size_t size)
{
if (this->inptr >= this->inend) return 0; // EOF
size_t x = qse_strxncpy (data, size, inptr, inend - inptr);
this->inptr += x;
return x;
}
ssize_t writeConsole (Console& io, const char_t* data, size_t size)
{
try { this->output.append (data, size); }
catch (...)
{
((Run*)io)->setError (QSE_AWK_ENOMEM);
return -1;
if (args[0].isIndexed())
{
run.setError (QSE_AWK_EINVAL);
return -1;
}
return size;
long_t x = args[0].toInt();
/*Value 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;
#if defined(_WIN32)
::Sleep ((DWORD)(x * 1000));
return ret.setInt (0);
#elif defined(__OS2__)
::DosSleep ((ULONG)(x * 1000));
return ret.setInt (0);
#else
return ret.setInt (::sleep (x));
#endif
}
int sumintarray (
Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len)
{
// BEGIN {
// for(i=0;i<=10;i++) x[i]=i;
// print sumintarray(x);
// }
long_t x = 0;
if (args[0].isIndexed())
{
Value val(run);
Value::Index idx;
Value::IndexIterator ii;
ii = args[0].getFirstIndex (&idx);
while (ii != ii.END)
{
if (args[0].getIndexed(idx, &val) <= -1) return -1;
x += val.toInt ();
ii = args[0].getNextIndex (&idx, ii);
}
}
else x += args[0].toInt();
return ret.setInt (x);
}
int arrayindices (
Run& run,
Value& ret,
Value* args,
size_t nargs,
const char_t* name,
size_t len)
{
// create another array composed of array indices
// BEGIN {
// for(i=0;i<=10;i++) x[i]=i;
// y=arrayindices(x);
// for (i in y) print y[i];
// }
if (!args[0].isIndexed()) return 0;
Value::Index idx;
Value::IndexIterator ii;
long_t i;
ii = args[0].getFirstIndex (&idx);
for (i = 0; ii != ii.END ; i++)
{
Value::IntIndex iidx (i);
if (ret.setIndexedStr (
iidx, idx.pointer(), idx.length()) <= -1) return -1;
ii = args[0].getNextIndex (&idx, ii);
}
return 0;
}
private:
int idLastSleep;
};
static void print_error (
const MyAwk::loc_t& loc, const MyAwk::char_t* msg)
static MyAwk* app_awk = QSE_NULL;
static void print_error (const qse_char_t* fmt, ...)
{
if (loc.line > 0 || loc.colm > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu COLUMN %lu\n"), msg, loc.line, loc.colm);
else
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
va_list va;
qse_fprintf (QSE_STDERR, QSE_T("ERROR: "));
va_start (va, fmt);
qse_vfprintf (QSE_STDERR, fmt, va);
va_end (va);
}
static int run_awk (MyAwk& awk)
static void print_error (MyAwk& awk)
{
// sample input string
const qse_char_t* instr = QSE_T(
"aardvark 555-5553 1200/300 B\n"
"alpo-net 555-3412 2400/1200/300 A\n"
"barfly 555-7685 1200/300 A\n"
"bites 555-1675 2400/1200/300 A\n"
"camelot 555-0542 300 C\n"
"core 555-2912 1200/300 C\n"
"fooey 555-1234 2400/1200/300 B\n"
"foot 555-6699 1200/300 B\n"
"macfoo 555-6480 1200/300 A\n"
"sdace 555-3430 2400/1200/300 A\n"
"sabafoo 555-2127 1200/300 C\n");
MyAwk::loc_t loc = awk.getErrorLocation();
// ARGV[0]
if (awk.addArgument (QSE_T("awk12")) <= -1) return -1;
// prepare a script to print the second and the first column
MyAwk::SourceString in (QSE_T("{ print $2, $1; }"));
// parse the script.
if (awk.parse (in, MyAwk::Source::NONE) == QSE_NULL) return -1;
MyAwk::Value r;
awk.setInput (instr); // locate the input string
awk.clearOutput (); // clear the output string
int x = awk.loop (&r); // execute the BEGIN, pattern-action, END blocks.
if (x >= 0)
if (loc.file)
{
qse_printf (QSE_T("%s"), awk.getOutput()); // print the console output
qse_printf (QSE_T("-----------------------------\n"));
print_error (QSE_T("line %u at %s - %s\n"), (unsigned)loc.line, loc.file, awk.getErrorMessage());
}
else
{
print_error (QSE_T("line %u - %s\n"), (unsigned)loc.line, awk.getErrorMessage());
}
}
// prepare a string to print lines with A in the fourth column
MyAwk::SourceString in2 (QSE_T("$4 == \"A\" { print $1; }"));
if (awk.parse (in2, MyAwk::Source::NONE) == QSE_NULL) return -1;
#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;
}
awk.setInput (instr);
awk.clearOutput ();
return FALSE;
}
#else
int x = awk.loop (&r);
static int setsignal (int sig, void(*handler)(int), int restart)
{
struct sigaction sa_int;
if (x >= 0)
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_signal (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_signal (void)
{
#ifdef _WIN32
SetConsoleCtrlHandler (stop_run, FALSE);
#else
setsignal (SIGINT, SIG_DFL, 1);
#endif
}
static void print_usage (QSE_FILE* out, const qse_char_t* argv0)
{
qse_fprintf (out, QSE_T("USAGE: %s [options] -f sourcefile [ -- ] [datafile]*\n"), argv0);
qse_fprintf (out, QSE_T(" %s [options] [ -- ] sourcestring [datafile]*\n"), argv0);
qse_fprintf (out, QSE_T("Where options are:\n"));
qse_fprintf (out, QSE_T(" -h print this message\n"));
qse_fprintf (out, QSE_T(" -f sourcefile set the source script file\n"));
qse_fprintf (out, QSE_T(" -d deparsedfile set the deparsing output file\n"));
qse_fprintf (out, QSE_T(" -o outputfile set the console output file\n"));
qse_fprintf (out, QSE_T(" -F string set a field separator(FS)\n"));
}
struct cmdline_t
{
qse_char_t* ins;
qse_char_t* inf;
qse_char_t* outf;
qse_char_t* outc;
qse_char_t* fs;
};
static int handle_cmdline (
MyAwk& awk, int argc, qse_char_t* argv[], cmdline_t* cmdline)
{
static qse_opt_t opt =
{
QSE_T("hF:f:d:o:"),
QSE_NULL
};
qse_cint_t c;
std::memset (cmdline, 0, QSE_SIZEOF(*cmdline));
while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
{
switch (c)
{
qse_printf (QSE_T("%s"), awk.getOutput());
qse_printf (QSE_T("-----------------------------\n"));
case QSE_T('h'):
print_usage (QSE_STDOUT, argv[0]);
return 0;
case QSE_T('F'):
cmdline->fs = opt.arg;
break;
case QSE_T('f'):
cmdline->inf = opt.arg;
break;
case QSE_T('d'):
cmdline->outf = opt.arg;
break;
case QSE_T('o'):
cmdline->outc = opt.arg;
break;
case QSE_T('?'):
print_error (QSE_T("illegal option - '%c'\n"), opt.opt);
return -1;
case QSE_T(':'):
print_error (QSE_T("bad argument for '%c'\n"), opt.opt);
return -1;
default:
print_usage (QSE_STDERR, argv[0]);
return -1;
}
}
return x;
if (opt.ind < argc && !cmdline->inf)
cmdline->ins = argv[opt.ind++];
while (opt.ind < argc)
{
if (awk.addArgument (argv[opt.ind++]) <= -1)
{
print_error (awk);
return -1;
}
}
if (!cmdline->ins && !cmdline->inf)
{
print_usage (QSE_STDERR, argv[0]);
return -1;
}
return 1;
}
static int awk_main_2 (MyAwk& awk, int argc, qse_char_t* argv[])
{
MyAwk::Run* run;
cmdline_t cmdline;
int n;
awk.setTrait (awk.getTrait() | QSE_AWK_EXTRAKWS | QSE_AWK_FLEXMAP | QSE_AWK_RWPIPE);
// ARGV[0]
if (awk.addArgument (QSE_T("awk08")) <= -1)
{
print_error (awk);
return -1;
}
if ((n = handle_cmdline (awk, argc, argv, &cmdline)) <= 0) return n;
MyAwk::Source* in, * out;
MyAwk::SourceString in_str (cmdline.ins);
MyAwk::SourceFile in_file (cmdline.inf);
MyAwk::SourceFile out_file (cmdline.outf);
in = (cmdline.ins)? (MyAwk::Source*)&in_str: (MyAwk::Source*)&in_file;
out = (cmdline.outf)? (MyAwk::Source*)&out_file: &MyAwk::Source::NONE;
run = awk.parse (*in, *out);
if (run == QSE_NULL)
{
print_error (awk);
return -1;
}
if (cmdline.fs)
{
MyAwk::Value fs (run);
if (fs.setStr (cmdline.fs) <= -1)
{
print_error (awk);
return -1;
}
if (awk.setGlobal (QSE_AWK_GBL_FS, fs) <= -1)
{
print_error (awk);
return -1;
}
}
if (cmdline.outc)
{
if (awk.addConsoleOutput (cmdline.outc) <= -1)
{
print_error (awk);
return -1;
}
}
MyAwk::Value ret;
if (awk.loop (&ret) <= -1)
{
print_error (awk);
return -1;
}
return 0;
}
static int awk_main (int argc, qse_char_t* argv[])
{
MyAwk awk;
int ret = awk.open ();
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
if (awk.open() <= -1)
{
MyAwk::loc_t loc = awk.getErrorLocation();
print_error (loc, awk.getErrorMessage());
print_error (awk);
return -1;
}
app_awk = &awk;
set_signal ();
int n = awk_main_2 (awk, argc, argv);
unset_signal ();
app_awk = QSE_NULL;
awk.close ();
return ret;
return n;
}
int qse_main (int argc, qse_achar_t* argv[])
{
int ret;
#if defined(_WIN32)
char locale[100];
UINT codepage = GetConsoleOutputCP();
UINT codepage;
WSADATA wsadata;
codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP (CP_UTF8);*/
@ -207,10 +461,23 @@ int qse_main (int argc, qse_achar_t* argv[])
setlocale (LC_ALL, locale);
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
}
if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0)
{
print_error (QSE_T("Failed to start up winsock\n"));
return -1;
}
#else
setlocale (LC_ALL, "");
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
#endif
return qse_runmain (argc,argv,awk_main);
ret = qse_runmain (argc, argv, awk_main);
#if defined(_WIN32)
WSACleanup ();
#endif
return ret;
}

View File

@ -57,6 +57,7 @@ public:
this->inend = inptr + this->input.length();
}
void clearOutput () { this->output.clear (); }
const char_t* getOutput () { return this->output.c_str(); }
protected:
@ -68,16 +69,6 @@ protected:
int openConsole (Console& io)
{
if (io.getMode() == Console::READ)
{
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
}
else
{
this->output.clear ();
}
return 1; // return open-success
}
@ -95,8 +86,8 @@ protected:
int nextConsole (Console& io)
{
// this stripped-down awk doesn't honor the nextfile statement
// or the nextofile statement. just return failure.
return -1;
// or the nextofile statement. just return success.
return 0;
}
ssize_t readConsole (Console& io, char_t* data, size_t size)
@ -145,30 +136,18 @@ static int run_awk (MyAwk& awk)
"sdace 555-3430 2400/1200/300 A\n"
"sabafoo 555-2127 1200/300 C\n");
const qse_char_t* instr2 = QSE_T(
"aardvark 555-5553 1200/300 A\n"
"alpo-net 555-3412 2400/1200/300 B\n"
"barfly 555-7685 1200/300 C\n"
"bites 555-1675 2400/1200/300 A\n"
"camelot 555-0542 300 C\n"
"core 555-2912 1200/300 B\n"
"fooey 555-1234 2400/1200/300 A\n"
"foot 555-6699 1200/300 A\n"
"macfoo 555-6480 1200/300 B\n"
"sdace 555-3430 2400/1200/300 B\n"
"sabafoo 555-2127 1200/300 A\n");
// ARGV[0]
if (awk.addArgument (QSE_T("awk13")) <= -1) return -1;
if (awk.addArgument (QSE_T("awk12")) <= -1) return -1;
// prepare a string to print lines with A in the fourth column
MyAwk::SourceString in (QSE_T("$4 == \"A\" { print $2, $1, $3; }"));
// prepare a script to print the second and the first column
MyAwk::SourceString in (QSE_T("{ print $2, $1; }"));
// parse the script.
if (awk.parse (in, MyAwk::Source::NONE) == QSE_NULL) return -1;
MyAwk::Value r;
awk.setInput (instr); // locate the input string
awk.clearOutput (); // clear the output string
int x = awk.loop (&r); // execute the BEGIN, pattern-action, END blocks.
if (x >= 0)
@ -176,11 +155,12 @@ static int run_awk (MyAwk& awk)
qse_printf (QSE_T("%s"), awk.getOutput()); // print the console output
qse_printf (QSE_T("-----------------------------\n"));
awk.setInput (instr2);
// prepare a string to print lines with A in the fourth column
MyAwk::SourceString in2 (QSE_T("$4 == \"A\" { print $1; }"));
if (awk.parse (in2, MyAwk::Source::NONE) == QSE_NULL) return -1;
// reset the runtime context so that the next loop() method
// is performed over a new console stream.
if (awk.resetRunContext() == QSE_NULL) return -1;
awk.setInput (instr);
awk.clearOutput ();
int x = awk.loop (&r);

View File

@ -40,31 +40,35 @@ typedef QSE::StdAwk StdAwk;
typedef QSE::StdAwk::Run Run;
typedef QSE::StdAwk::Value Value;
class MyConsoleHandler: public StdAwk::Console::Handler
class MyAwk: public StdAwk
{
public:
// this class defines a console handler that can be
// registered into an awk object.
//
// this class overrides console methods to use
// string buffers for console input and output.
//
MyAwk () { }
~MyAwk () { close (); }
void setInput (const StdAwk::char_t* instr)
void setInput (const char_t* instr)
{
this->input = instr;
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
}
const StdAwk::char_t* getOutput () { return this->output.c_str(); }
const char_t* getOutput () { return this->output.c_str(); }
protected:
String input; // console input buffer
const StdAwk::char_t* inptr;
const StdAwk::char_t* inend;
const char_t* inptr;
const char_t* inend;
String output; // console output buffer
int open (StdAwk::Console& io)
int openConsole (Console& io)
{
if (io.getMode() == StdAwk::Console::READ)
if (io.getMode() == Console::READ)
{
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
@ -77,25 +81,25 @@ protected:
return 1; // return open-success
}
int close (StdAwk::Console& io)
int closeConsole (Console& io)
{
return 0; // return success
}
int flush (StdAwk::Console& io)
int flushConsole (Console& io)
{
// there is nothing to flush since a string buffer
// is used for a console output. just return success.
return 0;
}
int next (StdAwk::Console& io)
int nextConsole (Console& io)
{
// this stripped-down awk doesn't honor the nextfile statement
// or the nextofile statement. just return failure.
return -1;
}
ssize_t read (StdAwk::Console& io, StdAwk::char_t* data, size_t size)
ssize_t readConsole (Console& io, char_t* data, size_t size)
{
if (this->inptr >= this->inend) return 0; // EOF
size_t x = qse_strxncpy (data, size, inptr, inend - inptr);
@ -103,12 +107,12 @@ protected:
return x;
}
ssize_t write (StdAwk::Console& io, const StdAwk::char_t* data, size_t size)
ssize_t writeConsole (Console& io, const char_t* data, size_t size)
{
try { this->output.append (data, size); }
catch (...)
{
((StdAwk::Run*)io)->setError (QSE_AWK_ENOMEM);
((Run*)io)->setError (QSE_AWK_ENOMEM);
return -1;
}
return size;
@ -116,7 +120,7 @@ protected:
};
static void print_error (
const StdAwk::loc_t& loc, const StdAwk::char_t* msg)
const MyAwk::loc_t& loc, const MyAwk::char_t* msg)
{
if (loc.line > 0 || loc.colm > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu COLUMN %lu\n"), msg, loc.line, loc.colm);
@ -125,7 +129,7 @@ static void print_error (
}
static int run_awk (StdAwk& awk)
static int run_awk (MyAwk& awk)
{
// sample input string
const qse_char_t* instr = QSE_T(
@ -155,26 +159,24 @@ static int run_awk (StdAwk& awk)
"sabafoo 555-2127 1200/300 A\n");
// ARGV[0]
if (awk.addArgument (QSE_T("awk14")) <= -1) return -1;
if (awk.addArgument (QSE_T("awk13")) <= -1) return -1;
// prepare a string to print lines with A in the fourth column
StdAwk::SourceString in (QSE_T("$4 == \"A\" { print $2, $1, $3; }"));
MyAwk::SourceString in (QSE_T("$4 == \"A\" { print $2, $1, $3; }"));
// parse the script.
if (awk.parse (in, StdAwk::Source::NONE) == QSE_NULL) return -1;
StdAwk::Value r;
if (awk.parse (in, MyAwk::Source::NONE) == QSE_NULL) return -1;
MyAwk::Value r;
MyConsoleHandler* mch = (MyConsoleHandler*)awk.getConsoleHandler();
mch->setInput (instr); // locate the input string
awk.setInput (instr); // locate the input string
int x = awk.loop (&r); // execute the BEGIN, pattern-action, END blocks.
if (x >= 0)
{
qse_printf (QSE_T("%s"), mch->getOutput()); // print the console output
qse_printf (QSE_T("%s"), awk.getOutput()); // print the console output
qse_printf (QSE_T("-----------------------------\n"));
mch->setInput (instr2);
awk.setInput (instr2);
// reset the runtime context so that the next loop() method
// is performed over a new console stream.
@ -184,7 +186,7 @@ static int run_awk (StdAwk& awk)
if (x >= 0)
{
qse_printf (QSE_T("%s"), mch->getOutput());
qse_printf (QSE_T("%s"), awk.getOutput());
qse_printf (QSE_T("-----------------------------\n"));
}
}
@ -194,20 +196,14 @@ static int run_awk (StdAwk& awk)
static int awk_main (int argc, qse_char_t* argv[])
{
MyConsoleHandler mch;
StdAwk awk;
MyAwk awk;
int ret = awk.open ();
if (ret >= 0)
{
awk.setConsoleHandler (&mch);
ret = run_awk (awk);
}
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)
{
StdAwk::loc_t loc = awk.getErrorLocation();
MyAwk::loc_t loc = awk.getErrorLocation();
print_error (loc, awk.getErrorMessage());
}

240
qse/samples/awk/awk28.cpp Normal file
View File

@ -0,0 +1,240 @@
/*
* $Id$
*
Copyright 2006-2012 Chung, Hyung-Hwan.
This file is part of QSE.
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
QSE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
*/
#include <qse/awk/StdAwk.hpp>
#include <qse/cmn/stdio.h>
#include <qse/cmn/main.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/str.h>
#include <locale.h>
#if defined(_WIN32)
# include <windows.h>
#endif
#include <string>
#if defined(QSE_CHAR_IS_WCHAR)
typedef std::wstring String;
#else
typedef std::string String;
#endif
typedef QSE::StdAwk StdAwk;
typedef QSE::StdAwk::Run Run;
typedef QSE::StdAwk::Value Value;
class MyConsoleHandler: public StdAwk::Console::Handler
{
public:
// this class defines a console handler that can be
// registered into an awk object.
void setInput (const StdAwk::char_t* instr)
{
this->input = instr;
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
}
const StdAwk::char_t* getOutput () { return this->output.c_str(); }
protected:
String input; // console input buffer
const StdAwk::char_t* inptr;
const StdAwk::char_t* inend;
String output; // console output buffer
int open (StdAwk::Console& io)
{
if (io.getMode() == StdAwk::Console::READ)
{
this->inptr = this->input.c_str();
this->inend = inptr + this->input.length();
}
else
{
this->output.clear ();
}
return 1; // return open-success
}
int close (StdAwk::Console& io)
{
return 0; // return success
}
int flush (StdAwk::Console& io)
{
// there is nothing to flush since a string buffer
// is used for a console output. just return success.
return 0;
}
int next (StdAwk::Console& io)
{
// this stripped-down awk doesn't honor the nextfile statement
// or the nextofile statement. just return failure.
return -1;
}
ssize_t read (StdAwk::Console& io, StdAwk::char_t* data, size_t size)
{
if (this->inptr >= this->inend) return 0; // EOF
size_t x = qse_strxncpy (data, size, inptr, inend - inptr);
this->inptr += x;
return x;
}
ssize_t write (StdAwk::Console& io, const StdAwk::char_t* data, size_t size)
{
try { this->output.append (data, size); }
catch (...)
{
((StdAwk::Run*)io)->setError (QSE_AWK_ENOMEM);
return -1;
}
return size;
}
};
static void print_error (
const StdAwk::loc_t& loc, const StdAwk::char_t* msg)
{
if (loc.line > 0 || loc.colm > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu COLUMN %lu\n"), msg, loc.line, loc.colm);
else
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
static int run_awk (StdAwk& awk)
{
// sample input string
const qse_char_t* instr = QSE_T(
"aardvark 555-5553 1200/300 B\n"
"alpo-net 555-3412 2400/1200/300 A\n"
"barfly 555-7685 1200/300 A\n"
"bites 555-1675 2400/1200/300 A\n"
"camelot 555-0542 300 C\n"
"core 555-2912 1200/300 C\n"
"fooey 555-1234 2400/1200/300 B\n"
"foot 555-6699 1200/300 B\n"
"macfoo 555-6480 1200/300 A\n"
"sdace 555-3430 2400/1200/300 A\n"
"sabafoo 555-2127 1200/300 C\n");
const qse_char_t* instr2 = QSE_T(
"aardvark 555-5553 1200/300 A\n"
"alpo-net 555-3412 2400/1200/300 B\n"
"barfly 555-7685 1200/300 C\n"
"bites 555-1675 2400/1200/300 A\n"
"camelot 555-0542 300 C\n"
"core 555-2912 1200/300 B\n"
"fooey 555-1234 2400/1200/300 A\n"
"foot 555-6699 1200/300 A\n"
"macfoo 555-6480 1200/300 B\n"
"sdace 555-3430 2400/1200/300 B\n"
"sabafoo 555-2127 1200/300 A\n");
// ARGV[0]
if (awk.addArgument (QSE_T("awk14")) <= -1) return -1;
// prepare a string to print lines with A in the fourth column
StdAwk::SourceString in (QSE_T("$4 == \"A\" { print $2, $1, $3; }"));
// parse the script.
if (awk.parse (in, StdAwk::Source::NONE) == QSE_NULL) return -1;
StdAwk::Value r;
MyConsoleHandler* mch = (MyConsoleHandler*)awk.getConsoleHandler();
mch->setInput (instr); // locate the input string
int x = awk.loop (&r); // execute the BEGIN, pattern-action, END blocks.
if (x >= 0)
{
qse_printf (QSE_T("%s"), mch->getOutput()); // print the console output
qse_printf (QSE_T("-----------------------------\n"));
mch->setInput (instr2);
// reset the runtime context so that the next loop() method
// is performed over a new console stream.
if (awk.resetRunContext() == QSE_NULL) return -1;
int x = awk.loop (&r);
if (x >= 0)
{
qse_printf (QSE_T("%s"), mch->getOutput());
qse_printf (QSE_T("-----------------------------\n"));
}
}
return x;
}
static int awk_main (int argc, qse_char_t* argv[])
{
MyConsoleHandler mch;
StdAwk awk;
int ret = awk.open ();
if (ret >= 0)
{
awk.setConsoleHandler (&mch);
ret = run_awk (awk);
}
if (ret <= -1)
{
StdAwk::loc_t loc = awk.getErrorLocation();
print_error (loc, awk.getErrorMessage());
}
awk.close ();
return ret;
}
int qse_main (int argc, qse_achar_t* argv[])
{
#if defined(_WIN32)
char locale[100];
UINT codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP (CP_UTF8);*/
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
}
else
{
sprintf (locale, ".%u", (unsigned int)codepage);
setlocale (LC_ALL, locale);
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
}
#else
setlocale (LC_ALL, "");
qse_setdflcmgrbyid (QSE_CMGR_SLMB);
#endif
return qse_runmain (argc,argv,awk_main);
}