changed Source IO model in Awk

This commit is contained in:
hyung-hwan 2009-07-10 06:46:14 +00:00
parent 1d88a17c7c
commit 852a51ae75
9 changed files with 1049 additions and 876 deletions

View File

@ -1,5 +1,5 @@
/*
* $Id: Awk.hpp 225 2009-07-08 13:01:45Z hyunghwan.chung $
* $Id: Awk.hpp 226 2009-07-09 12:46:14Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
@ -55,137 +55,67 @@ public:
typedef qse_awk_rio_cmd_t rio_cmd_t;
/**
* Represents the source code I/O context for Awk::parse.
* An instance of Awk::Source is passed to Awk::openSource,
* Awk::readSource, Awk::writeSource, Awk::closeSource
* when Awk::parse calls them to read the source code and write the
* internal parse tree. It indicates the mode of the context and
* provides space for data that may be needed for the I/O operation.
*/
class Source
{
public:
friend class Awk;
/** Mode of source code I/O. */
enum Mode
{
READ, /**< source code read. */
WRITE /**< source code write. */
};
protected:
Source (Mode mode);
class Data
{
public:
friend class Awk;
public:
/**
* Returns the mode of the source code I/O.
* You may call this method in Awk::openSource and
* Awk::closeSource to determine the mode as shown in
* the example below. This method always returns Source::READ
* and Source::WRITE respectively when called from
* Awk::readSource and Awk::writeSource.
*
* @code
* int openSource (Source& io)
* {
* if (io.getMode() == Source::READ)
* {
* // open for reading
* return 1;
* }
* else (io.getMode() == Source::WRITE)
* {
* // open for writing
* return 1;
* }
* return -1;
* }
*
* int closeSource (Source& io)
* {
* if (io.getMode() == Source::READ)
* {
* // close for reading
* return 0;
* }
* else (io.getMode() == Source::WRITE)
* {
* // close for writing
* return 0;
* }
* return -1;
* }
* @endcode
*
* @return Awk::Source::READ or Awk::Source::WRITE
*/
Mode getMode() const;
protected:
Data (Awk* awk, Mode mode):
awk (awk), mode (mode), handle (QSE_NULL) {}
/**
* Returns the value set with Source::setHandle.
* QSE_NULL is returned if it has not been set with
* Source::setHandle. You usually call this method
* from Awk::readSource, Awk::writeSource, and
* Awk::closeSource to get the value set in Awk::openSource
* as shown in the example below.
*
* @code
* int closeSource (Source& io)
* {
* if (io.getMode() == Source::READ)
* {
* fclose ((FILE*)io.getHandle());
* return 0;
* }
* else (io.getMode() == Source::WRITE)
* {
* fclose ((FILE*)io.getHandle());
* return 0;
* }
* return -1;
* }
* @endcode
*
* @return an arbitrary value of type void* set with
* Source::setHandle() or QSE_NULL
*/
const void* getHandle () const;
public:
Mode getMode() const
{
return mode;
}
/**
* Sets the handle value. Source::getHandle can retrieve
* the value set with Source::setHandle. You usually call
* this from Awk::openSource as shown in the example below.
*
* <pre>
* int openSource (Source& io)
* {
* if (io.getMode() == Source::READ)
* {
* FILE* fp = fopen ("t.awk", "r");
* if (fp == NULL) return -1;
* io.setHandle (fp);
* return 1;
* }
* else (io.getMode() == Source::WRITE)
* {
* FILE* fp = fopen ("t.out", "w");
* if (fp == NULL) return -1;
* io.setHandle (fp);
* return 1;
* }
* return -1;
* }
* </pre>
*
* @param handle an arbitrary value of the type void*
*/
void setHandle (void* handle);
const void* getHandle () const
{
return handle;
}
protected:
Mode mode;
void* handle;
void setHandle (void* handle)
{
this->handle = handle;
}
operator Awk* () const
{
return awk;
}
operator awk_t* () const
{
return awk->awk;
}
protected:
Awk* awk;
Mode mode;
void* handle;
};
Source () {}
virtual ~Source () {}
virtual int open (Data& io) = 0;
virtual int close (Data& io) = 0;
virtual ssize_t read (Data& io, char_t* buf, size_t len) = 0;
virtual ssize_t write (Data& io, char_t* buf, size_t len) = 0;
private:
Source (const Source&);
Source& operator= (const Source&);
};
class Run;
@ -212,6 +142,10 @@ public:
protected:
Run* run;
rio_arg_t* riod;
private:
RIOBase (const RIOBase&);
RIOBase& operator= (const RIOBase&);
};
/**
@ -819,7 +753,7 @@ public:
*
* @return a Run object on success, QSE_NULL on failure
*/
virtual Awk::Run* parse ();
virtual Awk::Run* parse (Source* in, Source* out);
/**
* Executes the BEGIN block, pattern-action blocks, and the END block.
@ -900,77 +834,6 @@ public:
protected:
virtual int dispatchFunction (Run* run, const char_t* name, size_t len);
/**
* @name Source code I/O handlers
* A subclass should override the following methods to support the
* source code input and output. The awk interpreter calls the
* following methods when the parse method is invoked.
*
* To read the source code, Awk::parse calls Awk::openSource,
* Awk::readSource, and Awk::closeSource as shown in the diagram below.
* Any failures wll cause Awk::parse to return an error.
*
* \image html awk-srcio-read.png
*
* Awk::parse is able to write back the internal parse tree by
* calling Awk::openSource, Awk::writeSource, and Awk::closeSource
* as shown in the diagram below. Any failures will cause Awk::parse
* to return an error.
*
* \image html awk-srcio-write.png
*
* Awk::parse passes an instance of Awk::Source when invoking these
* methods. You can determine the context of the method by calling
* Awk::Source::getMode and inspecting its return value. You may use
* Awk::Source::getHandle and Awk::Source::setHandle to store and
* retrieve the data information needed to complete the operation.
*/
/*@{*/
/**
* Opens the source code stream.
* A subclass should override this method. It should return 1 on
* success, -1 on failure, and 0 if the opening operation
* is successful but has reached the end of the stream.
* @param io I/O context passed from Awk::parse
* @see Awk::Source::getMode, Awk::Source::setHandle
*/
virtual int openSource (Source& io) = 0;
/**
* Closes the source code stream.
* A subclass should override this method. It should return 0 on
* success and -1 on failure.
* @param io I/O context passed from Awk::parse
* @see Awk::Source::getMode, Awk::Source::getHandle
*/
virtual int closeSource (Source& io) = 0;
/**
* Reads from the source code input stream.
* A subclass should override this method. It should return 0 when
* it has reached the end of the stream and -1 on falure.
* When it has data to return, it should read characters not longer
* than len characters, fill the buffer pointed at by buf with them,
* and return the number of the charaters read.
* @param io I/O context passed from Awk::parse
* @param buf pointer to a character buffer
* @param len number of characters in the buffer
*/
virtual ssize_t readSource (Source& io, char_t* buf, size_t len) = 0;
/**
* Writes to the source code output stream.
* A subclass should override this method. It should return 0 when
* it has reachedthe end of the stream and -1 on failure.
* It should write up to len characters from the buffer pointed at
* by buf and return the number of characters written.
* @param io I/O context passed from Awk::parse
* @param buf pointer to a character buffer
* @param len size of the buffer in characters
*/
virtual ssize_t writeSource (Source& io, char_t* buf, size_t len) = 0;
/*@}*/
/**
* @name Pipe I/O handlers
* Pipe operations are achieved through the following methods.
@ -1018,9 +881,9 @@ protected:
const char_t* fmt, va_list arg) = 0;
// static glue members for various handlers
static ssize_t sourceReader (
static ssize_t readSource (
awk_t* awk, qse_awk_sio_cmd_t cmd, char_t* data, size_t count);
static ssize_t sourceWriter (
static ssize_t writeSource (
awk_t* awk, qse_awk_sio_cmd_t cmd, char_t* data, size_t count);
static ssize_t pipeHandler (
@ -1050,8 +913,11 @@ protected:
errstr_t dflerrstr;
map_t* functionMap;
Source sourceIn;
Source sourceOut;
Source::Data sourceIn;
Source::Data sourceOut;
Source* sourceReader;
Source* sourceWriter;
ErrorNumber errnum;
size_t errlin;

View File

@ -1,5 +1,5 @@
/*
* $Id: StdAwk.hpp 224 2009-07-07 13:05:10Z hyunghwan.chung $
* $Id: StdAwk.hpp 226 2009-07-09 12:46:14Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
@ -24,6 +24,8 @@
/**
* @example awk05.cpp
* This program demonstrates how to embed QSE::StdAwk in C++.
* @example awk06.cpp
* This program demonstrates how to embed QSE::StdAwk in C++.
*/
/////////////////////////////////
@ -38,6 +40,35 @@ QSE_BEGIN_NAMESPACE(QSE)
class StdAwk: public Awk
{
public:
class SourceFile: public Source
{
public:
SourceFile (const char_t* name): name (name) {}
int open (Data& io);
int close (Data& io);
ssize_t read (Data& io, char_t* buf, size_t len);
ssize_t write (Data& io, char_t* buf, size_t len);
protected:
const char_t* name;
};
class SourceString: public Source
{
public:
SourceString (const char_t* str): str (str) {}
int open (Data& io);
int close (Data& io);
ssize_t read (Data& io, char_t* buf, size_t len);
ssize_t write (Data& io, char_t* buf, size_t len);
protected:
const char_t* str;
const char_t* ptr;
};
int open ();
void close ();
@ -46,7 +77,6 @@ public:
virtual void clearConsoleOutputs ();
protected:
// intrinsic functions
int sin (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len);

View File

@ -1,5 +1,5 @@
/*
* $Id: Awk.cpp 225 2009-07-08 13:01:45Z hyunghwan.chung $
* $Id: Awk.cpp 226 2009-07-09 12:46:14Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
@ -39,25 +39,6 @@ struct rxtn_t
Awk::Run* run;
};
Awk::Source::Source (Mode mode): mode (mode), handle (QSE_NULL)
{
}
Awk::Source::Mode Awk::Source::getMode () const
{
return this->mode;
}
const void* Awk::Source::getHandle () const
{
return this->handle;
}
void Awk::Source::setHandle (void* handle)
{
this->handle = handle;
}
//////////////////////////////////////////////////////////////////
// Awk::RIO
//////////////////////////////////////////////////////////////////
@ -1067,7 +1048,7 @@ int Awk::Run::getGlobal (int id, Argument& gbl) const
//////////////////////////////////////////////////////////////////
Awk::Awk () throw (): awk (QSE_NULL), functionMap (QSE_NULL),
sourceIn (Source::READ), sourceOut (Source::WRITE),
sourceIn (this, Source::READ), sourceOut (this, Source::WRITE),
errnum (ERR_NOERR), errlin (0), runCallback (false),
runctx (this)
@ -1329,15 +1310,18 @@ int Awk::unsetAllWords ()
return qse_awk_setword (awk, QSE_NULL, 0, QSE_NULL, 0);
}
Awk::Run* Awk::parse ()
Awk::Run* Awk::parse (Source* in, Source* out)
{
QSE_ASSERT (awk != QSE_NULL);
fini_runctx ();
sourceReader = in;
sourceWriter = out;
qse_awk_sio_t sio;
sio.in = sourceReader;
sio.out = sourceWriter;
sio.in = readSource;
sio.out = (sourceWriter == QSE_NULL)? QSE_NULL: writeSource;
int n = qse_awk_parse (awk, &sio);
if (n <= -1)
@ -1657,7 +1641,7 @@ void Awk::onStatement (Run& run, size_t line)
{
}
Awk::ssize_t Awk::sourceReader (
Awk::ssize_t Awk::readSource (
awk_t* awk, qse_awk_sio_cmd_t cmd, char_t* data, size_t count)
{
xtn_t* xtn = (xtn_t*) QSE_XTN (awk);
@ -1665,19 +1649,17 @@ Awk::ssize_t Awk::sourceReader (
switch (cmd)
{
case QSE_AWK_SIO_OPEN:
return xtn->awk->openSource (xtn->awk->sourceIn);
return xtn->awk->sourceReader->open (xtn->awk->sourceIn);
case QSE_AWK_SIO_CLOSE:
return xtn->awk->closeSource (xtn->awk->sourceIn);
return xtn->awk->sourceReader->close (xtn->awk->sourceIn);
case QSE_AWK_SIO_READ:
return xtn->awk->readSource (xtn->awk->sourceIn, data, count);
case QSE_AWK_SIO_WRITE:
return xtn->awk->sourceReader->read (xtn->awk->sourceIn, data, count);
default:
return -1;
}
return -1;
}
Awk::ssize_t Awk::sourceWriter (
Awk::ssize_t Awk::writeSource (
awk_t* awk, qse_awk_sio_cmd_t cmd, char_t* data, size_t count)
{
xtn_t* xtn = (xtn_t*) QSE_XTN (awk);
@ -1685,16 +1667,14 @@ Awk::ssize_t Awk::sourceWriter (
switch (cmd)
{
case QSE_AWK_SIO_OPEN:
return xtn->awk->openSource (xtn->awk->sourceOut);
return xtn->awk->sourceWriter->open (xtn->awk->sourceOut);
case QSE_AWK_SIO_CLOSE:
return xtn->awk->closeSource (xtn->awk->sourceOut);
return xtn->awk->sourceWriter->close (xtn->awk->sourceOut);
case QSE_AWK_SIO_WRITE:
return xtn->awk->writeSource (xtn->awk->sourceOut, data, count);
case QSE_AWK_SIO_READ:
return xtn->awk->sourceWriter->write (xtn->awk->sourceOut, data, count);
default:
return -1;
}
return -1;
}
Awk::ssize_t Awk::pipeHandler (

View File

@ -1,5 +1,5 @@
/*
* $Id: StdAwk.cpp 225 2009-07-08 13:01:45Z hyunghwan.chung $
* $Id: StdAwk.cpp 226 2009-07-09 12:46:14Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
@ -81,24 +81,6 @@ void StdAwk::close ()
Awk::close ();
}
int StdAwk::addConsoleOutput (const char_t* arg, size_t len)
{
QSE_ASSERT (awk != QSE_NULL);
int n = ofile.add (awk, arg, len);
if (n <= -1) setError (ERR_NOMEM);
return n;
}
int StdAwk::addConsoleOutput (const char_t* arg)
{
return addConsoleOutput (arg, qse_strlen(arg));
}
void StdAwk::clearConsoleOutputs ()
{
ofile.clear (awk);
}
int StdAwk::sin (Run& run, Return& ret, const Argument* args, size_t nargs,
const char_t* name, size_t len)
{
@ -300,22 +282,22 @@ int StdAwk::openPipe (Pipe& io)
{
Awk::Pipe::Mode mode = io.getMode();
qse_pio_t* pio = QSE_NULL;
int flags;
int flags = QSE_PIO_TEXT | QSE_PIO_SHELL;
switch (mode)
{
case Awk::Pipe::READ:
/* TODO: should we specify ERRTOOUT? */
flags = QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT;
flags |= QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT;
break;
case Awk::Pipe::WRITE:
flags = QSE_PIO_WRITEIN;
flags |= QSE_PIO_WRITEIN;
break;
case Awk::Pipe::RW:
flags = QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT |
QSE_PIO_WRITEIN;
flags |= QSE_PIO_READOUT |
QSE_PIO_ERRTOOUT |
QSE_PIO_WRITEIN;
break;
}
@ -323,7 +305,7 @@ int StdAwk::openPipe (Pipe& io)
((Awk*)io)->getMmgr(),
0,
io.getName(),
flags|QSE_PIO_TEXT|QSE_PIO_SHELL
flags
);
if (pio == QSE_NULL) return -1;
@ -352,26 +334,25 @@ int StdAwk::flushPipe (Pipe& io)
return qse_pio_flush ((qse_pio_t*)io.getHandle(), QSE_PIO_IN);
}
// file io handlers
int StdAwk::openFile (File& io)
{
Awk::File::Mode mode = io.getMode();
qse_fio_t* fio = QSE_NULL;
int flags;
int flags = QSE_FIO_TEXT;
switch (mode)
{
case Awk::File::READ:
flags = QSE_FIO_READ;
flags |= QSE_FIO_READ;
break;
case Awk::File::WRITE:
flags = QSE_FIO_WRITE |
QSE_FIO_CREATE |
QSE_FIO_TRUNCATE;
flags |= QSE_FIO_WRITE |
QSE_FIO_CREATE |
QSE_FIO_TRUNCATE;
break;
case Awk::File::APPEND:
flags = QSE_FIO_APPEND |
QSE_FIO_CREATE;
flags |= QSE_FIO_APPEND |
QSE_FIO_CREATE;
break;
}
@ -379,7 +360,7 @@ int StdAwk::openFile (File& io)
((Awk*)io)->getMmgr(),
0,
io.getName(),
flags | QSE_FIO_TEXT,
flags,
QSE_FIO_RUSR | QSE_FIO_WUSR |
QSE_FIO_RGRP | QSE_FIO_ROTH
);
@ -410,7 +391,24 @@ int StdAwk::flushFile (File& io)
return qse_fio_flush ((qse_fio_t*)io.getHandle());
}
// console io handlers
int StdAwk::addConsoleOutput (const char_t* arg, size_t len)
{
QSE_ASSERT (awk != QSE_NULL);
int n = ofile.add (awk, arg, len);
if (n <= -1) setError (ERR_NOMEM);
return n;
}
int StdAwk::addConsoleOutput (const char_t* arg)
{
return addConsoleOutput (arg, qse_strlen(arg));
}
void StdAwk::clearConsoleOutputs ()
{
ofile.clear (awk);
}
int StdAwk::open_console_in (Console& io)
{
qse_awk_rtx_t* rtx = (rtx_t*)io;
@ -754,6 +752,81 @@ int StdAwk::vsprintf (
return qse_vsprintf (buf, size, fmt, arg);
}
int StdAwk::SourceFile::open (Data& io)
{
qse_sio_t* sio;
if (name[0] == QSE_T('-') &&
name[1] == QSE_T('\0'))
{
sio = (io.getMode() == READ)? qse_sio_in: qse_sio_out;
}
else
{
sio = qse_sio_open (
((awk_t*)io)->mmgr,
0,
name,
(io.getMode() == READ?
QSE_SIO_READ:
(QSE_SIO_WRITE|QSE_SIO_CREATE|QSE_SIO_TRUNCATE))
);
if (sio == QSE_NULL) return -1;
}
io.setHandle (sio);
return 1;
}
int StdAwk::SourceFile::close (Data& io)
{
qse_sio_t* sio = (qse_sio_t*)io.getHandle();
qse_sio_flush (sio);
if (sio != qse_sio_in && sio != qse_sio_out && sio != qse_sio_err)
{
qse_sio_close (sio);
}
return 0;
}
StdAwk::ssize_t StdAwk::SourceFile::read (Data& io, char_t* buf, size_t len)
{
return qse_sio_getsn ((qse_sio_t*)io.getHandle(), buf, len);
}
StdAwk::ssize_t StdAwk::SourceFile::write (Data& io, char_t* buf, size_t len)
{
return qse_sio_putsn ((qse_sio_t*)io.getHandle(), buf, len);
}
int StdAwk::SourceString::open (Data& io)
{
/* SourceString does not support writing */
if (io.getMode() == WRITE) return -1;
ptr = str;
return 1;
}
int StdAwk::SourceString::close (Data& io)
{
return 0;
}
StdAwk::ssize_t StdAwk::SourceString::read (Data& io, char_t* buf, size_t len)
{
qse_size_t n = 0;
while (*ptr != QSE_T('\0') && n < len) buf[n++] = *ptr++;
return n;
}
StdAwk::ssize_t StdAwk::SourceString::write (Data& io, char_t* buf, size_t len)
{
return -1;
}
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

View File

@ -11,8 +11,13 @@ awk03_SOURCES = awk03.c
awk04_SOURCES = awk04.c
if ENABLE_CXX
bin_PROGRAMS += awk05
bin_PROGRAMS += awk05 awk06 awk07
awk05_SOURCES = awk05.cpp
awk06_SOURCES = awk06.cpp
awk07_SOURCES = awk07.cpp
awk05_LDADD = -lqseawk++ $(LDADD)
awk06_LDADD = -lqseawk++ $(LDADD)
awk07_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
@ENABLE_CXX_TRUE@am__append_1 = awk05 awk06 awk07
subdir = samples/awk
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -48,7 +48,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/qse/config.h
CONFIG_CLEAN_FILES =
@ENABLE_CXX_TRUE@am__EXEEXT_1 = awk05$(EXEEXT)
@ENABLE_CXX_TRUE@am__EXEEXT_1 = awk05$(EXEEXT) awk06$(EXEEXT) \
@ENABLE_CXX_TRUE@ awk07$(EXEEXT)
am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
@ -74,6 +75,14 @@ am__awk05_SOURCES_DIST = awk05.cpp
awk05_OBJECTS = $(am_awk05_OBJECTS)
am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
@ENABLE_CXX_TRUE@awk05_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__awk06_SOURCES_DIST = awk06.cpp
@ENABLE_CXX_TRUE@am_awk06_OBJECTS = awk06.$(OBJEXT)
awk06_OBJECTS = $(am_awk06_OBJECTS)
@ENABLE_CXX_TRUE@awk06_DEPENDENCIES = $(am__DEPENDENCIES_2)
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)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/qse
depcomp = $(SHELL) $(top_srcdir)/ac/au/depcomp
am__depfiles_maybe = depfiles
@ -96,9 +105,11 @@ 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)
$(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \
$(awk07_SOURCES)
DIST_SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \
$(awk04_SOURCES) $(am__awk05_SOURCES_DIST)
$(awk04_SOURCES) $(am__awk05_SOURCES_DIST) \
$(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -245,7 +256,11 @@ awk02_SOURCES = awk02.c
awk03_SOURCES = awk03.c
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@awk05_LDADD = -lqseawk++ $(LDADD)
@ENABLE_CXX_TRUE@awk06_LDADD = -lqseawk++ $(LDADD)
@ENABLE_CXX_TRUE@awk07_LDADD = -lqseawk++ $(LDADD)
all: all-am
.SUFFIXES:
@ -322,6 +337,12 @@ awk04$(EXEEXT): $(awk04_OBJECTS) $(awk04_DEPENDENCIES)
awk05$(EXEEXT): $(awk05_OBJECTS) $(awk05_DEPENDENCIES)
@rm -f awk05$(EXEEXT)
$(CXXLINK) $(awk05_OBJECTS) $(awk05_LDADD) $(LIBS)
awk06$(EXEEXT): $(awk06_OBJECTS) $(awk06_DEPENDENCIES)
@rm -f awk06$(EXEEXT)
$(CXXLINK) $(awk06_OBJECTS) $(awk06_LDADD) $(LIBS)
awk07$(EXEEXT): $(awk07_OBJECTS) $(awk07_DEPENDENCIES)
@rm -f awk07$(EXEEXT)
$(CXXLINK) $(awk07_OBJECTS) $(awk07_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@ -334,6 +355,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)/awk07.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@ -17,468 +17,29 @@
*/
#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
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
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);
}
print_error (0, msg);
}
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;
QSE::StdAwk awk;
QSE::StdAwk::Run* run;
// initialize awk
if (awk.open() <= -1)
{
print_error (awk.getErrorMessage());
@ -493,175 +54,41 @@ static int awk_main (int argc, qse_char_t* argv[])
return -1;
}
for (int i = 1; i < argc; i++)
// ARGV[1] and/or the first console input file
if (awk.addArgument (QSE_T("awk05.cpp")) <= -1)
{
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]);
print_error (awk.getErrorMessage());
awk.close ();
return -1;
}
run = awk.parse (srcin, srcout);
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.
run = awk.parse (&in, &out);
if (run == QSE_NULL)
{
qse_fprintf (stderr, QSE_T("cannot parse: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
print_error (awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
awk.enableRunCallback ();
app_awk = &awk;
// execute the BEGIN, pattern-action, END blocks.
if (awk.loop () <= -1)
{
qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"),
awk.getErrorLine(), awk.getErrorMessage());
print_error (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;
}

98
qse/samples/awk/awk06.cpp Normal file
View File

@ -0,0 +1,98 @@
/*
* $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/stdio.h>
#include <qse/cmn/main.h>
static void print_error (unsigned long line, const qse_char_t* msg)
{
if (line > 0)
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s at LINE %lu\n"), msg, line);
else
qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg);
}
static void print_error (const qse_char_t* msg)
{
print_error (0, msg);
}
static int awk_main (int argc, qse_char_t* argv[])
{
QSE::StdAwk awk;
QSE::StdAwk::Run* run;
// initialize awk
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;
}
// ARGV[1] and/or the first console input file
if (awk.addArgument (QSE_T("awk05.cpp")) <= -1)
{
print_error (awk.getErrorMessage());
awk.close ();
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.
run = awk.parse (&in, &out);
if (run == QSE_NULL)
{
print_error (awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
// execute the BEGIN, pattern-action, END blocks.
if (awk.loop () <= -1)
{
print_error (awk.getErrorLine(), awk.getErrorMessage());
awk.close ();
return -1;
}
awk.close ();
return 0;
}
int qse_main (int argc, qse_achar_t* argv[])
{
return qse_runmain (argc,argv,awk_main);
}

671
qse/samples/awk/awk07.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);
}