NetBSD/gnu/usr.bin/awk/cast.c

453 lines
9.4 KiB
C

/********************************************
cast.c
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.
********************************************/
/* $Log: cast.c,v $
/* Revision 1.2 1993/07/02 23:57:06 jtc
/* Updated to mawk 1.1.4
/*
* Revision 5.3.1.5 1993/05/05 00:11:22 mike
* patch4: overflow in check_strnum() implies pure string
*
* Revision 5.3.1.4 1993/01/22 15:05:19 mike
* pow2->mpow2 for linux
*
* Revision 5.3.1.3 1993/01/22 14:18:33 mike
* const for strtod and ansi picky compilers
*
* Revision 5.3.1.2 1993/01/20 12:53:06 mike
* d_to_l()
*
* Revision 5.3.1.1 1993/01/15 03:33:37 mike
* patch3: safer double to int conversion
*
* Revision 5.3 1992/11/28 23:48:42 mike
* For internal conversion numeric->string, when testing
* if integer, use longs instead of ints so 16 and 32 bit
* systems behave the same
*
* Revision 5.2 1992/08/17 14:19:45 brennan
* patch2: After parsing, only bi_sprintf() uses string_buff.
*
* Revision 5.1 1991/12/05 07:55:41 brennan
* 1.1 pre-release
*
*/
/* cast.c */
#include "mawk.h"
#include "field.h"
#include "memory.h"
#include "scan.h"
#include "repl.h"
int mpow2[NUM_CELL_TYPES] = {1,2,4,8,16,32,64,128,256,512} ;
void cast1_to_d( cp )
register CELL *cp ;
{
switch( cp->type )
{ case C_NOINIT : cp->dval = 0.0 ; break ;
case C_DOUBLE : return ;
case C_MBSTRN :
case C_STRING :
{ register STRING *s = (STRING *) cp->ptr ;
#if FPE_TRAPS_ON /* look for overflow error */
errno = 0 ;
cp->dval = strtod(s->str,(char **)0) ;
if ( errno && cp->dval != 0.0 ) /* ignore underflow */
rt_error("overflow converting %s to double", s) ;
#else
cp->dval = strtod(s->str,(char **)0) ;
#endif
free_STRING(s) ;
}
break ;
case C_STRNUM :
/* don't need to convert, but do need to free the STRING part */
free_STRING( string(cp) ) ;
break ;
default :
bozo("cast on bad type") ;
}
cp->type = C_DOUBLE ;
}
void cast2_to_d( cp )
register CELL *cp ;
{ register STRING *s ;
switch( cp->type )
{ case C_NOINIT : cp->dval = 0.0 ; break ;
case C_DOUBLE : goto two ;
case C_STRNUM :
free_STRING( string(cp) ) ;
break ;
case C_MBSTRN :
case C_STRING :
s = (STRING *) cp->ptr ;
#if FPE_TRAPS_ON /* look for overflow error */
errno = 0 ;
cp->dval = strtod(s->str,(char **)0) ;
if ( errno && cp->dval != 0.0 ) /* ignore underflow */
rt_error("overflow converting %s to double", s) ;
#else
cp->dval = strtod(s->str,(char **)0) ;
#endif
free_STRING(s) ;
break ;
default :
bozo("cast on bad type") ;
}
cp->type = C_DOUBLE ;
two: cp++ ;
switch( cp->type )
{ case C_NOINIT : cp->dval = 0.0 ; break ;
case C_DOUBLE : return ;
case C_STRNUM :
free_STRING( string(cp) ) ;
break ;
case C_MBSTRN :
case C_STRING :
s = (STRING *) cp->ptr ;
#if FPE_TRAPS_ON /* look for overflow error */
errno = 0 ;
cp->dval = strtod(s->str,(char **)0) ;
if ( errno && cp->dval != 0.0 ) /* ignore underflow */
rt_error("overflow converting %s to double", s) ;
#else
cp->dval = strtod(s->str,(char **)0) ;
#endif
free_STRING(s) ;
break ;
default :
bozo("cast on bad type") ;
}
cp->type = C_DOUBLE ;
}
void cast1_to_s( cp )
register CELL *cp ;
{
register long lval ;
char xbuff[260] ;
switch( cp->type )
{ case C_NOINIT :
null_str.ref_cnt++ ;
cp->ptr = (PTR) &null_str ;
break ;
case C_DOUBLE :
lval = d_to_l(cp->dval) ;
if ( lval == cp->dval )
(void) sprintf(xbuff, INT_FMT, lval) ;
else
(void) sprintf(xbuff , string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(xbuff) ;
break ;
case C_STRING : return ;
case C_MBSTRN :
case C_STRNUM : break ;
default : bozo("bad type on cast") ;
}
cp->type = C_STRING ;
}
void cast2_to_s( cp )
register CELL *cp ;
{
register long lval ;
char xbuff[260] ;
switch( cp->type )
{ case C_NOINIT :
null_str.ref_cnt++ ;
cp->ptr = (PTR) &null_str ;
break ;
case C_DOUBLE :
lval = d_to_l(cp->dval) ;
if ( lval == cp->dval )
(void) sprintf(xbuff, INT_FMT, lval) ;
else
(void) sprintf(xbuff , string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(xbuff) ;
break ;
case C_STRING : goto two ;
case C_MBSTRN :
case C_STRNUM : break ;
default : bozo("bad type on cast") ;
}
cp->type = C_STRING ;
two:
cp++ ;
switch( cp->type )
{ case C_NOINIT :
null_str.ref_cnt++ ;
cp->ptr = (PTR) &null_str ;
break ;
case C_DOUBLE :
lval = d_to_l(cp->dval) ;
if ( lval == cp->dval )
(void) sprintf(xbuff, INT_FMT, lval) ;
else
(void) sprintf(xbuff , string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(xbuff) ;
break ;
case C_STRING : return ;
case C_MBSTRN :
case C_STRNUM : break ;
default : bozo("bad type on cast") ;
}
cp->type = C_STRING ;
}
void cast_to_RE( cp )
register CELL *cp ;
{ register PTR p ;
if ( cp->type < C_STRING ) cast1_to_s(cp) ;
p = re_compile( string(cp) ) ;
free_STRING( string(cp) ) ;
cp->type = C_RE ;
cp->ptr = p ;
}
void cast_for_split(cp)
register CELL *cp ;
{
static char meta[] = "^$.*+?|[]()" ;
static char xbuff[] = "\\X" ;
int c ;
unsigned len ;
if ( cp->type < C_STRING ) cast1_to_s(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) new_STRING(xbuff) ;
}
}
else
if ( len == 0 )
{ free_STRING(string(cp)) ;
cp->type = C_SNULL ;
return ;
}
cast_to_RE(cp) ;
}
/* input: cp-> a CELL of type C_MBSTRN (maybe strnum)
test it -- casting it to the appropriate type
which is C_STRING or C_STRNUM
*/
void check_strnum( cp )
CELL *cp ;
{ char *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 ( scan_code[*s] == SC_SPACE ) s++ ;
if ( s == q ) return ;
while ( scan_code[ q[-1] ] == SC_SPACE ) q-- ;
if ( scan_code[ q[-1] ] != SC_DIGIT &&
q[-1] != '.' ) return ;
switch ( scan_code[*s] )
{
case SC_DIGIT :
case SC_PLUS :
case SC_MINUS :
case SC_DOT :
#if FPE_TRAPS_ON
errno = 0 ;
cp->dval = strtod((char *)s, &test) ;
/* treat overflow as pure string */
if ( errno && cp->dval != 0.0 ) return ;
#else
cp->dval = strtod((char *)s, &test) ;
#endif
if ((char *) q <= test ) cp->type = C_STRNUM ;
/* <= instead of == , for some buggy strtod
e.g. Apple Unix */
}
}
/* cast a CELL to a replacement cell */
void cast_to_REPL( cp )
register CELL *cp ;
{ register STRING *sval ;
if ( cp->type < C_STRING ) cast1_to_s(cp) ;
sval = (STRING *) cp->ptr ;
(void) cellcpy(cp, repl_compile(sval)) ;
free_STRING(sval) ;
}
/* convert a double to long (this is not as simple as a
cast because the results are undefined if it won't fit).
Truncate large values to +MAX__LONG or -MAX__LONG
Send nans to -MAX__LONG
*/
long
d_to_l(d)
double d ;
{
if ( d >= MAX__LONG ) return MAX__LONG ;
if ( d > -MAX__LONG ) return (int) d ;
return -MAX__LONG ;
}
#if HAVE_STRTOD==0
/* don't use this unless you really don't have strtod() because
(1) its probably slower than your real strtod()
(2) atof() may call the real strtod()
*/
#if __STDC__ == 0
#define const
#endif
double strtod(s, endptr)
const char *s ;
char **endptr ;
{
register unsigned char *p ;
int flag ;
double atof() ;
if ( endptr )
{
p = (unsigned char*) s ;
flag = 0 ;
while ( *p == ' ' || *p == '\t' ) p++ ;
if ( *p == '-' || *p == '+' ) p++ ;
while ( scan_code[*p] == SC_DIGIT ) { flag++ ; p++ ; }
if ( *p == '.' )
{
p++ ;
while ( scan_code[*p] == SC_DIGIT ) { flag++ ; p++ ; }
}
/* done with number part */
if ( flag == 0 )
{ /* no number part */
*endptr = s ; return 0.0 ;
}
else *endptr = (char *) p ;
/* now look for exponent */
if ( *p == 'e' || *p == 'E' )
{
flag = 0 ;
p++ ;
if ( *p == '-' || *p == '+' ) p++ ;
while ( scan_code[*p] == SC_DIGIT ) { flag++ ; p++ ; }
if ( flag ) *endptr = (char *) p ;
}
}
return atof(s) ;
}
#endif /* HAVE_STRTOD==0 */
#if HAVE_FMOD==0
#if SW_FP_CHECK /* this is V7 and XNX23A specific */
double fmod(x, y)
double x, y ;
{ double modf() ;
double dtmp, ipart ;
clrerr();
dtmp = x / y;
fpcheck();
(void) modf(dtmp, &ipart) ;
return x - ipart*y ;
}
#else
double fmod(x, y)
double x, y ;
{ double modf() ;
double ipart ;
(void) modf(x/y, &ipart) ;
return x - ipart*y ;
}
#endif
#endif