diff --git a/qse/include/qse/awk/Awk.hpp b/qse/include/qse/awk/Awk.hpp index 67e355bd..80eaa143 100644 --- a/qse/include/qse/awk/Awk.hpp +++ b/qse/include/qse/awk/Awk.hpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.hpp 229 2009-07-12 13:06:01Z hyunghwan.chung $ + * $Id: Awk.hpp 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -239,6 +239,69 @@ public: void operator delete (void* p) throw (); void operator delete[] (void* p) throw (); + class Index + { + public: + friend class Value; + + Index (): ptr (EMPTY_STRING), len (0) {} + Index (const char_t* ptr, size_t len): + ptr (ptr), len (len) {} + + const char_t* ptr; + size_t len; + }; + + class IntIndex: public Index + { + public: + IntIndex (long_t num); + + protected: + // 2^32: 4294967296 + // 2^64: 18446744073709551616 + // 2^128: 340282366920938463463374607431768211456 + // -(2^32/2): -2147483648 + // -(2^64/2): -9223372036854775808 + // -(2^128/2): -170141183460469231731687303715884105728 + #if QSE_SIZEOF_LONG_T > 16 + # error SIZEOF(qse_long_t) TOO LARGE. + # error INCREASE THE BUFFER SIZE TO SUPPORT IT. + #elif QSE_SIZEOF_LONG_T == 16 + char_t buf[41]; + #elif QSE_SIZEOF_LONG_T == 8 + char_t buf[21]; + #else + char_t buf[12]; + #endif + }; + + class IndexIterator + { + public: + friend class Value; + + static IndexIterator END; + + IndexIterator (): pair (QSE_NULL), buckno (0) {} + IndexIterator (pair_t* pair, size_t buckno): + pair (pair), buckno (buckno) {} + + bool operator== (const IndexIterator& ii) const + { + return pair == ii.pair && buckno == ii.buckno; + } + + bool operator!= (const IndexIterator& ii) const + { + return !operator== (ii); + } + + protected: + pair_t* pair; + size_t buckno; + }; + Value (); Value (Run& run); Value (Run* run); @@ -302,62 +365,75 @@ public: int setStr (Run* r, const char_t* str); int setIndexedVal ( - const char_t* idx, size_t isz, val_t* v); + const Index& idx, + val_t* v + ); + int setIndexedVal ( - Run* r, const char_t* idx, size_t isz, val_t* v); + Run* r, + const Index& idx, + val_t* v + ); int setIndexedInt ( - const char_t* idx, size_t isz, long_t v); + const Index& idx, + long_t v + ); + int setIndexedInt ( - Run* r, const char_t* idx, size_t isz, long_t v); + Run* r, + const Index& idx, + long_t v); int setIndexedReal ( - const char_t* idx, - size_t isz, + const Index& idx, real_t v ); int setIndexedReal ( Run* r, - const char_t* idx, - size_t isz, + const Index& idx, real_t v ); int setIndexedStr ( - const char_t* idx, - size_t isz, + const Index& idx, const char_t* str, size_t len ); int setIndexedStr ( Run* r, - const char_t* idx, - size_t isz, + const Index& idx, const char_t* str, size_t len ); int setIndexedStr ( - const char_t* idx, - size_t isz, + const Index& idx, const char_t* str ); int setIndexedStr ( Run* r, - const char_t* idx, - size_t isz, + const Index& idx, const char_t* str ); bool isIndexed () const; int getIndexed ( - const char_t* idx, - size_t isz, - Value& val + const Index& idx, + Value* val + ) const; + + IndexIterator getFirstIndex ( + Index* idx + ) const; + + IndexIterator getNextIndex ( + Index* idx, + const IndexIterator& iter ) const; protected: diff --git a/qse/include/qse/awk/StdAwk.hpp b/qse/include/qse/awk/StdAwk.hpp index c6fa99ed..b8225b96 100644 --- a/qse/include/qse/awk/StdAwk.hpp +++ b/qse/include/qse/awk/StdAwk.hpp @@ -1,5 +1,5 @@ /* - * $Id: StdAwk.hpp 229 2009-07-12 13:06:01Z hyunghwan.chung $ + * $Id: StdAwk.hpp 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -23,9 +23,11 @@ /** * @example awk05.cpp - * This program demonstrates how to embed QSE::StdAwk in C++. + * This program demonstrates how to embed QSE::StdAwk::loop(). * @example awk06.cpp - * This program demonstrates how to embed QSE::StdAwk in C++. + * This program demonstrates how to use QSE::StdAwk::call(). + * @example awk07.cpp + * This program demonstrates how to handle an indexed value. */ ///////////////////////////////// diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 3174d6d0..968b1083 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 228 2009-07-11 03:01:36Z hyunghwan.chung $ + * $Id: awk.h 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -1809,6 +1809,18 @@ void* qse_awk_rtx_alloc ( qse_size_t size /**< block size in bytes */ ); +/** + * The qse_awk_rtx_realloc() function resizes a memory block pointed to + * by @a ptr to @a size bytes using the memory manager associated with + * a runtime context @a rtx. + * @return the pointer to a memory block on success, #QSE_NULL on failure. + */ +void* qse_awk_rtx_realloc ( + qse_awk_rtx_t* rtx, /**< runtime context */ + void* ptr, /**< memory block */ + qse_size_t size /**< block size in bytes */ +); + /** * The qse_awk_rtx_free() function frees a memory block pointed to by @a ptr * using the memory manager of a runtime ocntext @a rtx. diff --git a/qse/include/qse/types.h b/qse/include/qse/types.h index 94cbed6e..882096e6 100644 --- a/qse/include/qse/types.h +++ b/qse/include/qse/types.h @@ -1,5 +1,5 @@ /* - * $Id: types.h 220 2009-07-01 13:14:39Z hyunghwan.chung $ + * $Id: types.h 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -70,24 +70,31 @@ typedef enum qse_tri_t qse_tri_t; (QSE_SIZEOF_VOID_P == QSE_SIZEOF_LONG) typedef long qse_int_t; typedef unsigned long qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF_LONG #elif defined(__SPU__) && (QSE_SIZEOF_VOID_P == QSE_SIZEOF_LONG) typedef long qse_int_t; typedef unsigned long qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF_LONG #elif QSE_SIZEOF_VOID_P == QSE_SIZEOF_INT typedef int qse_int_t; typedef unsigned int qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF_INT #elif QSE_SIZEOF_VOID_P == QSE_SIZEOF_LONG typedef long qse_int_t; typedef unsigned long qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF_LONG #elif QSE_SIZEOF_VOID_P == QSE_SIZEOF_LONG_LONG typedef long long qse_int_t; typedef unsigned long long qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF_LONG_LONG #elif QSE_SIZEOF_VOID_P == QSE_SIZEOF___INT32 typedef __int32 qse_int_t; typedef unsigned __int32 qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF___INT32 #elif QSE_SIZEOF_VOID_P == QSE_SIZEOF___INT64 typedef __int64 qse_int_t; typedef unsigned __int64 qse_uint_t; + #define QSE_SIZEOF_INT_T QSE_SIZEOF___INT64 #else # error unsupported pointer size #endif @@ -101,12 +108,15 @@ typedef enum qse_tri_t qse_tri_t; #if QSE_SIZEOF_LONG_LONG > 0 typedef long long qse_long_t; typedef unsigned long long qse_ulong_t; + #define QSE_SIZEOF_LONG_T QSE_SIZEOF_LONG_LONG #elif QSE_SIZEOF___INT64 > 0 typedef __int64 qse_long_t; typedef unsigned __int64 qse_ulong_t; + #define QSE_SIZEOF_LONG_T QSE_SIZEOF___INT64 #else typedef long qse_long_t; typedef unsigned long qse_ulong_t; + #define QSE_SIZEOF_LONG_T QSE_SIZEOF_LONG #endif /** @typedef qse_int8_t diff --git a/qse/lib/awk/Awk.cpp b/qse/lib/awk/Awk.cpp index 8610a27e..80adc46d 100644 --- a/qse/lib/awk/Awk.cpp +++ b/qse/lib/awk/Awk.cpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.cpp 229 2009-07-12 13:06:01Z hyunghwan.chung $ + * $Id: Awk.cpp 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -170,6 +170,51 @@ Awk::Console::Mode Awk::Console::getMode () const ////////////////////////////////////////////////////////////////// const Awk::char_t* Awk::Value::EMPTY_STRING = QSE_T(""); +Awk::Value::IndexIterator Awk::Value::IndexIterator::END; + +Awk::Value::IntIndex::IntIndex (long_t x) +{ + ptr = buf; + len = 0; + +#define NTOC(n) ((n) + QSE_T('0')) + + int base = 10; + long_t last = x % base; + long_t y = 0; + int dig = 0; + + if (x < 0) buf[len++] = QSE_T('-'); + + x = x / base; + if (x < 0) x = -x; + + while (x > 0) + { + y = y * base + (x % base); + x = x / base; + dig++; + } + + while (y > 0) + { + buf[len++] = NTOC (y % base); + y = y / base; + dig--; + } + + while (dig > 0) + { + dig--; + buf[len++] = QSE_T('0'); + } + if (last < 0) last = -last; + buf[len++] = NTOC(last); + + buf[len] = QSE_T('\0'); + +#undef NTOC +} void* Awk::Value::operator new (size_t n, Run* run) throw () { @@ -326,7 +371,11 @@ int Awk::Value::getInt (long_t* v) const { real_t rv; int n = qse_awk_rtx_valtonum (run->rtx, val, &lv, &rv); - if (n <= -1) return -1; + if (n <= -1) + { + run->awk->retrieveError (run->rtx); + return -1; + } if (n >= 1) lv = rv; } @@ -346,7 +395,11 @@ int Awk::Value::getReal (real_t* v) const { long_t lv; int n = qse_awk_rtx_valtonum (run->rtx, val, &lv, &rv); - if (n <= -1) return -1; + if (n <= -1) + { + run->awk->retrieveError (run->rtx); + return -1; + } if (n == 0) rv = lv; } @@ -379,6 +432,7 @@ int Awk::Value::getStr (const char_t** str, size_t* len) const if (qse_awk_rtx_valtostr ( run->rtx, val, &out) == QSE_NULL) { + run->awk->retrieveError (run->rtx); return -1; } @@ -440,7 +494,11 @@ int Awk::Value::setInt (Run* r, long_t v) { val_t* tmp; tmp = qse_awk_rtx_makeintval (r->rtx, v); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } int n = setVal (r, tmp); QSE_ASSERT (n == 0); @@ -457,7 +515,11 @@ int Awk::Value::setReal (Run* r, real_t v) { val_t* tmp; tmp = qse_awk_rtx_makerealval (r->rtx, v); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } int n = setVal (r, tmp); QSE_ASSERT (n == 0); @@ -474,7 +536,11 @@ int Awk::Value::setStr (Run* r, const char_t* str, size_t len) { val_t* tmp; tmp = qse_awk_rtx_makestrval (r->rtx, str, len); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } int n = setVal (r, tmp); QSE_ASSERT (n == 0); @@ -491,27 +557,37 @@ int Awk::Value::setStr (Run* r, const char_t* str) { val_t* tmp; tmp = qse_awk_rtx_makestrval0 (r->rtx, str); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } int n = setVal (r, tmp); QSE_ASSERT (n == 0); return n; } -int Awk::Value::setIndexedVal (const char_t* idx, size_t isz, val_t* v) +int Awk::Value::setIndexedVal (const Index& idx, val_t* v) { if (run == QSE_NULL) return -1; - return setIndexedVal (run, idx, isz, v); + return setIndexedVal (run, idx, v); } -int Awk::Value::setIndexedVal (Run* r, const char_t* idx, size_t isz, val_t* v) +int Awk::Value::setIndexedVal (Run* r, const Index& idx, val_t* v) { + QSE_ASSERT (r != QSE_NULL); + if (val->type != QSE_AWK_VAL_MAP) { /* the previous value is not a map. * a new map value needs to be created first */ - val_t* map = qse_awk_rtx_makemapval (run->rtx); - if (map == QSE_NULL) return -1; + val_t* map = qse_awk_rtx_makemapval (r->rtx); + if (map == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } qse_awk_rtx_refupval (r->rtx, map); qse_awk_rtx_refupval (r->rtx, v); @@ -519,12 +595,13 @@ int Awk::Value::setIndexedVal (Run* r, const char_t* idx, size_t isz, val_t* v) /* update the map with a given value */ pair_t* pair = qse_map_upsert ( ((qse_awk_val_map_t*)map)->map, - (char_t*)idx, isz, v, 0); + (char_t*)idx.ptr, idx.len, v, 0); if (pair == QSE_NULL) { qse_awk_rtx_refdownval (r->rtx, v); qse_awk_rtx_refdownval (r->rtx, map); - run->setError (ERR_NOMEM, 0, QSE_NULL, 0); + r->setError (ERR_NOMEM, 0, QSE_NULL, 0); + r->awk->retrieveError (r->rtx); return -1; } @@ -545,6 +622,7 @@ int Awk::Value::setIndexedVal (Run* r, const char_t* idx, size_t isz, val_t* v) { // it can't span across multiple runtime contexts run->setError (ERR_INVAL); + run->awk->retrieveError (run->rtx); return -1; } @@ -552,11 +630,12 @@ int Awk::Value::setIndexedVal (Run* r, const char_t* idx, size_t isz, val_t* v) pair_t* pair = qse_map_upsert ( ((qse_awk_val_map_t*)val)->map, - (char_t*)idx, isz, v, 0); + (char_t*)idx.ptr, idx.len, v, 0); if (pair == QSE_NULL) { qse_awk_rtx_refdownval (r->rtx, v); run->setError (ERR_NOMEM); + run->awk->retrieveError (run->rtx); return -1; } } @@ -564,79 +643,94 @@ int Awk::Value::setIndexedVal (Run* r, const char_t* idx, size_t isz, val_t* v) return 0; } -int Awk::Value::setIndexedInt (const char_t* idx, size_t isz, long_t v) +int Awk::Value::setIndexedInt (const Index& idx, long_t v) { if (run == QSE_NULL) return -1; - return setIndexedInt (run, idx, isz, v); + return setIndexedInt (run, idx, v); } -int Awk::Value::setIndexedInt (Run* r, const char_t* idx, size_t isz, long_t v) +int Awk::Value::setIndexedInt (Run* r, const Index& idx, long_t v) { val_t* tmp; tmp = qse_awk_rtx_makeintval (r->rtx, v); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } qse_awk_rtx_refupval (r->rtx, tmp); - int n = setIndexedVal (r, idx, isz, tmp); + int n = setIndexedVal (r, idx, tmp); qse_awk_rtx_refdownval (r->rtx, tmp); return n; } -int Awk::Value::setIndexedReal (const char_t* idx, size_t isz, real_t v) +int Awk::Value::setIndexedReal (const Index& idx, real_t v) { if (run == QSE_NULL) return -1; - return setIndexedReal (run, idx, isz, v); + return setIndexedReal (run, idx, v); } -int Awk::Value::setIndexedReal (Run* r, const char_t* idx, size_t isz, real_t v) +int Awk::Value::setIndexedReal (Run* r, const Index& idx, real_t v) { val_t* tmp; tmp = qse_awk_rtx_makerealval (r->rtx, v); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } qse_awk_rtx_refupval (r->rtx, tmp); - int n = setIndexedVal (r, idx, isz, tmp); + int n = setIndexedVal (r, idx, tmp); qse_awk_rtx_refdownval (r->rtx, tmp); return n; } -int Awk::Value::setIndexedStr (const char_t* idx, size_t isz, const char_t* str, size_t len) +int Awk::Value::setIndexedStr (const Index& idx, const char_t* str, size_t len) { if (run == QSE_NULL) return -1; - return setIndexedStr (run, idx, isz, str, len); + return setIndexedStr (run, idx, str, len); } int Awk::Value::setIndexedStr ( - Run* r, const char_t* idx, size_t isz, const char_t* str, size_t len) + Run* r, const Index& idx, const char_t* str, size_t len) { val_t* tmp; tmp = qse_awk_rtx_makestrval (r->rtx, str, len); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } qse_awk_rtx_refupval (r->rtx, tmp); - int n = setIndexedVal (r, idx, isz, tmp); + int n = setIndexedVal (r, idx, tmp); qse_awk_rtx_refdownval (r->rtx, tmp); return n; } -int Awk::Value::setIndexedStr (const char_t* idx, size_t isz, const char_t* str) +int Awk::Value::setIndexedStr (const Index& idx, const char_t* str) { if (run == QSE_NULL) return -1; - return setIndexedStr (run, idx, isz, str); + return setIndexedStr (run, idx, str); } -int Awk::Value::setIndexedStr ( - Run* r, const char_t* idx, size_t isz, const char_t* str) +int Awk::Value::setIndexedStr (Run* r, const Index& idx, const char_t* str) { val_t* tmp; tmp = qse_awk_rtx_makestrval0 (r->rtx, str); - if (tmp == QSE_NULL) return -1; + if (tmp == QSE_NULL) + { + r->awk->retrieveError (r->rtx); + return -1; + } qse_awk_rtx_refupval (r->rtx, tmp); - int n = setIndexedVal (r, idx, isz, tmp); + int n = setIndexedVal (r, idx, tmp); qse_awk_rtx_refdownval (r->rtx, tmp); return n; @@ -649,30 +743,68 @@ bool Awk::Value::isIndexed () const return val->type == QSE_AWK_VAL_MAP; } -int Awk::Value::getIndexed (const char_t* idx, size_t isz, Value& v) const +int Awk::Value::getIndexed (const Index& idx, Value* v) const { QSE_ASSERT (val != QSE_NULL); // not a map. v is just nil. not an error if (val->type != QSE_AWK_VAL_MAP) { - v.clear (); + v->clear (); return 0; } // get the value from the map. qse_awk_val_map_t* m = (qse_awk_val_map_t*)val; - pair_t* pair = qse_map_search (m->map, idx, isz); + pair_t* pair = qse_map_search (m->map, idx.ptr, idx.len); // the key is not found. it is not an error. v is just nil if (pair == QSE_NULL) { - v.clear (); + v->clear (); return 0; } // if v.set fails, it should return an error - return v.setVal (run, (val_t*)QSE_MAP_VPTR(pair)); + return v->setVal (run, (val_t*)QSE_MAP_VPTR(pair)); +} + +Awk::Value::IndexIterator Awk::Value::getFirstIndex (Index* idx) const +{ + QSE_ASSERT (val != QSE_NULL); + + if (val->type != QSE_AWK_VAL_MAP) return IndexIterator::END; + + size_t buckno; + qse_awk_val_map_t* m = (qse_awk_val_map_t*)val; + pair_t* pair = qse_map_getfirstpair (m->map, &buckno); + if (pair == QSE_NULL) return IndexIterator::END; // no more key + + idx->ptr = (const char_t*)QSE_MAP_KPTR(pair); + idx->len = QSE_MAP_KLEN(pair); + + return IndexIterator (pair, buckno); +} + +Awk::Value::IndexIterator Awk::Value::getNextIndex ( + Index* idx, const IndexIterator& iter) const +{ + QSE_ASSERT (val != QSE_NULL); + + if (val->type != QSE_AWK_VAL_MAP) return IndexIterator::END; + + qse_awk_val_map_t* m = (qse_awk_val_map_t*)val; + + pair_t* pair = (pair_t*)iter.pair; + size_t buckno = iter.buckno; + + pair = qse_map_getnextpair (m->map, pair, &buckno); + if (pair == QSE_NULL) return IndexIterator::END; + + idx->ptr = (const char_t*)QSE_MAP_KPTR(pair); + idx->len = QSE_MAP_KLEN(pair); + + return IndexIterator (pair, buckno); } #if 0 @@ -724,35 +856,6 @@ int Awk::Argument::getNextIndex (Awk::Argument& val) const return 1; } -int Awk::Return::setIndexed (long_t idx, real_t v) -{ - if (this->run == QSE_NULL) return -1; - - char_t ri[128]; - - int rl = Awk::sprintf ( - (awk_t*)this->run->awk, ri, QSE_COUNTOF(ri), - #if QSE_SIZEOF_LONG_LONG > 0 - QSE_T("%lld"), (long long)idx - #elif QSE_SIZEOF___INT64 > 0 - QSE_T("%I64d"), (__int64)idx - #elif QSE_SIZEOF_LONG > 0 - QSE_T("%ld"), (long)idx - #elif QSE_SIZEOF_INT > 0 - QSE_T("%d"), (int)idx - #else - #error unsupported size - #endif - ); - - if (rl < 0) - { - this->run->setError (ERR_INTERN, 0, QSE_NULL, 0); - return -1; - } - - return setIndexed (ri, rl, v); -} #endif ////////////////////////////////////////////////////////////////// @@ -1270,6 +1373,7 @@ int Awk::call (const char_t* name, Value* ret, const Value* args, size_t nargs) if (ptr == QSE_NULL) { runctx.setError (ERR_NOMEM); + retrieveError (runctx.rtx); return -1; } } diff --git a/qse/lib/awk/misc.c b/qse/lib/awk/misc.c index 8c7c0dae..65114823 100644 --- a/qse/lib/awk/misc.c +++ b/qse/lib/awk/misc.c @@ -1,5 +1,5 @@ /* - * $Id: misc.c 220 2009-07-01 13:14:39Z hyunghwan.chung $ + * $Id: misc.c 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -983,6 +983,11 @@ void* qse_awk_rtx_alloc (qse_awk_rtx_t* rtx, qse_size_t size) return qse_awk_alloc (rtx->awk, size); } +void* qse_awk_rtx_realloc (qse_awk_rtx_t* rtx, void* ptr, qse_size_t size) +{ + return qse_awk_realloc (rtx->awk, ptr, size); +} + void qse_awk_rtx_free (qse_awk_rtx_t* rtx, void* ptr) { qse_awk_free (rtx->awk, ptr); diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index 54468133..c69500fb 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c 228 2009-07-11 03:01:36Z hyunghwan.chung $ + * $Id: run.c 230 2009-07-13 08:51:23Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -243,6 +243,9 @@ typedef qse_awk_val_t* (*binop_func_t) ( qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right); typedef qse_awk_val_t* (*eval_expr_t) (qse_awk_rtx_t* run, qse_awk_nde_t* nde); +#ifdef NDEBUG +#define xstr_to_cstr(x) ((qse_cstr_t*)x) +#else static qse_cstr_t* xstr_to_cstr (qse_xstr_t* xstr) { /* i use this function to typecast qse_cstr_t* to @@ -252,6 +255,7 @@ static qse_cstr_t* xstr_to_cstr (qse_xstr_t* xstr) * haved changed to something else. */ return (qse_cstr_t*)xstr; } +#endif qse_size_t qse_awk_rtx_getnargs (qse_awk_rtx_t* run) { @@ -3328,7 +3332,6 @@ static qse_awk_val_t* do_assignment ( goto exit_on_error; } - ret = do_assignment_pos (run, (qse_awk_nde_pos_t*)var, val); } else @@ -3463,7 +3466,7 @@ static qse_awk_val_t* do_assignment_map ( (var->type == QSE_AWK_NDE_LCLIDX)? (qse_awk_val_map_t*)STACK_LCL(run,var->id.idxa): (qse_awk_val_map_t*)STACK_ARG(run,var->id.idxa); - } + } if (map->type == QSE_AWK_VAL_NIL) { diff --git a/qse/samples/awk/Makefile.am b/qse/samples/awk/Makefile.am index c997e4de..ab783b70 100644 --- a/qse/samples/awk/Makefile.am +++ b/qse/samples/awk/Makefile.am @@ -11,13 +11,15 @@ awk03_SOURCES = awk03.c awk04_SOURCES = awk04.c if ENABLE_CXX -bin_PROGRAMS += awk05 awk06 awk07 +bin_PROGRAMS += awk05 awk06 awk07 awk08 awk05_SOURCES = awk05.cpp awk06_SOURCES = awk06.cpp awk07_SOURCES = awk07.cpp +awk08_SOURCES = awk08.cpp awk05_LDADD = -lqseawk++ $(LDADD) awk06_LDADD = -lqseawk++ $(LDADD) awk07_LDADD = -lqseawk++ $(LDADD) +awk08_LDADD = -lqseawk++ $(LDADD) endif diff --git a/qse/samples/awk/Makefile.in b/qse/samples/awk/Makefile.in index d58c2107..a2bf09c7 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 awk06 awk07 +@ENABLE_CXX_TRUE@am__append_1 = awk05 awk06 awk07 awk08 subdir = samples/awk DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -49,7 +49,7 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/qse/config.h CONFIG_CLEAN_FILES = @ENABLE_CXX_TRUE@am__EXEEXT_1 = awk05$(EXEEXT) awk06$(EXEEXT) \ -@ENABLE_CXX_TRUE@ awk07$(EXEEXT) +@ENABLE_CXX_TRUE@ awk07$(EXEEXT) awk08$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) @@ -83,6 +83,10 @@ am__awk07_SOURCES_DIST = awk07.cpp @ENABLE_CXX_TRUE@am_awk07_OBJECTS = awk07.$(OBJEXT) awk07_OBJECTS = $(am_awk07_OBJECTS) @ENABLE_CXX_TRUE@awk07_DEPENDENCIES = $(am__DEPENDENCIES_2) +am__awk08_SOURCES_DIST = awk08.cpp +@ENABLE_CXX_TRUE@am_awk08_OBJECTS = awk08.$(OBJEXT) +awk08_OBJECTS = $(am_awk08_OBJECTS) +@ENABLE_CXX_TRUE@awk08_DEPENDENCIES = $(am__DEPENDENCIES_2) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/qse depcomp = $(SHELL) $(top_srcdir)/ac/au/depcomp am__depfiles_maybe = depfiles @@ -106,10 +110,11 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \ $(awk04_SOURCES) $(awk05_SOURCES) $(awk06_SOURCES) \ - $(awk07_SOURCES) + $(awk07_SOURCES) $(awk08_SOURCES) DIST_SOURCES = $(awk01_SOURCES) $(awk02_SOURCES) $(awk03_SOURCES) \ $(awk04_SOURCES) $(am__awk05_SOURCES_DIST) \ - $(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST) + $(am__awk06_SOURCES_DIST) $(am__awk07_SOURCES_DIST) \ + $(am__awk08_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -258,9 +263,11 @@ awk04_SOURCES = awk04.c @ENABLE_CXX_TRUE@awk05_SOURCES = awk05.cpp @ENABLE_CXX_TRUE@awk06_SOURCES = awk06.cpp @ENABLE_CXX_TRUE@awk07_SOURCES = awk07.cpp +@ENABLE_CXX_TRUE@awk08_SOURCES = awk08.cpp @ENABLE_CXX_TRUE@awk05_LDADD = -lqseawk++ $(LDADD) @ENABLE_CXX_TRUE@awk06_LDADD = -lqseawk++ $(LDADD) @ENABLE_CXX_TRUE@awk07_LDADD = -lqseawk++ $(LDADD) +@ENABLE_CXX_TRUE@awk08_LDADD = -lqseawk++ $(LDADD) all: all-am .SUFFIXES: @@ -343,6 +350,9 @@ awk06$(EXEEXT): $(awk06_OBJECTS) $(awk06_DEPENDENCIES) awk07$(EXEEXT): $(awk07_OBJECTS) $(awk07_DEPENDENCIES) @rm -f awk07$(EXEEXT) $(CXXLINK) $(awk07_OBJECTS) $(awk07_LDADD) $(LIBS) +awk08$(EXEEXT): $(awk08_OBJECTS) $(awk08_DEPENDENCIES) + @rm -f awk08$(EXEEXT) + $(CXXLINK) $(awk08_OBJECTS) $(awk08_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -357,6 +367,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk05.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk06.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk07.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/awk08.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/qse/samples/awk/awk07.cpp b/qse/samples/awk/awk07.cpp index c6421646..dd18e554 100644 --- a/qse/samples/awk/awk07.cpp +++ b/qse/samples/awk/awk07.cpp @@ -17,652 +17,103 @@ */ #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 -} - -static void print_error (const qse_char_t* msg) -{ - qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg); -} - -static struct -{ - const qse_char_t* name; - MyAwk::Option opt; -} otab[] = -{ - { QSE_T("implicit"), MyAwk::OPT_IMPLICIT }, - { QSE_T("explicit"), MyAwk::OPT_EXPLICIT }, - { QSE_T("bxor"), MyAwk::OPT_BXOR }, - { QSE_T("shift"), MyAwk::OPT_SHIFT }, - { QSE_T("idiv"), MyAwk::OPT_IDIV }, - { QSE_T("rio"), MyAwk::OPT_RIO }, - { QSE_T("rwpipe"), MyAwk::OPT_RWPIPE }, - { QSE_T("newline"), MyAwk::OPT_NEWLINE }, - { QSE_T("stripspaces"), MyAwk::OPT_STRIPSPACES }, - { QSE_T("nextofile"), MyAwk::OPT_NEXTOFILE }, - { QSE_T("crlf"), MyAwk::OPT_CRLF }, - { QSE_T("reset"), MyAwk::OPT_RESET }, - { QSE_T("maptovar"), MyAwk::OPT_MAPTOVAR }, - { QSE_T("pablock"), MyAwk::OPT_PABLOCK } -}; - -static void print_usage (const qse_char_t* argv0) -{ - const qse_char_t* base; - int j; + qse_fprintf (QSE_STDERR, QSE_T("ERROR: %s\n"), msg); - base = qse_strrchr(argv0, QSE_T('/')); - if (base == QSE_NULL) base = qse_strrchr(argv0, QSE_T('\\')); - if (base == QSE_NULL) base = argv0; else base++; +} - qse_printf (QSE_T("Usage: %s [-si file]? [-so file]? [-ci file]* [-co file]* [-w o:n]* \n"), base); - qse_printf (QSE_T(" -si file Specify the input source file\n")); - qse_printf (QSE_T(" The source code is read from stdin when it is not specified\n")); - qse_printf (QSE_T(" -so file Specify the output source file\n")); - qse_printf (QSE_T(" The deparsed code is not output when is it not specified\n")); - qse_printf (QSE_T(" -ci file Specify the input console file\n")); - qse_printf (QSE_T(" -co file Specify the output console file\n")); - qse_printf (QSE_T(" -w o:n Specify an old and new word pair\n")); - qse_printf (QSE_T(" o - an original word\n")); - qse_printf (QSE_T(" n - the new word to replace the original\n")); - qse_printf (QSE_T(" -v Print extra messages\n")); +static int run_awk (QSE::StdAwk& awk) +{ + QSE::StdAwk::Run* run; + const qse_char_t* script = QSE_T( + "function pa (x) {\n" + " reset ret;\n" + " for (i in x) { print i, \"=>\", x[i]; ret += x[i]; }\n" + " return ret;\n" + "}\n" + "function pb (x) {\n" + " reset ret;\n" + " for (i in x) { ret[-i] = -x[i]; }\n" + " return ret;\n" + "}" + ); - qse_printf (QSE_T("\nYou may specify the following options to change the behavior of the interpreter.\n")); - for (j = 0; j < (int)QSE_COUNTOF(otab); j++) + QSE::StdAwk::SourceString in (script); + QSE::StdAwk::SourceFile out (QSE_T("awk07.out")); + + // parse the script and deparse it to awk07.out + run = awk.parse (&in, &out); + if (run == QSE_NULL) return -1; + + QSE::StdAwk::Value arg[1]; + + for (int i = 1; i <= 5; i++) { - qse_printf (QSE_T(" -%-20s -no%-20s\n"), otab[j].name, otab[j].name); + if (arg[0].setIndexedInt ( + run, QSE::StdAwk::Value::IntIndex(i), i*20) <= -1) return -1; } + + QSE::StdAwk::Value r; + + // call the 'pa' function + if (awk.call (QSE_T("pa"), &r, arg, QSE_COUNTOF(arg)) <= -1) return -1; + + // output the result in various types + qse_printf (QSE_T("RESULT: (int) [%lld]\n"), (long long)r.toInt()); + qse_printf (QSE_T(" (real) [%Lf]\n"), (long double)r.toReal()); + qse_printf (QSE_T(" (str) [%s]\n"), r.toStr(QSE_NULL)); + + // call the 'pb' function + if (awk.call (QSE_T("pb"), &r, arg, QSE_COUNTOF(arg)) <= -1) return -1; + + // output the returned map. + QSE_ASSERT (r.isIndexed()); + + QSE::StdAwk::Value::IndexIterator iter; + QSE::StdAwk::Value::Index idx; + QSE::StdAwk::Value v; + + qse_printf (QSE_T("RESULT:\n")); + + iter = r.getFirstIndex (&idx); + while (iter != QSE::StdAwk::Value::IndexIterator::END) + { + if (r.getIndexed (idx, &v) <= -1) return -1; + + qse_printf (QSE_T("\t[%.*s]=>[%lld]\n"), + (int)idx.len, idx.ptr, (long long)v.toInt()); + + iter = r.getNextIndex (&idx, iter); + } + + return 0; } static int awk_main (int argc, qse_char_t* argv[]) { - MyAwk awk; - MyAwk::Run* run; + QSE::StdAwk awk; - int mode = 0; - const qse_char_t* srcin = QSE_T(""); - const qse_char_t* srcout = NULL; - qse_size_t nsrcins = 0; - qse_size_t nsrcouts = 0; + int ret = awk.open(); - if (awk.open() <= -1) - { - print_error (awk.getErrorMessage()); - return -1; - } + // allow returning a map from a function and enable 'reset' + awk.setOption ( + awk.getOption() | + QSE::StdAwk::OPT_MAPTOVAR | + QSE::StdAwk::OPT_RESET); - // ARGV[0] - if (awk.addArgument (QSE_T("awk05")) <= -1) - { - print_error (awk.getErrorMessage()); - awk.close (); - return -1; - } + if (ret >= 0) ret = run_awk (awk); + if (ret <= -1) print_error (awk.getErrorLine(), awk.getErrorMessage()); - for (int i = 1; i < argc; i++) - { - if (mode == 0) - { - if (qse_strcmp(argv[i], QSE_T("-si")) == 0) mode = 1; - else if (qse_strcmp(argv[i], QSE_T("-so")) == 0) mode = 2; - else if (qse_strcmp(argv[i], QSE_T("-ci")) == 0) mode = 3; - else if (qse_strcmp(argv[i], QSE_T("-co")) == 0) mode = 4; - else if (qse_strcmp(argv[i], QSE_T("-w")) == 0) mode = 5; - else if (qse_strcmp(argv[i], QSE_T("-v")) == 0) - { - verbose = true; - } - else - { - if (argv[i][0] == QSE_T('-')) - { - int j; - - if (argv[i][1] == QSE_T('n') && argv[i][2] == QSE_T('o')) - { - for (j = 0; j < (int)QSE_COUNTOF(otab); j++) - { - if (qse_strcmp(&argv[i][3], otab[j].name) == 0) - { - awk.setOption (awk.getOption() & ~otab[j].opt); - goto ok_valid; - } - } - } - else - { - for (j = 0; j < (int)QSE_COUNTOF(otab); j++) - { - if (qse_strcmp(&argv[i][1], otab[j].name) == 0) - { - awk.setOption (awk.getOption() | otab[j].opt); - goto ok_valid; - } - } - } - } - - print_usage (argv[0]); - return -1; - - ok_valid: - ; - } - } - else - { - if (argv[i][0] == QSE_T('-')) - { - print_usage (argv[0]); - return -1; - } - - if (mode == 1) // source input - { - if (nsrcins != 0) - { - print_usage (argv[0]); - return -1; - } - - srcin = argv[i]; - nsrcins++; - mode = 0; - } - else if (mode == 2) // source output - { - if (nsrcouts != 0) - { - print_usage (argv[0]); - return -1; - } - - srcout = argv[i]; - nsrcouts++; - mode = 0; - } - else if (mode == 3) // console input - { - if (awk.addArgument (argv[i]) <= -1) - { - print_error (QSE_T("too many console inputs")); - return -1; - } - - mode = 0; - } - else if (mode == 4) // console output - { - if (awk.addConsoleOutput (argv[i]) <= -1) - { - print_error (QSE_T("too many console outputs")); - return -1; - } - - mode = 0; - } - else if (mode == 5) // word replacement - { - const qse_char_t* p; - qse_size_t l; - - p = qse_strchr(argv[i], QSE_T(':')); - if (p == QSE_NULL) - { - print_usage (argv[0]); - return -1; - } - - l = qse_strlen (argv[i]); - - awk.setWord ( - argv[i], p - argv[i], - p + 1, l - (p - argv[i] + 1)); - - mode = 0; - } - } - } - - if (mode != 0) - { - print_usage (argv[0]); - awk.close (); - return -1; - } - - run = awk.parse (srcin, srcout); - if (run == QSE_NULL) - { - qse_fprintf (stderr, QSE_T("cannot parse: LINE[%d] %s\n"), - awk.getErrorLine(), awk.getErrorMessage()); - awk.close (); - return -1; - } - - awk.enableRunCallback (); - app_awk = &awk; - - if (awk.loop () <= -1) - { - qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"), - awk.getErrorLine(), awk.getErrorMessage()); - awk.close (); - return -1; - } - -#if 0 - MyAwk::Return args[2]; - - args[0].setRun (run); - args[1].setRun (run); - - if (awk.call (QSE_T("add"), args, 2) <= -1) - { - qse_fprintf (stderr, QSE_T("cannot run: LINE[%d] %s\n"), - awk.getErrorLine(), awk.getErrorMessage()); - awk.close (); - } -#endif - - app_awk = QSE_NULL; awk.close (); - - return 0; + return -1; } int qse_main (int argc, qse_achar_t* argv[]) diff --git a/qse/samples/awk/awk08.cpp b/qse/samples/awk/awk08.cpp new file mode 100644 index 00000000..c6421646 --- /dev/null +++ b/qse/samples/awk/awk08.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); +}