/********************************************
cast.c
libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include <stdio.h>
#include <string.h>
#include "mawk.h"
#include "field.h"
#include "memory.h"
#include "scan.h"
#include "repl.h"
#include "num.h"
#include "cell.h"
void mawk_cast1_to_num(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
switch (cp->type) {
case C_NOINIT:
cp->d.dval = MAWK_NUM_ZERO;
break;
case C_NUM:
return;
case C_MBSTRN:
case C_STRING:
{
register mawk_string_t *s = (mawk_string_t *) cp->ptr;
#if FPE_TRAPS_ON /* look for mawk_overflow error */
errno = 0;
cp->d.dval = strtonum(s->str, (char **) 0);
if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
mawk_rt_error("mawk_overflow converting %s to number", s->str);
#else
cp->d.dval = strtonum(s->str, (char **) 0);
#endif
free_STRING(s);
}
break;
case C_STRNUM:
/* don't need to convert, but do need to free the mawk_string_t part */
free_STRING(string(cp));
break;
default:
mawk_bozo(MAWK, "mawk_cast on bad type");
}
cp->type = C_NUM;
}
void mawk_cast2_to_num(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
register mawk_string_t *s;
switch (cp->type) {
case C_NOINIT:
cp->d.dval = MAWK_NUM_ZERO;
break;
case C_NUM:
goto two;
case C_STRNUM:
free_STRING(string(cp));
break;
case C_MBSTRN:
case C_STRING:
s = (mawk_string_t *) cp->ptr;
#if FPE_TRAPS_ON /* look for mawk_overflow error */
errno = 0;
cp->d.dval = strtonum(s->str, (char **) 0);
if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
mawk_rt_error("mawk_overflow converting %s to number", s->str);
#else
cp->d.dval = strtonum(s->str, (char **) 0);
#endif
free_STRING(s);
break;
default:
mawk_bozo(MAWK, "mawk_cast on bad type");
}
cp->type = C_NUM;
two:cp++;
switch (cp->type) {
case C_NOINIT:
cp->d.dval = MAWK_NUM_ZERO;
break;
case C_NUM:
return;
case C_STRNUM:
free_STRING(string(cp));
break;
case C_MBSTRN:
case C_STRING:
s = (mawk_string_t *) cp->ptr;
#if FPE_TRAPS_ON /* look for mawk_overflow error */
errno = 0;
cp->d.dval = strtonum(s->str, (char **) 0);
if (errno && cp->d.dval != MAWK_NUM_ZERO) /* ignore underflow */
mawk_rt_error("mawk_overflow converting %s to number", s->str);
#else
cp->d.dval = strtonum(s->str, (char **) 0);
#endif
free_STRING(s);
break;
default:
mawk_bozo(MAWK, "mawk_cast on bad type");
}
cp->type = C_NUM;
}
void mawk_cast1_to_str(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
register Int lval;
char xbuff[260];
switch (cp->type) {
case C_NOINIT:
MAWK->null_str.ref_cnt++;
cp->ptr = (PTR) & MAWK->null_str;
break;
case C_NUM:
lval = mawk_d_to_I(cp->d.dval);
if (lval == cp->d.dval)
sprintf(xbuff, INT_FMT, lval);
else
sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
break;
case C_STRING:
return;
case C_MBSTRN:
case C_STRNUM:
break;
default:
mawk_bozo(MAWK, "bad type on mawk_cast");
}
cp->type = C_STRING;
}
void mawk_cast2_to_str(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
register Int lval;
char xbuff[260];
switch (cp->type) {
case C_NOINIT:
MAWK->null_str.ref_cnt++;
cp->ptr = (PTR) & (MAWK->null_str);
break;
case C_NUM:
lval = mawk_d_to_I(cp->d.dval);
if (lval == cp->d.dval)
sprintf(xbuff, INT_FMT, lval);
else
sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
break;
case C_STRING:
goto two;
case C_MBSTRN:
case C_STRNUM:
break;
default:
mawk_bozo(MAWK, "bad type on mawk_cast");
}
cp->type = C_STRING;
two:
cp++;
switch (cp->type) {
case C_NOINIT:
MAWK->null_str.ref_cnt++;
cp->ptr = (PTR) & MAWK->null_str;
break;
case C_NUM:
lval = mawk_d_to_I(cp->d.dval);
if (lval == cp->d.dval)
sprintf(xbuff, INT_FMT, lval);
else
sprintf(xbuff, string(MAWK_CONVFMT)->str, cp->d.dval);
cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
break;
case C_STRING:
return;
case C_MBSTRN:
case C_STRNUM:
break;
default:
mawk_bozo(MAWK, "bad type on mawk_cast");
}
cp->type = C_STRING;
}
void mawk_cast_to_RE(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
register PTR p;
if (cp->type < C_STRING)
mawk_cast1_to_str(MAWK, cp);
p = mawk_re_compile(MAWK, string(cp));
free_STRING(string(cp));
cp->type = C_RE;
cp->ptr = p;
}
void mawk_cast_for_split(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
static const char meta[] = "^$.*+?|[]()";
char xbuff[] = "\\X";
int c;
unsigned len;
if (cp->type < C_STRING)
mawk_cast1_to_str(MAWK, cp);
if ((len = string(cp)->len) == 1) {
if ((c = string(cp)->str[0]) == ' ') {
free_STRING(string(cp));
cp->type = C_SPACE;
return;
}
else if (strchr(meta, c)) {
xbuff[1] = c;
free_STRING(string(cp));
cp->ptr = (PTR) mawk_new_STRING(MAWK, xbuff);
}
}
else if (len == 0) {
free_STRING(string(cp));
cp->type = C_SNULL;
return;
}
mawk_cast_to_RE(MAWK, cp);
}
/* input: cp-> a mawk_cell_t of type C_MBSTRN (maybe strnum)
mawk_test it -- mawk_casting it to the appropriate type
which is C_STRING or C_STRNUM
*/
void mawk_check_strnum(mawk_state_t *MAWK, mawk_cell_t *cp)
{
char *mawk_test;
register unsigned char *s, *q;
cp->type = C_STRING; /* assume not C_STRNUM */
s = (unsigned char *) string(cp)->str;
q = s + string(cp)->len;
while (MAWK->scan_code[*s] == SC_SPACE)
s++;
if (s == q)
return;
while (MAWK->scan_code[q[-1]] == SC_SPACE)
q--;
if (MAWK->scan_code[q[-1]] != SC_DIGIT && q[-1] != '.')
return;
switch (MAWK->scan_code[*s]) {
case SC_DIGIT:
case SC_PLUS:
case SC_MINUS:
case SC_DOT:
#if FPE_TRAPS_ON
errno = 0;
cp->d.dval = strtonum((char *) s, &mawk_test);
/* make mawk_overflow pure string */
if (errno && cp->d.dval != MAWK_NUM_ZERO)
return;
#else
cp->d.dval = strtonum((char *) s, &mawk_test);
#endif
if ((char *) q <= mawk_test)
cp->type = C_STRNUM;
/* <= instead of == , for some buggy strtod
e.g. Apple Unix */
}
}
/* mawk_cast a mawk_cell_t to a replacement cell */
void mawk_cast_to_REPL(mawk_state_t *MAWK, register mawk_cell_t *cp)
{
register mawk_string_t *sval;
if (cp->type < C_STRING)
mawk_cast1_to_str(MAWK, cp);
sval = (mawk_string_t *) cp->ptr;
mawk_cellcpy(MAWK, cp, mawk_repl_compile(MAWK, sval));
free_STRING(sval);
}