home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 11
/
AUCD11B.iso
/
LANGUAGES
/
WraithSet
/
AwkStuff
/
MawkSrc
/
c
/
print
< prev
next >
Wrap
Text File
|
1996-09-17
|
13KB
|
581 lines
/********************************************
print.c
copyright 1991-1993. 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: print.c,v $
* Revision 1.7 1996/09/18 01:04:36 mike
* Check ferror() after print and printf.
*
* Revision 1.6 1995/10/13 16:56:45 mike
* Some assumptions that int==long were still in do_printf -- now removed.
*
* Revision 1.5 1995/06/18 19:17:50 mike
* Create a type Int which on most machines is an int, but on machines
* with 16bit ints, i.e., the PC is a long. This fixes implicit assumption
* that int==long.
*
* Revision 1.4 1994/10/08 19:15:50 mike
* remove SM_DOS
*
* Revision 1.3 1993/07/15 23:38:19 mike
* SIZE_T and indent
*
* Revision 1.2 1993/07/07 00:07:50 mike
* more work on 1.2
*
* Revision 1.1.1.1 1993/07/03 18:58:18 mike
* move source to cvs
*
* Revision 5.6 1993/02/13 21:57:30 mike
* merge patch3
*
* Revision 5.5 1993/01/01 21:30:48 mike
* split new_STRING() into new_STRING and new_STRING0
*
* Revision 5.4.1.2 1993/01/20 12:53:11 mike
* d_to_l()
*
* Revision 5.4.1.1 1993/01/15 03:33:47 mike
* patch3: safer double to int conversion
*
* Revision 5.4 1992/11/29 18:03:11 mike
* when printing integers, convert doubles to
* longs so output is the same on 16bit systems as 32bit systems
*
* Revision 5.3 1992/08/17 14:23:21 brennan
* patch2: After parsing, only bi_sprintf() uses string_buff.
*
* Revision 5.2 1992/02/24 10:52:16 brennan
* printf and sprintf() can now have more args than % conversions
* removed HAVE_PRINTF_HD -- it was too obscure
*
* Revision 5.1 91/12/05 07:56:22 brennan
* 1.1 pre-release
*
*/
#include "mawk.h"
#include "bi_vars.h"
#include "bi_funct.h"
#include "memory.h"
#include "field.h"
#include "scan.h"
#include "files.h"
static void PROTO(print_cell, (CELL *, FILE *)) ;
static STRING *PROTO(do_printf, (FILE *, char *, unsigned, CELL *)) ;
static void PROTO(bad_conversion, (int, char *, char *)) ;
static void PROTO(write_error,(void)) ;
/* prototyping fprintf() or sprintf() is a loser as ellipses will
always cause problems with ansi compilers depending on what
they've already seen,
but we need them here and sometimes they are missing
*/
#ifdef NO_FPRINTF_IN_STDIO
int PROTO(fprintf, (FILE *, const char *,...)) ;
#endif
#ifdef NO_SPRINTF_IN_STDIO
int PROTO(sprintf, (char *, const char *,...)) ;
#endif
/* this can be moved and enlarged by -W sprintf=num */
char *sprintf_buff = string_buff ;
char *sprintf_limit = string_buff + SPRINTF_SZ ;
/* Once execute() starts the sprintf code is (belatedly) the only
code allowed to use string_buff */
static void
print_cell(p, fp)
register CELL *p ;
register FILE *fp ;
{
int len ;
switch (p->type)
{
case C_NOINIT:
break ;
case C_MBSTRN:
case C_STRING:
case C_STRNUM:
switch (len = string(p)->len)
{
case 0:
break ;
case 1:
putc(string(p)->str[0], fp) ;
break ;
default:
fwrite(string(p)->str, 1, len, fp) ;
}
break ;
case C_DOUBLE:
{
Int ival = d_to_I(p->dval) ;
/* integers print as "%[l]d" */
if ((double) ival == p->dval) fprintf(fp, INT_FMT, ival) ;
else fprintf(fp, string(OFMT)->str, p->dval) ;
}
break ;
default:
bozo("bad cell passed to print_cell") ;
}
}
/* on entry to bi_print or bi_printf the stack is:
sp[0] = an integer k
if ( k < 0 ) output is to a file with name in sp[-1]
{ so open file and sp -= 2 }
sp[0] = k >= 0 is the number of print args
sp[-k] holds the first argument
*/
CELL *
bi_print(sp)
CELL *sp ; /* stack ptr passed in */
{
register CELL *p ;
register int k ;
FILE *fp ;
k = sp->type ;
if (k < 0)
{
/* k holds redirection */
if ((--sp)->type < C_STRING) cast1_to_s(sp) ;
fp = (FILE *) file_find(string(sp), k) ;
free_STRING(string(sp)) ;
k = (--sp)->type ;
/* k now has number of arguments */
}
else fp = stdout ;
if (k)
{
p = sp - k ; /* clear k variables off the stack */
sp = p - 1 ;
k-- ;
while (k > 0)
{
print_cell(p,fp) ; print_cell(OFS,fp) ;
cell_destroy(p) ;
p++ ; k-- ;
}
print_cell(p, fp) ; cell_destroy(p) ;
}
else
{ /* print $0 */
sp-- ;
print_cell(&field[0], fp) ;
}
print_cell(ORS, fp) ;
if (ferror(fp)) write_error() ;
return sp ;
}
/*---------- types and defs for doing printf and sprintf----*/
#define PF_C 0 /* %c */
#define PF_S 1 /* %s */
#define PF_D 2 /* int conversion */
#define PF_F 3 /* float conversion */
/* for switch on number of '*' and type */
#define AST(num,type) ((PF_F+1)*(num)+(type))
/* some picky ANSI compilers go berserk without this */
#ifdef NO_PROTOS
typedef int (*PRINTER) () ;
#else
typedef int (*PRINTER) (PTR, const char *,...) ;
#endif
/*-------------------------------------------------------*/
static void
bad_conversion(cnt, who, format)
int cnt ;
char *who, *format ;
{
rt_error("improper conversion(number %d) in %s(\"%s\")",
cnt, who, format) ;
}
/* the contents of format are preserved,
caller does CELL cleanup
This routine does both printf and sprintf (if fp==0)
*/
static STRING *
do_printf(fp, format, argcnt, cp)
FILE *fp ;
char *format ;
unsigned argcnt ; /* number of args on eval stack */
CELL *cp ; /* ptr to an array of arguments
(on the eval stack) */
{
char save ;
char *p ;
register char *q = format ;
register char *target ;
int l_flag, h_flag ; /* seen %ld or %hd */
int ast_cnt ;
int ast[2] ;
Int Ival ;
int num_conversion = 0 ; /* for error messages */
char *who ; /*ditto*/
int pf_type ; /* conversion type */
PRINTER printer ; /* pts at fprintf() or sprintf() */
#ifdef SHORT_INTS
char xbuff[256] ; /* splice in l qualifier here */
#endif
if (fp == (FILE *) 0) /* doing sprintf */
{
target = sprintf_buff ;
printer = (PRINTER) sprintf ;
who = "sprintf" ;
}
else /* doing printf */
{
target = (char *) fp ; /* will never change */
printer = (PRINTER) fprintf ;
who = "printf" ;
}
while (1)
{
if (fp) /* printf */
{
while (*q != '%') {
if (*q == 0) {
if (ferror(fp)) write_error() ;
/* return is ignored */
return (STRING *) 0 ;
}
else { putc(*q,fp) ; q++ ; }
}
}
else /* sprintf */
{
while (*q != '%')
if (*q == 0)
{
if (target > sprintf_limit) /* damaged */
{
/* hope this works */
rt_overflow("sprintf buffer",
sprintf_limit - sprintf_buff) ;
}
else /* really done */
{
STRING *retval ;
int len = target - sprintf_buff ;
retval = new_STRING0(len) ;
memcpy(retval->str, sprintf_buff, len) ;
return retval ;
}
}
else *target++ = *q++ ;
}
/* *q == '%' */
num_conversion++ ;
if (*++q == '%') /* %% */
{
if (fp) putc(*q, fp) ;
else *target++ = *q ;
q++ ; continue ;
}
/* mark the '%' with p */
p = q - 1 ;
/* eat the flags */
while (*q == '-' || *q == '+' || *q == ' ' ||
*q == '#' || *q == '0')
q++ ;
ast_cnt = 0 ;
if (*q == '*')
{
if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
ast[ast_cnt++] = d_to_i(cp++->dval) ;
argcnt-- ; q++ ;
}
else
while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++ ;
/* width is done */
if (*q == '.') /* have precision */
{
q++ ;
if (*q == '*')
{
if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
ast[ast_cnt++] = d_to_i(cp++->dval) ;
argcnt-- ; q++ ;
}
else
while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++ ;
}
if (argcnt <= 0)
rt_error("not enough arguments passed to %s(\"%s\")",
who, format) ;
l_flag = h_flag = 0 ;
if (*q == 'l') { q++ ; l_flag = 1 ; }
else if (*q == 'h') { q++ ; h_flag = 1 ; }
switch (*q++)
{
case 's':
if (l_flag + h_flag)
bad_conversion(num_conversion, who, format) ;
if (cp->type < C_STRING) cast1_to_s(cp) ;
pf_type = PF_S ;
break ;
case 'c':
if (l_flag + h_flag)
bad_conversion(num_conversion, who, format) ;
switch (cp->type)
{
case C_NOINIT:
Ival = 0 ;
break ;
case C_STRNUM:
case C_DOUBLE:
Ival = d_to_I(cp->dval) ;
break ;
case C_STRING:
Ival = string(cp)->str[0] ;
break ;
case C_MBSTRN:
check_strnum(cp) ;
Ival = cp->type == C_STRING ?
string(cp)->str[0] : d_to_I(cp->dval) ;
break ;
default:
bozo("printf %c") ;
}
pf_type = PF_C ;
break ;
case 'd':
case 'o':
case 'x':
case 'X':
case 'i':
case 'u':
if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
Ival = d_to_I(cp->dval) ;
pf_type = PF_D ;
break ;
case 'e':
case 'g':
case 'f':
case 'E':
case 'G':
if (h_flag + l_flag)
bad_conversion(num_conversion, who, format) ;
if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
pf_type = PF_F ;
break ;
default:
bad_conversion(num_conversion, who, format) ;
}
save = *q ;
*q = 0 ;
#ifdef SHORT_INTS
if (pf_type == PF_D)
{
/* need to splice in long modifier */
strcpy(xbuff, p) ;
if (l_flag) /* do nothing */ ;
else
{
int k = q - p ;
if (h_flag)
{
Ival = (short) Ival ;
/* replace the 'h' with 'l' (really!) */
xbuff[k - 2] = 'l' ;
if (xbuff[k - 1] != 'd' && xbuff[k - 1] != 'i')
Ival &= 0xffff ;
}
else
{
/* the usual case */
xbuff[k] = xbuff[k - 1] ;
xbuff[k - 1] = 'l' ;
xbuff[k + 1] = 0 ;
}
}
}
#endif
/* ready to call printf() */
switch (AST(ast_cnt, pf_type))
{
case AST(0, PF_C):
(*printer) ((PTR) target, p, (int) Ival) ;
break ;
case AST(1, PF_C):
(*printer) ((PTR) target, p, ast[0], (int) Ival) ;
break ;
case AST(2, PF_C):
(*printer) ((PTR) target, p, ast[0], ast[1], (int) Ival) ;
break ;
case AST(0, PF_S):
(*printer) ((PTR) target, p, string(cp)->str) ;
break ;
case AST(1, PF_S):
(*printer) ((PTR) target, p, ast[0], string(cp)->str) ;
break ;
case AST(2, PF_S):
(*printer) ((PTR) target, p, ast[0], ast[1], string(cp)->str) ;
break ;
#ifdef SHORT_INTS
#define FMT xbuff /* format in xbuff */
#else
#define FMT p /* p -> format */
#endif
case AST(0, PF_D):
(*printer) ((PTR) target, FMT, Ival) ;
break ;
case AST(1, PF_D):
(*printer) ((PTR) target, FMT, ast[0], Ival) ;
break ;
case AST(2, PF_D):
(*printer) ((PTR) target, FMT, ast[0], ast[1], Ival) ;
break ;
#undef FMT
case AST(0, PF_F):
(*printer) ((PTR) target, p, cp->dval) ;
break ;
case AST(1, PF_F):
(*printer) ((PTR) target, p, ast[0], cp->dval) ;
break ;
case AST(2, PF_F):
(*printer) ((PTR) target, p, ast[0], ast[1], cp->dval) ;
break ;
}
if (fp == (FILE *) 0)
while (*target) target++ ;
*q = save ; argcnt-- ; cp++ ;
}
}
CELL *
bi_printf(sp)
register CELL *sp ;
{
register int k ;
register CELL *p ;
FILE *fp ;
k = sp->type ;
if (k < 0)
{
/* k has redirection */
if ((--sp)->type < C_STRING) cast1_to_s(sp) ;
fp = (FILE *) file_find(string(sp), k) ;
free_STRING(string(sp)) ;
k = (--sp)->type ;
/* k is now number of args including format */
}
else fp = stdout ;
sp -= k ; /* sp points at the format string */
k-- ;
if (sp->type < C_STRING) cast1_to_s(sp) ;
do_printf(fp, string(sp)->str, k, sp + 1);
free_STRING(string(sp)) ;
/* cleanup arguments on eval stack */
for (p = sp + 1; k; k--, p++) cell_destroy(p) ;
return --sp ;
}
CELL *
bi_sprintf(sp)
CELL *sp ;
{
CELL *p ;
int argcnt = sp->type ;
STRING *sval ;
sp -= argcnt ; /* sp points at the format string */
argcnt-- ;
if (sp->type != C_STRING) cast1_to_s(sp) ;
sval = do_printf((FILE *) 0, string(sp)->str, argcnt, sp + 1) ;
free_STRING(string(sp)) ;
sp->ptr = (PTR) sval ;
/* cleanup */
for (p = sp + 1; argcnt; argcnt--, p++) cell_destroy(p) ;
return sp ;
}
static void
write_error()
{
errmsg(errno, "write failure") ;
mawk_exit(2) ;
}