NetBSD/gnu/usr.bin/awk/cast.c
1993-03-21 09:45:37 +00:00

405 lines
8.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.1.1.1 1993/03/21 09:45:37 cgd
/* initial import of 386bsd-0.1 sources
/*
* Revision 5.1 91/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 pow2[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 int ival ;
switch( cp->type )
{ case C_NOINIT :
null_str.ref_cnt++ ;
cp->ptr = (PTR) &null_str ;
break ;
case C_DOUBLE :
if ( (double) (ival = (int) cp->dval) == cp->dval )
(void) sprintf(string_buff, "%d", ival) ;
else
(void) sprintf(string_buff ,
string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(string_buff) ;
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 int ival ;
switch( cp->type )
{ case C_NOINIT :
null_str.ref_cnt++ ;
cp->ptr = (PTR) &null_str ;
break ;
case C_DOUBLE :
if ( (double) (ival = (int) cp->dval) == cp->dval )
(void) sprintf(string_buff, "%d", ival) ;
else
(void) sprintf(string_buff ,
string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(string_buff) ;
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 :
if ( (double) (ival = (int) cp->dval) == cp->dval )
(void) sprintf(string_buff, "%d", ival) ;
else
(void) sprintf(string_buff ,
string(CONVFMT)->str, cp->dval) ;
cp->ptr = (PTR) new_STRING(string_buff) ;
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) ;
if ( errno && cp->dval != 0.0 )
rt_error(
"overflow converting %s to double" , s) ;
#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) ;
}
#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()
*/
double strtod(s, endptr)
char *s , **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