diff --git a/qse/include/qse/Types.hpp b/qse/include/qse/Types.hpp index 721f252d..e46851e6 100644 --- a/qse/include/qse/Types.hpp +++ b/qse/include/qse/Types.hpp @@ -38,14 +38,18 @@ public: typedef qse_char_t char_t; /** data type that can hold any character or an end-of-file value */ typedef qse_cint_t cint_t; - /** represents an unsigned integer number of the same size as void* */ + /** redefines an unsigned integer number of the same size as void* */ typedef qse_size_t size_t; /** signed version of size_t */ typedef qse_ssize_t ssize_t; - /** represents an integer */ + /** redefines an integer */ typedef qse_long_t long_t; - /** represents a floating-point number */ + /** redefines a floating-point number */ typedef qse_real_t real_t; + /** redefines a structure of a constant character pointer and length */ + typedef qse_cstr_t cstr_t; + /** redefines a structure of a character pointer and length */ + typedef qse_xstr_t xstr_t; }; ///////////////////////////////// diff --git a/qse/include/qse/sed/Sed.hpp b/qse/include/qse/sed/Sed.hpp index b33e1b9b..27551fbf 100644 --- a/qse/include/qse/sed/Sed.hpp +++ b/qse/include/qse/sed/Sed.hpp @@ -143,6 +143,15 @@ public: */ size_t getConsoleLine () throw (); + /** + * The setError() function sets information on an error occurred. + */ + void setError ( + errnum_t err, ///< an error number + size_t lin = 0, ///< a line number + const cstr_t* args = QSE_NULL ///< strings for formatting an error message + ); + /** * The setConsoleLine() function changes the current line * number from an input console. diff --git a/qse/include/qse/sed/StdSed.hpp b/qse/include/qse/sed/StdSed.hpp index 592c0798..338c2b15 100644 --- a/qse/include/qse/sed/StdSed.hpp +++ b/qse/include/qse/sed/StdSed.hpp @@ -21,13 +21,6 @@ #include -/** @file - * A standard stream editor - * - * @example sed02.cpp - * The example shows a simple usage of the StdSed class. - */ - ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// @@ -35,15 +28,13 @@ QSE_BEGIN_NAMESPACE(QSE) /** * The StdSed class inherits the Sed class and implements the standard * IO handlers and memory manager for easier use. + * */ class StdSed: public Sed { protected: - /** allocate a memory chunk */ void* allocMem (qse_size_t n) throw (); - /** resize a memory chunk */ void* reallocMem (void* ptr, qse_size_t n) throw (); - /** free a memory chunk */ void freeMem (void* ptr) throw (); int openConsole (Console& io); @@ -57,6 +48,16 @@ protected: ssize_t writeFile (File& io, const char_t* data, size_t len); }; +/** + * @example sed02.cpp + * The example shows how to use the QSE::StdSed class to write a simple stream + * editor that reads from a standard input and writes to a standard output. + * + * @example sed03.cpp + * The example shows how to extend the QSE::StdSed class to read from and + * write to a string. + */ + ///////////////////////////////// QSE_END_NAMESPACE(QSE) ///////////////////////////////// diff --git a/qse/include/qse/utl/main.h b/qse/include/qse/utl/main.h index 6039c427..60127182 100644 --- a/qse/include/qse/utl/main.h +++ b/qse/include/qse/utl/main.h @@ -1,7 +1,19 @@ /* - * $Id: main.h 463 2008-12-09 06:52:03Z baconevi $ + * $Id$ * - * {License} + 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. */ #ifndef _QSE_UTL_MAIN_H_ @@ -10,6 +22,16 @@ #include #include +/** @file + * This file includes a macro and a function to help users to write a + * cross-platform main function. + */ + +/** + * The #qse_main macro defines a main function wrapper for an underlying + * platform. Combined with the qse_runmain() function, it provides a consistant + * view to the main function. + */ #if defined(_WIN32) && !defined(__MINGW32__) # if defined(QSE_CHAR_IS_MCHAR) # define qse_main main @@ -27,6 +49,10 @@ extern "C" { #endif +/** + * The qse_runmain() function helps to invoke a main function independent of + * the character mode configured for the library. + */ int qse_runmain ( int argc, qse_achar_t* argv[], diff --git a/qse/lib/sed/Sed.cpp b/qse/lib/sed/Sed.cpp index 280d9850..dcd66828 100644 --- a/qse/lib/sed/Sed.cpp +++ b/qse/lib/sed/Sed.cpp @@ -89,6 +89,12 @@ Sed::errnum_t Sed::getErrorNumber () const throw () return (sed == QSE_NULL)? QSE_SED_ENOERR: qse_sed_geterrnum (sed); } +void Sed::setError (errnum_t err, size_t lin, const cstr_t* args) +{ + QSE_ASSERT (sed != QSE_NULL); + qse_sed_seterror (sed, err, lin, args); +} + Sed::size_t Sed::getConsoleLine () throw () { QSE_ASSERT (sed != QSE_NULL); diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c index edc6db62..01c49a0d 100644 --- a/qse/lib/sed/sed.c +++ b/qse/lib/sed/sed.c @@ -1391,8 +1391,9 @@ static int read_file ( n = sed->e.in.fun (sed, QSE_SED_IO_OPEN, &arg); if (n <= -1) { - /*SETERR0 (sed, QSE_SED_EIOUSR, cmd->lnum); - return -1;*/ + /*if (sed->errnum != QSE_SED_ENOERR) + * SETERR0 (sed, QSE_SED_EIOUSR, cmd->lnum); + *return -1;*/ /* it is ok if it is not able to open a file */ return 0; } @@ -1521,7 +1522,10 @@ static int flush (qse_sed_t* sed) if (n == 0) { - /* reached the end of file - anything to do? */ + /* reached the end of file - this is also an error */ + if (sed->errnum == QSE_SED_ENOERR) + SETERR0 (sed, QSE_SED_EIOUSR, 0); + return -1; } pos += n; @@ -2629,7 +2633,7 @@ int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf) /* flush the output stream in case it's not flushed * in write functions */ n = flush (sed); - if (n <= -1) goto done; + if (n <= -1) { ret = -1; goto done; } } done: diff --git a/qse/test/sed/Makefile.in b/qse/test/sed/Makefile.in index 14aaeebf..da56308f 100644 --- a/qse/test/sed/Makefile.in +++ b/qse/test/sed/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -33,7 +33,7 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = sed01$(EXEEXT) $(am__EXEEXT_1) -@ENABLE_CXX_TRUE@am__append_1 = sed02 +@ENABLE_CXX_TRUE@am__append_1 = sed02 sed03 subdir = test/sed DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -43,7 +43,7 @@ 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 = sed02$(EXEEXT) +@ENABLE_CXX_TRUE@am__EXEEXT_1 = sed02$(EXEEXT) sed03$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) @@ -57,6 +57,10 @@ am__sed02_SOURCES_DIST = sed02.cpp sed02_OBJECTS = $(am_sed02_OBJECTS) am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) @ENABLE_CXX_TRUE@sed02_DEPENDENCIES = $(am__DEPENDENCIES_2) +am__sed03_SOURCES_DIST = sed03.cpp +@ENABLE_CXX_TRUE@am_sed03_OBJECTS = sed03.$(OBJEXT) +sed03_OBJECTS = $(am_sed03_OBJECTS) +@ENABLE_CXX_TRUE@sed03_DEPENDENCIES = $(am__DEPENDENCIES_2) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/qse depcomp = $(SHELL) $(top_srcdir)/autoconf/depcomp am__depfiles_maybe = depfiles @@ -78,8 +82,9 @@ CXXLD = $(CXX) CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(sed01_SOURCES) $(sed02_SOURCES) -DIST_SOURCES = $(sed01_SOURCES) $(am__sed02_SOURCES_DIST) +SOURCES = $(sed01_SOURCES) $(sed02_SOURCES) $(sed03_SOURCES) +DIST_SOURCES = $(sed01_SOURCES) $(am__sed02_SOURCES_DIST) \ + $(am__sed03_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -104,14 +109,13 @@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ HAVE_OBJC = @HAVE_OBJC@ @@ -127,6 +131,7 @@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ @@ -138,6 +143,8 @@ OBJCDEPMODE = @OBJCDEPMODE@ OBJCFLAGS = @OBJCFLAGS@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -158,7 +165,7 @@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ac_ct_OBJC = @ac_ct_OBJC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ @@ -190,6 +197,7 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -202,6 +210,7 @@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir)/include @@ -209,6 +218,8 @@ LDADD = -lqsesed -lqseutl -lqsecmn $(LIBM) sed01_SOURCES = sed01.c @ENABLE_CXX_TRUE@sed02_SOURCES = sed02.cpp @ENABLE_CXX_TRUE@sed02_LDADD = -lqsesed++ $(LDADD) +@ENABLE_CXX_TRUE@sed03_SOURCES = sed03.cpp +@ENABLE_CXX_TRUE@sed03_LDADD = -lqsesed++ $(LDADD) all: all-am .SUFFIXES: @@ -217,8 +228,8 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ @@ -276,6 +287,9 @@ sed01$(EXEEXT): $(sed01_OBJECTS) $(sed01_DEPENDENCIES) sed02$(EXEEXT): $(sed02_OBJECTS) $(sed02_DEPENDENCIES) @rm -f sed02$(EXEEXT) $(CXXLINK) $(sed02_OBJECTS) $(sed02_LDADD) $(LIBS) +sed03$(EXEEXT): $(sed03_OBJECTS) $(sed03_DEPENDENCIES) + @rm -f sed03$(EXEEXT) + $(CXXLINK) $(sed03_OBJECTS) $(sed03_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -285,6 +299,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sed01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sed02.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sed03.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -339,7 +354,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS diff --git a/qse/test/sed/sed01.c b/qse/test/sed/sed01.c index 0c7f79b6..658eca3d 100644 --- a/qse/test/sed/sed01.c +++ b/qse/test/sed/sed01.c @@ -1,4 +1,4 @@ -/* +/** * $Id$ * Copyright 2006-2009 Chung, Hyung-Hwan. diff --git a/qse/test/sed/sed02.cpp b/qse/test/sed/sed02.cpp index e8e20508..58ced2fa 100644 --- a/qse/test/sed/sed02.cpp +++ b/qse/test/sed/sed02.cpp @@ -1,4 +1,4 @@ -/* +/** * $Id$ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -22,6 +22,13 @@ int sed_main (int argc, qse_char_t* argv[]) { + if (argc != 2) + { + qse_fprintf (QSE_STDERR, + QSE_T("usage: %s command-string\n"), argv[0]); + return -1; + } + QSE::StdSed sed; if (sed.open () == -1) diff --git a/qse/test/sed/sed03.cpp b/qse/test/sed/sed03.cpp index 92a56c78..6136f4ef 100644 --- a/qse/test/sed/sed03.cpp +++ b/qse/test/sed/sed03.cpp @@ -1,4 +1,4 @@ -/* +/** * $Id$ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -18,59 +18,101 @@ #include #include -#include +#include +#include + +typedef std::basic_string xstring; +typedef QSE::StdSed StdSed; // added for doxygen cross-reference + +// +// The MySed class provides a handier interface to QSE::StdSed by +// reimplementing console I/O functions, combining compile() and execute(), +// and utilizing exception handling. +// class MySed: protected QSE::StdSed { public: - MySed () - { - if (open() == -1) - { - throw 1; - } - } + + class Error + { + public: + Error (const char_t* msg) throw (): msg (msg) { } + const char_t* getMessage() const throw() { return msg; } + protected: + const char_t* msg; + }; - ~MySed () - { - close (); + MySed () + { + if (QSE::StdSed::open() == -1) + throw Error (QSE_T("cannot open")); + } + + ~MySed () + { + QSE::StdSed::close (); } - int exec (const char_t* cmds, const char_t* in, string& out) + void run (const char_t* cmds, const char_t* in, xstring& out) { - if (compile (cmds) == -1) return -1; - if (execute () == -1) return -1; - return 0; + // remember an input string and an output string + this->in = in; this->out = &out; + + // compile source commands and execute compiled commands. + if (QSE::StdSed::compile (cmds) <= -1 || + QSE::StdSed::execute () <= -1) + { + throw Error (QSE::StdSed::getErrorMessage()); + } } protected: - int openConsole (Console& io) - { + // override console I/O functions to perform I/O over strings. + + int openConsole (Console& io) + { + if (io.getMode() == Console::WRITE) out->clear(); return 1; } - int closeConsole (Console& io) + int closeConsole (Console& io) { return 0; } ssize_t readConsole (Console& io, char_t* buf, size_t len) { - return 0; + ssize_t n = qse_strxcpy (buf, len, in); + in += n; return n; } ssize_t writeConsole (Console& io, const char_t* buf, size_t len) { - return 0; + try { out->append (buf, len); return len; } + catch (...) { QSE::Sed::setError (QSE_SED_ENOMEM); throw; } } + +protected: + const char_t* in; + xstring* out; }; int sed_main (int argc, qse_char_t* argv[]) { - MySed sed; - - if (sed.exec (QSE_T("s/abc/XXXXXXXXXXX/g"), in, out) == 0) + try { + MySed sed; + xstring out; + + sed.run ( + QSE_T("y/ABC/abc/;s/abc/def/g"), + QSE_T("ABCDEFabcdef"), out); + std::cout << QSE_T("OUTPUT: ") << out << std::endl; + } + catch (MySed::Error& err) + { + std::cout << QSE_T("ERROR: ") << err.getMessage() << std::endl; return -1; }