/* * $Id: val.c,v 1.75 2006-10-22 12:39:30 bacon Exp $ */ #include static sse_char_t* __str_to_str ( sse_awk_run_t* run, const sse_char_t* str, sse_size_t str_len, int opt, sse_awk_str_t* buf, sse_size_t* len); static sse_char_t* __val_int_to_str ( sse_awk_run_t* run, sse_awk_val_int_t* v, int opt, sse_awk_str_t* buf, sse_size_t* len); static sse_char_t* __val_real_to_str ( sse_awk_run_t* run, sse_awk_val_real_t* v, int opt, sse_awk_str_t* buf, sse_size_t* len); static sse_awk_val_nil_t __awk_nil = { SSE_AWK_VAL_NIL, 0 }; sse_awk_val_t* sse_awk_val_nil = (sse_awk_val_t*)&__awk_nil; static sse_awk_val_str_t __awk_zls = { SSE_AWK_VAL_STR, 0, SSE_T(""), 0 }; sse_awk_val_t* sse_awk_val_zls = (sse_awk_val_t*)&__awk_zls; static sse_awk_val_int_t __awk_int[] = { { SSE_AWK_VAL_INT, 0, -1 }, { SSE_AWK_VAL_INT, 0, 0 }, { SSE_AWK_VAL_INT, 0, 1 }, { SSE_AWK_VAL_INT, 0, 2 }, { SSE_AWK_VAL_INT, 0, 3 }, { SSE_AWK_VAL_INT, 0, 4 }, { SSE_AWK_VAL_INT, 0, 5 }, { SSE_AWK_VAL_INT, 0, 6 }, { SSE_AWK_VAL_INT, 0, 7 }, { SSE_AWK_VAL_INT, 0, 8 }, { SSE_AWK_VAL_INT, 0, 9 }, }; sse_awk_val_t* sse_awk_val_zero = (sse_awk_val_t*)&__awk_int[1]; sse_awk_val_t* sse_awk_val_one = (sse_awk_val_t*)&__awk_int[2]; sse_awk_val_t* sse_awk_makeintval (sse_awk_run_t* run, sse_long_t v) { sse_awk_val_int_t* val; if (v >= __awk_int[0].val && v <= __awk_int[sse_countof(__awk_int)-1].val) { return (sse_awk_val_t*)&__awk_int[v-__awk_int[0].val]; } if (run->icache_count > 0) { val = run->icache[--run->icache_count]; } else { val = (sse_awk_val_int_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_int_t)); if (val == SSE_NULL) return SSE_NULL; } val->type = SSE_AWK_VAL_INT; val->ref = 0; val->val = v; val->nde = SSE_NULL; /*xp_printf (SSE_T("makeintval => %p\n"), val);*/ return (sse_awk_val_t*)val; } sse_awk_val_t* sse_awk_makerealval (sse_awk_run_t* run, sse_real_t v) { sse_awk_val_real_t* val; if (run->rcache_count > 0) { val = run->rcache[--run->rcache_count]; } else { val = (sse_awk_val_real_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_real_t)); if (val == SSE_NULL) return SSE_NULL; } val->type = SSE_AWK_VAL_REAL; val->ref = 0; val->val = v; val->nde = SSE_NULL; /*xp_printf (SSE_T("makerealval => %p\n"), val);*/ return (sse_awk_val_t*)val; } sse_awk_val_t* sse_awk_makestrval0 (sse_awk_run_t* run, const sse_char_t* str) { return sse_awk_makestrval (run, str, sse_awk_strlen(str)); } sse_awk_val_t* sse_awk_makestrval ( sse_awk_run_t* run, const sse_char_t* str, sse_size_t len) { sse_awk_val_str_t* val; val = (sse_awk_val_str_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_str_t)); if (val == SSE_NULL) return SSE_NULL; val->type = SSE_AWK_VAL_STR; val->ref = 0; val->len = len; val->buf = sse_awk_strxdup (run->awk, str, len); if (val->buf == SSE_NULL) { SSE_AWK_FREE (run->awk, val); return SSE_NULL; } /*xp_printf (SSE_T("makestrval => %p\n"), val);*/ return (sse_awk_val_t*)val; } sse_awk_val_t* sse_awk_makestrval2 ( sse_awk_run_t* run, const sse_char_t* str1, sse_size_t len1, const sse_char_t* str2, sse_size_t len2) { sse_awk_val_str_t* val; val = (sse_awk_val_str_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_str_t)); if (val == SSE_NULL) return SSE_NULL; val->type = SSE_AWK_VAL_STR; val->ref = 0; val->len = len1 + len2; val->buf = sse_awk_strxdup2 (run->awk, str1, len1, str2, len2); if (val->buf == SSE_NULL) { SSE_AWK_FREE (run->awk, val); return SSE_NULL; } /*xp_printf (SSE_T("makestrval2 => %p\n"), val);*/ return (sse_awk_val_t*)val; } sse_awk_val_t* sse_awk_makerexval ( sse_awk_run_t* run, const sse_char_t* buf, sse_size_t len, void* code) { sse_awk_val_rex_t* val; val = (sse_awk_val_rex_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_rex_t)); if (val == SSE_NULL) return SSE_NULL; val->type = SSE_AWK_VAL_REX; val->ref = 0; val->len = len; val->buf = sse_awk_strxdup (run->awk, buf, len); if (val->buf == SSE_NULL) { SSE_AWK_FREE (run->awk, val); return SSE_NULL; } val->code = SSE_AWK_MALLOC (run->awk, SSE_AWK_REX_LEN(code)); if (val->code == SSE_NULL) { SSE_AWK_FREE (run->awk, val->buf); SSE_AWK_FREE (run->awk, val); return SSE_NULL; } SSE_AWK_MEMCPY (run->awk, val->code, code, SSE_AWK_REX_LEN(code)); return (sse_awk_val_t*)val; } static void __free_map_val (void* run, void* v) { /* xp_printf (SSE_T("refdown in map free...")); sse_awk_printval (v); xp_printf (SSE_T("\n")); */ sse_awk_refdownval (run, v); } sse_awk_val_t* sse_awk_makemapval (sse_awk_run_t* run) { sse_awk_val_map_t* val; val = (sse_awk_val_map_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_map_t)); if (val == SSE_NULL) return SSE_NULL; val->type = SSE_AWK_VAL_MAP; val->ref = 0; val->map = sse_awk_map_open ( SSE_NULL, run, 256, __free_map_val, run->awk); if (val->map == SSE_NULL) { SSE_AWK_FREE (run->awk, val); return SSE_NULL; } return (sse_awk_val_t*)val; } sse_awk_val_t* sse_awk_makerefval (sse_awk_run_t* run, int id, sse_awk_val_t** adr) { sse_awk_val_ref_t* val; if (run->fcache_count > 0) { val = run->fcache[--run->fcache_count]; } else { val = (sse_awk_val_ref_t*) SSE_AWK_MALLOC ( run->awk, sse_sizeof(sse_awk_val_ref_t)); if (val == SSE_NULL) return SSE_NULL; } val->type = SSE_AWK_VAL_REF; val->ref = 0; val->id = id; val->adr = adr; return (sse_awk_val_t*)val; } sse_bool_t sse_awk_isbuiltinval (sse_awk_val_t* val) { return val == SSE_NULL || val == sse_awk_val_nil || val == sse_awk_val_zls || val == sse_awk_val_zero || val == sse_awk_val_one || (val >= (sse_awk_val_t*)&__awk_int[0] && val <= (sse_awk_val_t*)&__awk_int[sse_countof(__awk_int)-1]); } void sse_awk_freeval (sse_awk_run_t* run, sse_awk_val_t* val, sse_bool_t cache) { if (sse_awk_isbuiltinval(val)) return; /*xp_printf (SSE_T("freeing [cache=%d] ... "), cache); sse_awk_printval (val); xp_printf (SSE_T("\n"));*/ if (val->type == SSE_AWK_VAL_NIL) { SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_INT) { if (cache == sse_true && run->icache_count < sse_countof(run->icache)) { run->icache[run->icache_count++] = (sse_awk_val_int_t*)val; } else SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_REAL) { if (cache == sse_true && run->rcache_count < sse_countof(run->rcache)) { run->rcache[run->rcache_count++] = (sse_awk_val_real_t*)val; } else SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_STR) { SSE_AWK_FREE (run->awk, ((sse_awk_val_str_t*)val)->buf); SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_REX) { SSE_AWK_FREE (run->awk, ((sse_awk_val_rex_t*)val)->buf); sse_awk_freerex (run->awk, ((sse_awk_val_rex_t*)val)->code); SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_MAP) { sse_awk_map_close (((sse_awk_val_map_t*)val)->map); SSE_AWK_FREE (run->awk, val); } else if (val->type == SSE_AWK_VAL_REF) { if (cache == sse_true && run->fcache_count < sse_countof(run->fcache)) { run->fcache[run->fcache_count++] = (sse_awk_val_ref_t*)val; } else SSE_AWK_FREE (run->awk, val); } else { sse_awk_assert (run->awk, !"should never happen - invalid value type"); } } void sse_awk_refupval (sse_awk_val_t* val) { if (sse_awk_isbuiltinval(val)) return; /* xp_printf (SSE_T("ref up ")); sse_awk_printval (val); xp_printf (SSE_T("\n")); */ val->ref++; } void sse_awk_refdownval (sse_awk_run_t* run, sse_awk_val_t* val) { if (sse_awk_isbuiltinval(val)) return; /* xp_printf (SSE_T("%p, %p, %p\n"), sse_awk_val_nil, &__awk_nil, val); xp_printf (SSE_T("ref down [count=>%d]\n"), (int)val->ref); sse_awk_printval (val); xp_printf (SSE_T("\n")); */ sse_awk_assert (run->awk, val->ref > 0); val->ref--; if (val->ref <= 0) { /* xp_printf (SSE_T("**FREEING [")); sse_awk_printval (val); xp_printf (SSE_T("]\n")); */ sse_awk_freeval(run, val, sse_true); } } void sse_awk_refdownval_nofree (sse_awk_run_t* run, sse_awk_val_t* val) { if (sse_awk_isbuiltinval(val)) return; sse_awk_assert (run->awk, val->ref > 0); val->ref--; } sse_bool_t sse_awk_valtobool (sse_awk_run_t* run, sse_awk_val_t* val) { if (val == SSE_NULL) return sse_false; switch (val->type) { case SSE_AWK_VAL_NIL: return sse_false; case SSE_AWK_VAL_INT: return ((sse_awk_val_int_t*)val)->val != 0; case SSE_AWK_VAL_REAL: return ((sse_awk_val_real_t*)val)->val != 0.0; case SSE_AWK_VAL_STR: return ((sse_awk_val_str_t*)val)->len > 0; case SSE_AWK_VAL_REX: /* TODO: is this correct? */ return ((sse_awk_val_rex_t*)val)->len > 0; case SSE_AWK_VAL_MAP: return sse_false; /* TODO: is this correct? */ case SSE_AWK_VAL_REF: return sse_false; /* TODO: is this correct? */ } sse_awk_assert (run->awk, !"should never happen - invalid value type"); return sse_false; } sse_char_t* sse_awk_valtostr ( sse_awk_run_t* run, sse_awk_val_t* v, int opt, sse_awk_str_t* buf, sse_size_t* len) { if (v->type == SSE_AWK_VAL_NIL) { return __str_to_str (run, SSE_T(""), 0, opt, buf, len); } if (v->type == SSE_AWK_VAL_INT) { sse_awk_val_int_t* vi = (sse_awk_val_int_t*)v; /* if (vi->nde != SSE_NULL && vi->nde->str != SSE_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 == SSE_AWK_VAL_REAL) { sse_awk_val_real_t* vr = (sse_awk_val_real_t*)v; /* if (vr->nde != SSE_NULL && vr->nde->str != SSE_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 == SSE_AWK_VAL_STR) { sse_awk_val_str_t* vs = (sse_awk_val_str_t*)v; return __str_to_str ( run, vs->buf, vs->len, opt, buf, len); } /* TODO: process more value types */ xp_printf (SSE_T("*** ERROR: WRONG VALUE TYPE [%d] in sse_awk_valtostr v=> %p***\n"), v->type, v); run->errnum = SSE_AWK_EVALTYPE; return SSE_NULL; } static sse_char_t* __str_to_str ( sse_awk_run_t* run, const sse_char_t* str, sse_size_t str_len, int opt, sse_awk_str_t* buf, sse_size_t* len) { if (buf == SSE_NULL) { sse_char_t* tmp; tmp = sse_awk_strxdup (run->awk, str, str_len); if (tmp == SSE_NULL) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } if (len != SSE_NULL) *len = str_len; return tmp; } else { sse_size_t n; if (opt & SSE_AWK_VALTOSTR_CLEAR) sse_awk_str_clear (buf); n = sse_awk_str_ncat (buf, str, str_len); if (n == (sse_size_t)-1) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } if (len != SSE_NULL) *len = SSE_AWK_STR_LEN(buf); return SSE_AWK_STR_BUF(buf); } } static sse_char_t* __val_int_to_str ( sse_awk_run_t* run, sse_awk_val_int_t* v, int opt, sse_awk_str_t* buf, sse_size_t* len) { sse_char_t* tmp; sse_long_t t; sse_size_t l = 0; t = v->val; if (t == 0) { /* handle zero */ if (buf == SSE_NULL) { tmp = SSE_AWK_MALLOC ( run->awk, 2 * sse_sizeof(sse_char_t)); if (tmp == SSE_NULL) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } tmp[0] = SSE_T('0'); tmp[1] = SSE_T('\0'); if (len != SSE_NULL) *len = 1; return tmp; } else { if (opt & SSE_AWK_VALTOSTR_CLEAR) sse_awk_str_clear (buf); if (sse_awk_str_cat (buf, SSE_T("0")) == (sse_size_t)-1) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } if (len != SSE_NULL) *len = SSE_AWK_STR_LEN(buf); return SSE_AWK_STR_BUF(buf); } } /* non-zero values */ if (t < 0) { t = -t; l++; } while (t > 0) { l++; t /= 10; } if (buf == SSE_NULL) { tmp = SSE_AWK_MALLOC ( run->awk, (l + 1) * sse_sizeof(sse_char_t)); if (tmp == SSE_NULL) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } tmp[l] = SSE_T('\0'); if (len != SSE_NULL) *len = l; } else { /* clear the buffer */ if (opt & SSE_AWK_VALTOSTR_CLEAR) sse_awk_str_clear (buf); tmp = SSE_AWK_STR_BUF(buf) + SSE_AWK_STR_LEN(buf); /* extend the buffer */ if (sse_awk_str_nccat ( buf, SSE_T(' '), l) == (sse_size_t)-1) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } } t = v->val; if (t < 0) t = -t; while (t > 0) { tmp[--l] = (sse_char_t)(t % 10) + SSE_T('0'); t /= 10; } if (v->val < 0) tmp[--l] = SSE_T('-'); if (buf != SSE_NULL) { tmp = SSE_AWK_STR_BUF(buf); if (len != SSE_NULL) *len = SSE_AWK_STR_LEN(buf); } return tmp; } static sse_char_t* __val_real_to_str ( sse_awk_run_t* run, sse_awk_val_real_t* v, int opt, sse_awk_str_t* buf, sse_size_t* len) { /* TODO: change the code */ sse_char_t tbuf[256], * tmp; tmp = (opt & SSE_AWK_VALTOSTR_PRINT)? run->global.ofmt.ptr: run->global.convfmt.ptr; /* TODO: need to use awk's own version of sprintf so that it would have * problems with handling long double or double... */ /* TODO: does it need to check if a null character is included in convfmt??? */ run->awk->syscas.sprintf (tbuf, sse_countof(tbuf), tmp, (double)v->val); if (buf == SSE_NULL) { tmp = sse_awk_strdup (run->awk, tbuf); if (tmp == SSE_NULL) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } if (len != SSE_NULL) *len = sse_awk_strlen(tmp); } else { if (opt & SSE_AWK_VALTOSTR_CLEAR) sse_awk_str_clear (buf); if (sse_awk_str_cat (buf, tbuf) == (sse_size_t)-1) { run->errnum = SSE_AWK_ENOMEM; return SSE_NULL; } tmp = SSE_AWK_STR_BUF(buf); if (len != SSE_NULL) *len = SSE_AWK_STR_LEN(buf); } return tmp; } int sse_awk_valtonum ( sse_awk_run_t* run, sse_awk_val_t* v, sse_long_t* l, sse_real_t* r) { if (v->type == SSE_AWK_VAL_NIL) { *l = 0; return 0; } if (v->type == SSE_AWK_VAL_INT) { *l = ((sse_awk_val_int_t*)v)->val; return 0; /* long */ } if (v->type == SSE_AWK_VAL_REAL) { *r = ((sse_awk_val_real_t*)v)->val; return 1; /* real */ } if (v->type == SSE_AWK_VAL_STR) { const sse_char_t* endptr; *l = sse_awk_strxtolong (run->awk, ((sse_awk_val_str_t*)v)->buf, ((sse_awk_val_str_t*)v)->len, 0, &endptr); if (*endptr == SSE_T('.') || *endptr == SSE_T('E') || *endptr == SSE_T('e')) { *r = sse_awk_strxtoreal (run->awk, ((sse_awk_val_str_t*)v)->buf, ((sse_awk_val_str_t*)v)->len, SSE_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 */ } xp_printf (SSE_T("*** ERROR: WRONG VALUE TYPE [%d] in sse_awk_valtonum v=> %p***\n"), v->type, v); run->errnum = SSE_AWK_EVALTYPE; return -1; /* error */ } static int __print_pair (sse_awk_pair_t* pair, void* arg) { xp_printf (SSE_T(" %s=>"), pair->key); sse_awk_printval (pair->val); xp_printf (SSE_T(" ")); return 0; } void sse_awk_printval (sse_awk_val_t* val) { /* TODO: better value printing...................... */ switch (val->type) { case SSE_AWK_VAL_NIL: xp_printf (SSE_T("nil")); break; case SSE_AWK_VAL_INT: #if defined(__LCC__) xp_printf (SSE_T("%lld"), (long long)((sse_awk_val_int_t*)val)->val); #elif defined(__BORLANDC__) || defined(_MSC_VER) xp_printf (SSE_T("%I64d"), (__int64)((sse_awk_nde_int_t*)val)->val); #elif defined(vax) || defined(__vax) || defined(_SCO_DS) xp_printf (SSE_T("%ld"), (long)((sse_awk_val_int_t*)val)->val); #else xp_printf (SSE_T("%lld"), (long long)((sse_awk_val_int_t*)val)->val); #endif break; case SSE_AWK_VAL_REAL: xp_printf (SSE_T("%Lf"), (long double)((sse_awk_val_real_t*)val)->val); break; case SSE_AWK_VAL_STR: xp_printf (SSE_T("%s"), ((sse_awk_val_str_t*)val)->buf); break; case SSE_AWK_VAL_REX: xp_printf (SSE_T("REX[%s]"), ((sse_awk_val_rex_t*)val)->buf); break; case SSE_AWK_VAL_MAP: xp_printf (SSE_T("MAP[")); sse_awk_map_walk (((sse_awk_val_map_t*)val)->map, __print_pair, SSE_NULL); xp_printf (SSE_T("]")); break; case SSE_AWK_VAL_REF: xp_printf (SSE_T("REF[id=%d,val="), ((sse_awk_val_ref_t*)val)->id); sse_awk_printval (*((sse_awk_val_ref_t*)val)->adr); xp_printf (SSE_T("]")); break; default: xp_printf (SSE_T("**** INTERNAL ERROR - INVALID VALUE TYPE ****\n")); } }