/* * $Id: val.c 380 2008-09-24 08:16:41Z baconevi $ * * {License} */ #include "awk.h" #ifdef DEBUG_VAL #include #endif #define CHUNKSIZE 100 typedef struct ase_awk_val_ichunk_t ase_awk_val_ichunk_t; typedef struct ase_awk_val_rchunk_t ase_awk_val_rchunk_t; struct ase_awk_val_chunk_t { ase_awk_val_chunk_t* next; }; struct ase_awk_val_ichunk_t { ase_awk_val_chunk_t* next; /* make sure that it has the same fields as ase_awk_val_chunk_t up to this point */ ase_awk_val_int_t slot[CHUNKSIZE]; }; struct ase_awk_val_rchunk_t { ase_awk_val_chunk_t* next; /* make sure that it has the same fields as ase_awk_val_chunk_t up to this point */ ase_awk_val_real_t slot[CHUNKSIZE]; }; static ase_char_t* str_to_str ( ase_awk_run_t* run, const ase_char_t* str, ase_size_t str_len, int opt, ase_str_t* buf, ase_size_t* len); static ase_char_t* val_int_to_str ( ase_awk_run_t* run, ase_awk_val_int_t* v, int opt, ase_str_t* buf, ase_size_t* len); static ase_char_t* val_real_to_str ( ase_awk_run_t* run, ase_awk_val_real_t* v, int opt, ase_str_t* buf, ase_size_t* len); static ase_awk_val_nil_t awk_nil = { ASE_AWK_VAL_NIL, 0 }; static ase_awk_val_str_t awk_zls = { ASE_AWK_VAL_STR, 0, ASE_T(""), 0 }; ase_awk_val_t* ase_awk_val_nil = (ase_awk_val_t*)&awk_nil; ase_awk_val_t* ase_awk_val_zls = (ase_awk_val_t*)&awk_zls; static ase_awk_val_int_t awk_int[] = { { ASE_AWK_VAL_INT, 0, -1, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 0, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 1, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 2, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 3, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 4, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 5, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 6, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 7, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 8, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 9, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 10, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 11, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 12, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 13, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 14, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 15, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 16, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 17, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 18, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 19, ASE_NULL }, { ASE_AWK_VAL_INT, 0, 20, ASE_NULL } }; ase_awk_val_t* ase_awk_val_negone = (ase_awk_val_t*)&awk_int[0]; ase_awk_val_t* ase_awk_val_zero = (ase_awk_val_t*)&awk_int[1]; ase_awk_val_t* ase_awk_val_one = (ase_awk_val_t*)&awk_int[2]; ase_awk_val_t* ase_awk_makeintval (ase_awk_run_t* run, ase_long_t v) { ase_awk_val_int_t* val; if (v >= awk_int[0].val && v <= awk_int[ASE_COUNTOF(awk_int)-1].val) { return (ase_awk_val_t*)&awk_int[v-awk_int[0].val]; } /* if (run->icache_count > 0) { val = run->icache[--run->icache_count]; } else { val = (ase_awk_val_int_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_int_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } } */ if (run->vmgr.ifree == ASE_NULL) { ase_awk_val_ichunk_t* c; ase_awk_val_int_t* x; ase_size_t i; /* use ase_awk_val_ichunk structure to avoid * any alignment issues on platforms requiring * aligned memory access - using the code commented out * will cause a fault on such a platform */ /* c = ASE_AWK_ALLOC (run->awk, ASE_SIZEOF(ase_awk_val_chunk_t)+ ASE_SIZEOF(ase_awk_val_int_t)*CHUNKSIZE); */ c = ASE_AWK_ALLOC (run->awk, ASE_SIZEOF(ase_awk_val_ichunk_t)); if (c == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } c->next = run->vmgr.ichunk; /*run->vmgr.ichunk = c;*/ run->vmgr.ichunk = (ase_awk_val_chunk_t*)c; /*x = (ase_awk_val_int_t*)(c + 1); for (i = 0; i < CHUNKSIZE-1; i++) x[i].nde = (ase_awk_nde_int_t*)&x[i+1]; x[i].nde = ASE_NULL; run->vmgr.ifree = x; */ for (i = 0; i < CHUNKSIZE-1; i++) c->slot[i].nde = (ase_awk_nde_int_t*)&c->slot[i+1]; c->slot[i].nde = ASE_NULL; run->vmgr.ifree = &c->slot[0]; } val = run->vmgr.ifree; run->vmgr.ifree = (ase_awk_val_int_t*)val->nde; val->type = ASE_AWK_VAL_INT; val->ref = 0; val->val = v; val->nde = ASE_NULL; #ifdef DEBUG_VAL ase_dprintf (ASE_T("makeintval => %ld [%p]\n"), (long)v, val); #endif return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makerealval (ase_awk_run_t* run, ase_real_t v) { ase_awk_val_real_t* val; /* if (run->rcache_count > 0) { val = run->rcache[--run->rcache_count]; } else { val = (ase_awk_val_real_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_real_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } } */ if (run->vmgr.rfree == ASE_NULL) { ase_awk_val_rchunk_t* c; ase_awk_val_real_t* x; ase_size_t i; /* c = ASE_AWK_ALLOC (run->awk, ASE_SIZEOF(ase_awk_val_chunk_t)+ ASE_SIZEOF(ase_awk_val_real_t)*CHUNKSIZE); */ c = ASE_AWK_ALLOC (run->awk, ASE_SIZEOF(ase_awk_val_rchunk_t)); if (c == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } c->next = run->vmgr.rchunk; /*run->vmgr.rchunk = c;*/ run->vmgr.rchunk = (ase_awk_val_chunk_t*)c; /* x = (ase_awk_val_real_t*)(c + 1); for (i = 0; i < CHUNKSIZE-1; i++) x[i].nde = (ase_awk_nde_real_t*)&x[i+1]; x[i].nde = ASE_NULL; run->vmgr.rfree = x; */ for (i = 0; i < CHUNKSIZE-1; i++) c->slot[i].nde = (ase_awk_nde_real_t*)&c->slot[i+1]; c->slot[i].nde = ASE_NULL; run->vmgr.rfree = &c->slot[0]; } val = run->vmgr.rfree; run->vmgr.rfree = (ase_awk_val_real_t*)val->nde; val->type = ASE_AWK_VAL_REAL; val->ref = 0; val->val = v; val->nde = ASE_NULL; #ifdef DEBUG_VAL ase_dprintf (ASE_T("makerealval => %Lf [%p]\n"), (double)v, val); #endif return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makestrval0 (ase_awk_run_t* run, const ase_char_t* str) { return ase_awk_makestrval (run, str, ase_strlen(str)); } ase_awk_val_t* ase_awk_makestrval ( ase_awk_run_t* run, const ase_char_t* str, ase_size_t len) { ase_awk_val_str_t* val; ase_size_t rlen = len; /*if (rlen <= 32) { if (run->scache32_count > 0) { val = run->scache32[--run->scache32_count]; goto init; } rlen = 32; } else if (rlen <= 64) { if (run->scache64_count > 0) { val = run->scache64[--run->scache64_count]; goto init; } rlen = 64; }*/ val = (ase_awk_val_str_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_str_t) + (rlen+1)*ASE_SIZEOF(ase_char_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } init: val->type = ASE_AWK_VAL_STR; val->ref = 0; val->len = len; val->buf = (ase_char_t*)(val + 1); /*ase_strxncpy (val->buf, len+1, str, len);*/ ase_strncpy (val->buf, str, len); #ifdef DEBUG_VAL ase_dprintf (ASE_T("makestrval => %p\n"), val); #endif return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makestrval_nodup ( ase_awk_run_t* run, ase_char_t* str, ase_size_t len) { ase_awk_val_str_t* val; val = (ase_awk_val_str_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_str_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } val->type = ASE_AWK_VAL_STR; val->ref = 0; val->len = len; val->buf = str; return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makestrval2 ( ase_awk_run_t* run, const ase_char_t* str1, ase_size_t len1, const ase_char_t* str2, ase_size_t len2) { ase_awk_val_str_t* val; ase_size_t rlen = len1 + len2; /*if (rlen <= 32) { if (run->scache32_count > 0) { val = run->scache32[--run->scache32_count]; goto init; } rlen = 32; } else if (rlen <= 64) { if (run->scache64_count > 0) { val = run->scache64[--run->scache64_count]; goto init; } rlen = 64; }*/ val = (ase_awk_val_str_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_str_t) + (rlen+1)*ASE_SIZEOF(ase_char_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } init: val->type = ASE_AWK_VAL_STR; val->ref = 0; val->len = len1 + len2; val->buf = (ase_char_t*)(val + 1); /*ase_strxncpy (val->buf, len1+1, str1, len1); ase_strxncpy (val->buf[len1], len2+1, str2, len2);*/ ase_strncpy (val->buf, str1, len1); ase_strncpy (&val->buf[len1], str2, len2); #ifdef DEBUG_VAL ase_dprintf (ASE_T("makestrval2 => %p\n"), val); #endif return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makerexval ( ase_awk_run_t* run, const ase_char_t* buf, ase_size_t len, void* code) { ase_awk_val_rex_t* val; val = (ase_awk_val_rex_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_rex_t) + (ASE_SIZEOF(*buf)*len+1) + ASE_REX_LEN(code)); if (val == ASE_NULL) return ASE_NULL; val->type = ASE_AWK_VAL_REX; val->ref = 0; val->len = len; /* val->buf = ASE_AWK_STRXDUP (run->awk, buf, len); if (val->buf == ASE_NULL) { ASE_AWK_FREE (run->awk, val); ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; }*/ val->buf = (ase_char_t*)(val + 1); ase_strncpy (val->buf, buf, len); /* val->code = ASE_AWK_ALLOC (run->awk, ASE_REX_LEN(code)); if (val->code == ASE_NULL) { ASE_AWK_FREE (run->awk, val->buf); ASE_AWK_FREE (run->awk, val); ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } */ val->code = val->buf + len + 1; ASE_MEMCPY (val->code, code, ASE_REX_LEN(code)); return (ase_awk_val_t*)val; } /* CHECK */ /* static void free_mapval (void* run, void* v) { #ifdef DEBUG_VAL ase_dprintf (ASE_T("refdown in map free...")); ase_awk_dprintval (run, v); ase_dprintf (ASE_T("\n")); #endif ase_awk_refdownval (run, v); } static void same_mapval (void* run, void* v) { #ifdef DEBUG_VAL ase_dprintf (ASE_T("refdown nofree in map free...")); ase_awk_dprintval (run, v); ase_dprintf (ASE_T("\n")); #endif ase_awk_refdownval_nofree (run, v); } */ static void free_mapval (ase_map_t* map, void* dptr, ase_size_t dlen) { ase_awk_run_t* run = *(ase_awk_run_t**)ASE_MAP_EXTENSION(map); #ifdef DEBUG_VAL ase_dprintf (ASE_T("refdown in map free...")); ase_awk_dprintval (run, dptr); ase_dprintf (ASE_T("\n")); #endif ase_awk_refdownval (run, dptr); } static void same_mapval (ase_map_t* map, void* dptr, ase_size_t dlen) { ase_awk_run_t* run = *(ase_awk_run_t**)ASE_MAP_EXTENSION(map); #ifdef DEBUG_VAL ase_dprintf (ASE_T("refdown nofree in map free...")); ase_awk_dprintval (run, dptr); ase_dprintf (ASE_T("\n")); #endif ase_awk_refdownval_nofree (run, dptr); } /* END CHECK */ ase_awk_val_t* ase_awk_makemapval (ase_awk_run_t* run) { ase_awk_val_map_t* val; val = (ase_awk_val_map_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_map_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } val->type = ASE_AWK_VAL_MAP; val->ref = 0; /* CHECK */ /* val->map = ase_map_open ( run, 256, 70, free_mapval, same_mapval, run->awk->mmgr); if (val->map == ASE_NULL) { ASE_AWK_FREE (run->awk, val); ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } */ val->map = ase_map_open (run->awk->mmgr, ASE_SIZEOF(run), 256, 70); if (val->map == ASE_NULL) { ASE_AWK_FREE (run->awk, val); ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } *(ase_awk_run_t**)ASE_MAP_EXTENSION(val->map) = run; /* the key is copied inline into a pair and is freed when the pair * is destroyed */ ase_map_setcopier (val->map, ASE_MAP_KEY, ASE_MAP_COPIER_INLINE); /* not setting copier for a value means that the pointer to the data * allocated somewhere else is remembered in a pair. but the freeing * the actual value is handled by free_mapval and same_mapval */ ase_map_setfreeer (val->map, ASE_MAP_VAL, free_mapval); ase_map_setkeeper (val->map, same_mapval); /* END CHECK */ return (ase_awk_val_t*)val; } ase_awk_val_t* ase_awk_makerefval (ase_awk_run_t* run, int id, ase_awk_val_t** adr) { ase_awk_val_ref_t* val; if (run->fcache_count > 0) { val = run->fcache[--run->fcache_count]; } else { val = (ase_awk_val_ref_t*) ASE_AWK_ALLOC ( run->awk, ASE_SIZEOF(ase_awk_val_ref_t)); if (val == ASE_NULL) { ase_awk_setrunerrnum (run, ASE_AWK_ENOMEM); return ASE_NULL; } } val->type = ASE_AWK_VAL_REF; val->ref = 0; val->id = id; val->adr = adr; return (ase_awk_val_t*)val; } #define IS_STATICVAL(val) \ ((val) == ASE_NULL || \ (val) == ase_awk_val_nil || \ (val) == ase_awk_val_zls || \ (val) == ase_awk_val_zero || \ (val) == ase_awk_val_one || \ ((val) >= (ase_awk_val_t*)&awk_int[0] && \ (val) <= (ase_awk_val_t*)&awk_int[ASE_COUNTOF(awk_int)-1])) ase_bool_t ase_awk_isstaticval (ase_awk_val_t* val) { return IS_STATICVAL(val); } void ase_awk_freeval (ase_awk_run_t* run, ase_awk_val_t* val, ase_bool_t cache) { if (IS_STATICVAL(val)) return; #ifdef DEBUG_VAL ase_dprintf (ASE_T("freeing [cache=%d] ... "), cache); ase_awk_dprintval (run, val); ase_dprintf (ASE_T("\n")); #endif if (val->type == ASE_AWK_VAL_NIL) { ASE_AWK_FREE (run->awk, val); } else if (val->type == ASE_AWK_VAL_INT) { /* if (cache && run->icache_count < ASE_COUNTOF(run->icache)) { run->icache[run->icache_count++] = (ase_awk_val_int_t*)val; } else ASE_AWK_FREE (run->awk, val); */ ((ase_awk_val_int_t*)val)->nde = (ase_awk_nde_int_t*)run->vmgr.ifree; run->vmgr.ifree = (ase_awk_val_int_t*)val; } else if (val->type == ASE_AWK_VAL_REAL) { /* if (cache && run->rcache_count < ASE_COUNTOF(run->rcache)) { run->rcache[run->rcache_count++] = (ase_awk_val_real_t*)val; } else ASE_AWK_FREE (run->awk, val); */ ((ase_awk_val_real_t*)val)->nde = (ase_awk_nde_real_t*)run->vmgr.rfree; run->vmgr.rfree = (ase_awk_val_real_t*)val; } else if (val->type == ASE_AWK_VAL_STR) { /* if (cache) { ase_awk_val_str_t* v = (ase_awk_val_str_t*)val; if (v->len <= 32 && run->scache32_countscache32)) { run->scache32[run->scache32_count++] = v; } else if (v->len <= 64 && run->scache64_countscache64)) { run->scache64[run->scache64_count++] = v; } else ASE_AWK_FREE (run->awk, val); } else*/ ASE_AWK_FREE (run->awk, val); } else if (val->type == ASE_AWK_VAL_REX) { /* ASE_AWK_FREE (run->awk, ((ase_awk_val_rex_t*)val)->buf); ASE_AWK_FREEREX (run->awk, ((ase_awk_val_rex_t*)val)->code); */ ASE_AWK_FREE (run->awk, val); } else if (val->type == ASE_AWK_VAL_MAP) { ase_map_close (((ase_awk_val_map_t*)val)->map); ASE_AWK_FREE (run->awk, val); } else if (val->type == ASE_AWK_VAL_REF) { if (cache && run->fcache_count < ASE_COUNTOF(run->fcache)) { run->fcache[run->fcache_count++] = (ase_awk_val_ref_t*)val; } else ASE_AWK_FREE (run->awk, val); } else { ASE_ASSERTX ( !"should never happen - invalid value type", "the type of a value should be one of ASE_AWK_VAL_XXX's defined in awk.h"); } } void ase_awk_refupval (ase_awk_run_t* run, ase_awk_val_t* val) { if (IS_STATICVAL(val)) return; #ifdef DEBUG_VAL ase_dprintf (ASE_T("ref up [ptr=%p] [count=%d] "), val, (int)val->ref); ase_awk_dprintval (run, val); ase_dprintf (ASE_T("\n")); #endif val->ref++; } void ase_awk_refdownval (ase_awk_run_t* run, ase_awk_val_t* val) { if (IS_STATICVAL(val)) return; #ifdef DEBUG_VAL ase_dprintf (ASE_T("ref down [ptr=%p] [count=%d]\n"), val, (int)val->ref); ase_awk_dprintval (run, val); ase_dprintf (ASE_T("\n")); #endif ASE_ASSERTX (val->ref > 0, "the reference count of a value should be greater than zero for it to be decremented. check the source code for any bugs"); val->ref--; if (val->ref <= 0) { ase_awk_freeval(run, val, ASE_TRUE); } } void ase_awk_refdownval_nofree (ase_awk_run_t* run, ase_awk_val_t* val) { if (IS_STATICVAL(val)) return; ASE_ASSERTX (val->ref > 0, "the reference count of a value should be greater than zero for it to be decremented. check the source code for any bugs"); val->ref--; } void ase_awk_freevalchunk (ase_awk_run_t* run, ase_awk_val_chunk_t* chunk) { while (chunk != ASE_NULL) { ase_awk_val_chunk_t* next = chunk->next; ASE_AWK_FREE (run->awk, chunk); chunk = next; } } ase_bool_t ase_awk_valtobool (ase_awk_run_t* run, ase_awk_val_t* val) { if (val == ASE_NULL) return ASE_FALSE; switch (val->type) { case ASE_AWK_VAL_NIL: return ASE_FALSE; case ASE_AWK_VAL_INT: return ((ase_awk_val_int_t*)val)->val != 0; case ASE_AWK_VAL_REAL: return ((ase_awk_val_real_t*)val)->val != 0.0; case ASE_AWK_VAL_STR: return ((ase_awk_val_str_t*)val)->len > 0; case ASE_AWK_VAL_REX: /* TODO: is this correct? */ return ((ase_awk_val_rex_t*)val)->len > 0; case ASE_AWK_VAL_MAP: return ASE_FALSE; /* TODO: is this correct? */ case ASE_AWK_VAL_REF: return ASE_FALSE; /* TODO: is this correct? */ } ASE_ASSERTX ( !"should never happen - invalid value type", "the type of a value should be one of ASE_AWK_VAL_XXX's defined in awk.h"); return ASE_FALSE; } ase_char_t* ase_awk_valtostr ( ase_awk_run_t* run, ase_awk_val_t* v, int opt, ase_str_t* buf, ase_size_t* len) { if (v->type == ASE_AWK_VAL_NIL) { return str_to_str (run, ASE_T(""), 0, opt, buf, len); } if (v->type == ASE_AWK_VAL_INT) { ase_awk_val_int_t* vi = (ase_awk_val_int_t*)v; /* if (vi->nde != ASE_NULL && vi->nde->str != ASE_NULL) { return str_to_str ( run, vi->nde->str, vi->nde->len, opt, buf, len); } else {*/ return val_int_to_str (run, vi, opt, buf, len); /*}*/ } if (v->type == ASE_AWK_VAL_REAL) { ase_awk_val_real_t* vr = (ase_awk_val_real_t*)v; /* if (vr->nde != ASE_NULL && vr->nde->str != ASE_NULL) { return str_to_str ( run, vr->nde->str, vr->nde->len, opt, buf, len); } else {*/ return val_real_to_str (run, vr, opt, buf, len); /*}*/ } if (v->type == ASE_AWK_VAL_STR) { ase_awk_val_str_t* vs = (ase_awk_val_str_t*)v; return str_to_str ( run, vs->buf, vs->len, opt, buf, len); } #ifdef DEBUG_VAL ase_dprintf ( ASE_T("ERROR: WRONG VALUE TYPE [%d] in ase_awk_valtostr\n"), v->type); #endif ase_awk_setrunerror (run, ASE_AWK_EVALTYPE, 0, ASE_NULL, 0); return ASE_NULL; } static ase_char_t* str_to_str ( ase_awk_run_t* run, const ase_char_t* str, ase_size_t str_len, int opt, ase_str_t* buf, ase_size_t* len) { if (buf == ASE_NULL) { ase_char_t* tmp; tmp = ASE_AWK_STRXDUP (run->awk, str, str_len); if (tmp == ASE_NULL) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } if (len != ASE_NULL) *len = str_len; return tmp; } else if (opt & ASE_AWK_VALTOSTR_FIXED) { ASE_ASSERT (buf != ASE_NULL && len != ASE_NULL); if (str_len >= *len) { ase_awk_setrunerror ( run, ASE_AWK_EINVAL, 0, ASE_NULL, 0); *len = str_len + 1; return ASE_NULL; } *len = ase_strncpy ((ase_char_t*)buf, str, str_len); return (ase_char_t*)buf; } else { ase_size_t n; if (opt & ASE_AWK_VALTOSTR_CLEAR) ase_str_clear (buf); n = ase_str_ncat (buf, str, str_len); if (n == (ase_size_t)-1) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } if (len != ASE_NULL) *len = ASE_STR_LEN(buf); return ASE_STR_PTR(buf); } } static ase_char_t* val_int_to_str ( ase_awk_run_t* run, ase_awk_val_int_t* v, int opt, ase_str_t* buf, ase_size_t* len) { ase_char_t* tmp; ase_long_t t; ase_size_t rlen = 0; t = v->val; if (t == 0) { /* handle zero */ if (buf == ASE_NULL) { tmp = ASE_AWK_ALLOC ( run->awk, 2 * ASE_SIZEOF(ase_char_t)); if (tmp == ASE_NULL) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } tmp[0] = ASE_T('0'); tmp[1] = ASE_T('\0'); if (len != ASE_NULL) *len = 1; return tmp; } else if (opt & ASE_AWK_VALTOSTR_FIXED) { ASE_ASSERT (buf != ASE_NULL && len != ASE_NULL); if (1 >= *len) { ase_awk_setrunerror ( run, ASE_AWK_EINVAL, 0, ASE_NULL, 0); *len = 2; /* buffer size required */ return ASE_NULL; } tmp = (ase_char_t*)buf; tmp[0] = ASE_T('0'); tmp[1] = ASE_T('\0'); *len = 1; /* actual length */ return tmp; } else { if (opt & ASE_AWK_VALTOSTR_CLEAR) ase_str_clear (buf); if (ase_str_cat (buf, ASE_T("0")) == (ase_size_t)-1) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } if (len != ASE_NULL) *len = ASE_STR_LEN(buf); return ASE_STR_PTR(buf); } } /* non-zero values */ if (t < 0) { t = -t; rlen++; } while (t > 0) { rlen++; t /= 10; } if (buf == ASE_NULL) { tmp = ASE_AWK_ALLOC ( run->awk, (rlen + 1) * ASE_SIZEOF(ase_char_t)); if (tmp == ASE_NULL) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } tmp[rlen] = ASE_T('\0'); if (len != ASE_NULL) *len = rlen; } else if (opt & ASE_AWK_VALTOSTR_FIXED) { ASE_ASSERT (buf != ASE_NULL && len != ASE_NULL); if (rlen >= *len) { ase_awk_setrunerror ( run, ASE_AWK_EINVAL, 0, ASE_NULL, 0); *len = rlen + 1; /* buffer size required */ return ASE_NULL; } tmp = (ase_char_t*)buf; tmp[rlen] = ASE_T('\0'); *len = rlen; /* actual length */ } else { /* clear the buffer */ if (opt & ASE_AWK_VALTOSTR_CLEAR) ase_str_clear (buf); tmp = ASE_STR_PTR(buf) + ASE_STR_LEN(buf); /* extend the buffer */ if (ase_str_nccat ( buf, ASE_T(' '), rlen) == (ase_size_t)-1) { ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } } t = v->val; if (t < 0) t = -t; while (t > 0) { tmp[--rlen] = (ase_char_t)(t % 10) + ASE_T('0'); t /= 10; } if (v->val < 0) tmp[--rlen] = ASE_T('-'); if (buf != ASE_NULL && !(opt & ASE_AWK_VALTOSTR_FIXED)) { tmp = ASE_STR_PTR(buf); if (len != ASE_NULL) *len = ASE_STR_LEN(buf); } return tmp; } static ase_char_t* val_real_to_str ( ase_awk_run_t* run, ase_awk_val_real_t* v, int opt, ase_str_t* buf, ase_size_t* len) { ase_char_t* tmp; ase_size_t tmp_len; ase_str_t out, fbu; if (opt & ASE_AWK_VALTOSTR_PRINT) { tmp = run->global.ofmt.ptr; tmp_len = run->global.ofmt.len; } else { tmp = run->global.convfmt.ptr; tmp_len = run->global.convfmt.len; } if (ase_str_init (&out, run->awk->mmgr, 256) == ASE_NULL) { ase_awk_setrunerror (run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } if (ase_str_init (&fbu, run->awk->mmgr, 256) == ASE_NULL) { ase_str_fini (&out); ase_awk_setrunerror (run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } tmp = ase_awk_format (run, &out, &fbu, tmp, tmp_len, (ase_size_t)-1, (ase_awk_nde_t*)v, &tmp_len); if (tmp == ASE_NULL) { ase_str_fini (&fbu); ase_str_fini (&out); return ASE_NULL; } if (buf == ASE_NULL) { ase_str_fini (&fbu); ase_str_yield (&out, ASE_NULL, 0); ase_str_fini (&out); if (len != ASE_NULL) *len = tmp_len; } else if (opt & ASE_AWK_VALTOSTR_FIXED) { ASE_ASSERT (buf != ASE_NULL && len != ASE_NULL); if (tmp_len >= *len) { ase_awk_setrunerror ( run, ASE_AWK_EINVAL, 0, ASE_NULL, 0); *len = tmp_len + 1; /* buffer size required */ ase_str_close (&fbu); ase_str_close (&out); return ASE_NULL; } ase_strncpy ((ase_char_t*)buf, tmp, tmp_len); tmp = (ase_char_t*)buf; *len = tmp_len; ase_str_fini (&fbu); ase_str_fini (&out); } else { if (opt & ASE_AWK_VALTOSTR_CLEAR) ase_str_clear (buf); if (ase_str_ncat (buf, tmp, tmp_len) == (ase_size_t)-1) { ase_str_fini (&fbu); ase_str_fini (&out); ase_awk_setrunerror ( run, ASE_AWK_ENOMEM, 0, ASE_NULL, 0); return ASE_NULL; } tmp = ASE_STR_PTR(buf); if (len != ASE_NULL) *len = ASE_STR_LEN(buf); ase_str_fini (&fbu); ase_str_fini (&out); } return tmp; } int ase_awk_valtonum ( ase_awk_run_t* run, ase_awk_val_t* v, ase_long_t* l, ase_real_t* r) { if (v->type == ASE_AWK_VAL_NIL) { *l = 0; return 0; } if (v->type == ASE_AWK_VAL_INT) { *l = ((ase_awk_val_int_t*)v)->val; return 0; /* long */ } if (v->type == ASE_AWK_VAL_REAL) { *r = ((ase_awk_val_real_t*)v)->val; return 1; /* real */ } if (v->type == ASE_AWK_VAL_STR) { return ase_awk_strtonum (run, ((ase_awk_val_str_t*)v)->buf, ((ase_awk_val_str_t*)v)->len, l, r); } #ifdef DEBUG_VAL ase_dprintf ( ASE_T("ERROR: WRONG VALUE TYPE [%d] in ase_awk_valtonum\n"), v->type); #endif ase_awk_setrunerror (run, ASE_AWK_EVALTYPE, 0, ASE_NULL, 0); return -1; /* error */ } int ase_awk_strtonum ( ase_awk_run_t* run, const ase_char_t* ptr, ase_size_t len, ase_long_t* l, ase_real_t* r) { const ase_char_t* endptr; *l = ase_awk_strxtolong (run->awk, ptr, len, 0, &endptr); if (*endptr == ASE_T('.') || *endptr == ASE_T('E') || *endptr == ASE_T('e')) { *r = ase_awk_strxtoreal (run->awk, ptr, len, ASE_NULL); /* TODO: need to check if it is a valid number using * endptr for strxtoreal? */ return 1; /* real */ } /* TODO: do should i handle strings ending with invalid number * characters like "123xx" or "dkdkdkd"? */ return 0; /* long */ } #define DPRINTF run->awk->prmfns->dprintf #define DCUSTOM run->awk->prmfns->data static ase_map_walk_t print_pair ( ase_map_t* map, ase_map_pair_t* pair, void* arg) { ase_awk_run_t* run = (ase_awk_run_t*)arg; ASE_ASSERT (run == *(ase_awk_run_t**)ASE_MAP_EXTENSION(map)); DPRINTF (DCUSTOM, ASE_T(" %.*s=>"), (int)ASE_MAP_KCLEN(pair), ASE_MAP_KPTR(pair)); ase_awk_dprintval ((ase_awk_run_t*)arg, ASE_MAP_VPTR(pair)); DPRINTF (DCUSTOM, ASE_T(" ")); return ASE_MAP_WALK_FORWARD; } void ase_awk_dprintval (ase_awk_run_t* run, ase_awk_val_t* val) { /* TODO: better value printing ... */ switch (val->type) { case ASE_AWK_VAL_NIL: DPRINTF (DCUSTOM, ASE_T("nil")); break; case ASE_AWK_VAL_INT: #if ASE_SIZEOF_LONG_LONG > 0 DPRINTF (DCUSTOM, ASE_T("%lld"), (long long)((ase_awk_val_int_t*)val)->val); #elif ASE_SIZEOF___INT64 > 0 DPRINTF (DCUSTOM, ASE_T("%I64d"), (__int64)((ase_awk_val_int_t*)val)->val); #elif ASE_SIZEOF_LONG > 0 DPRINTF (DCUSTOM, ASE_T("%ld"), (long)((ase_awk_val_int_t*)val)->val); #elif ASE_SIZEOF_INT > 0 DPRINTF (DCUSTOM, ASE_T("%d"), (int)((ase_awk_val_int_t*)val)->val); #else #error unsupported size #endif break; case ASE_AWK_VAL_REAL: DPRINTF (DCUSTOM, ASE_T("%Lf"), (long double)((ase_awk_val_real_t*)val)->val); break; case ASE_AWK_VAL_STR: DPRINTF (DCUSTOM, ASE_T("%s"), ((ase_awk_val_str_t*)val)->buf); break; case ASE_AWK_VAL_REX: DPRINTF (DCUSTOM, ASE_T("REX[%s]"), ((ase_awk_val_rex_t*)val)->buf); break; case ASE_AWK_VAL_MAP: DPRINTF (DCUSTOM, ASE_T("MAP[")); ase_map_walk (((ase_awk_val_map_t*)val)->map, print_pair, run); DPRINTF (DCUSTOM, ASE_T("]")); break; case ASE_AWK_VAL_REF: DPRINTF (DCUSTOM, ASE_T("REF[id=%d,val="), ((ase_awk_val_ref_t*)val)->id); ase_awk_dprintval (run, *((ase_awk_val_ref_t*)val)->adr); DPRINTF (DCUSTOM, ASE_T("]")); break; default: DPRINTF (DCUSTOM, ASE_T("**** INTERNAL ERROR - INVALID VALUE TYPE ****\n")); } }