From 852a51ae75d6160f59c363d7587d1c328f4eaa75 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 10 Jul 2009 06:46:14 +0000 Subject: [PATCH] changed Source IO model in Awk --- qse/include/qse/awk/Awk.hpp | 256 +++---------- qse/include/qse/awk/StdAwk.hpp | 34 +- qse/lib/awk/Awk.cpp | 56 +-- qse/lib/awk/StdAwk.cpp | 147 ++++++-- qse/samples/awk/Makefile.am | 7 +- qse/samples/awk/Makefile.in | 31 +- qse/samples/awk/awk05.cpp | 625 ++---------------------------- qse/samples/awk/awk06.cpp | 98 +++++ qse/samples/awk/awk07.cpp | 671 +++++++++++++++++++++++++++++++++ 9 files changed, 1049 insertions(+), 876 deletions(-) create mode 100644 qse/samples/awk/awk06.cpp create mode 100644 qse/samples/awk/awk07.cpp diff --git a/qse/include/qse/awk/Awk.hpp b/qse/include/qse/awk/Awk.hpp index ce0039ea..eec0e12c 100644 --- a/qse/include/qse/awk/Awk.hpp +++ b/qse/include/qse/awk/Awk.hpp @@ -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. - * - *
-		 * 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;
-		 * }
-		 * 
- * - * @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; diff --git a/qse/include/qse/awk/StdAwk.hpp b/qse/include/qse/awk/StdAwk.hpp index f395d822..04f0a4f3 100644 --- a/qse/include/qse/awk/StdAwk.hpp +++ b/qse/include/qse/awk/StdAwk.hpp @@ -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); diff --git a/qse/lib/awk/Awk.cpp b/qse/lib/awk/Awk.cpp index f234960c..83c79fdb 100644 --- a/qse/lib/awk/Awk.cpp +++ b/qse/lib/awk/Awk.cpp @@ -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 ( diff --git a/qse/lib/awk/StdAwk.cpp b/qse/lib/awk/StdAwk.cpp index 5e6638ea..1d560ff3 100644 --- a/qse/lib/awk/StdAwk.cpp +++ b/qse/lib/awk/StdAwk.cpp @@ -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) ///////////////////////////////// diff --git a/qse/samples/awk/Makefile.am b/qse/samples/awk/Makefile.am index f5dc428e..c997e4de 100644 --- a/qse/samples/awk/Makefile.am +++ b/qse/samples/awk/Makefile.am @@ -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 diff --git a/qse/samples/awk/Makefile.in b/qse/samples/awk/Makefile.in index 4307cfc2..d58c2107 100644 --- a/qse/samples/awk/Makefile.in +++ b/qse/samples/awk/Makefile.in @@ -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 $@ $< diff --git a/qse/samples/awk/awk05.cpp b/qse/samples/awk/awk05.cpp index c6421646..653a55b3 100644 --- a/qse/samples/awk/awk05.cpp +++ b/qse/samples/awk/awk05.cpp @@ -17,468 +17,29 @@ */ #include -#include #include #include -#include -#include - -#if defined(_WIN32) -# include -#else -# include -# include -# include -#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; } diff --git a/qse/samples/awk/awk06.cpp b/qse/samples/awk/awk06.cpp new file mode 100644 index 00000000..653a55b3 --- /dev/null +++ b/qse/samples/awk/awk06.cpp @@ -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 +#include +#include + +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); +} diff --git a/qse/samples/awk/awk07.cpp b/qse/samples/awk/awk07.cpp new file mode 100644 index 00000000..c6421646 --- /dev/null +++ b/qse/samples/awk/awk07.cpp @@ -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 +#include +#include +#include + +#include +#include + +#if defined(_WIN32) +# include +#else +# include +# include +# include +#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); +}