2 /********************************************
4 copyright 1991-1993. Michael D. Brennan
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
14 * Revision 1.7 1996/09/18 01:04:36 mike
15 * Check ferror() after print and printf.
17 * Revision 1.6 1995/10/13 16:56:45 mike
18 * Some assumptions that int==long were still in do_printf -- now removed.
20 * Revision 1.5 1995/06/18 19:17:50 mike
21 * Create a type Int which on most machines is an int, but on machines
22 * with 16bit ints, i.e., the PC is a long. This fixes implicit assumption
25 * Revision 1.4 1994/10/08 19:15:50 mike
28 * Revision 1.3 1993/07/15 23:38:19 mike
31 * Revision 1.2 1993/07/07 00:07:50 mike
34 * Revision 1.1.1.1 1993/07/03 18:58:18 mike
37 * Revision 5.6 1993/02/13 21:57:30 mike
40 * Revision 5.5 1993/01/01 21:30:48 mike
41 * split new_STRING() into new_STRING and new_STRING0
43 * Revision 5.4.1.2 1993/01/20 12:53:11 mike
46 * Revision 5.4.1.1 1993/01/15 03:33:47 mike
47 * patch3: safer double to int conversion
49 * Revision 5.4 1992/11/29 18:03:11 mike
50 * when printing integers, convert doubles to
51 * longs so output is the same on 16bit systems as 32bit systems
53 * Revision 5.3 1992/08/17 14:23:21 brennan
54 * patch2: After parsing, only bi_sprintf() uses string_buff.
56 * Revision 5.2 1992/02/24 10:52:16 brennan
57 * printf and sprintf() can now have more args than % conversions
58 * removed HAVE_PRINTF_HD -- it was too obscure
60 * Revision 5.1 91/12/05 07:56:22 brennan
73 static void PROTO(print_cell, (CELL *, FILE *)) ;
74 static STRING *PROTO(do_printf, (FILE *, char *, unsigned, CELL *)) ;
75 static void PROTO(bad_conversion, (int, char *, char *)) ;
76 static void PROTO(write_error,(void)) ;
78 /* prototyping fprintf() or sprintf() is a loser as ellipses will
79 always cause problems with ansi compilers depending on what
81 but we need them here and sometimes they are missing
84 #ifdef NO_FPRINTF_IN_STDIO
85 int PROTO(fprintf, (FILE *, const char *,...)) ;
87 #ifdef NO_SPRINTF_IN_STDIO
88 int PROTO(sprintf, (char *, const char *,...)) ;
91 /* this can be moved and enlarged by -W sprintf=num */
92 char *sprintf_buff = string_buff ;
93 char *sprintf_limit = string_buff + SPRINTF_SZ ;
95 /* Once execute() starts the sprintf code is (belatedly) the only
96 code allowed to use string_buff */
112 switch (len = string(p)->len)
117 putc(string(p)->str[0], fp) ;
121 fwrite(string(p)->str, 1, len, fp) ;
127 Int ival = d_to_I(p->dval) ;
129 /* integers print as "%[l]d" */
130 if ((double) ival == p->dval) fprintf(fp, INT_FMT, ival) ;
131 else fprintf(fp, string(OFMT)->str, p->dval) ;
136 bozo("bad cell passed to print_cell") ;
140 /* on entry to bi_print or bi_printf the stack is:
143 if ( k < 0 ) output is to a file with name in sp[-1]
144 { so open file and sp -= 2 }
146 sp[0] = k >= 0 is the number of print args
147 sp[-k] holds the first argument
152 CELL *sp ; /* stack ptr passed in */
161 /* k holds redirection */
162 if ((--sp)->type < C_STRING) cast1_to_s(sp) ;
163 fp = (FILE *) file_find(string(sp), k) ;
164 free_STRING(string(sp)) ;
166 /* k now has number of arguments */
172 p = sp - k ; /* clear k variables off the stack */
178 print_cell(p,fp) ; print_cell(OFS,fp) ;
183 print_cell(p, fp) ; cell_destroy(p) ;
188 print_cell(&field[0], fp) ;
191 print_cell(ORS, fp) ;
192 if (ferror(fp)) write_error() ;
196 /*---------- types and defs for doing printf and sprintf----*/
197 #define PF_C 0 /* %c */
198 #define PF_S 1 /* %s */
199 #define PF_D 2 /* int conversion */
200 #define PF_F 3 /* float conversion */
202 /* for switch on number of '*' and type */
203 #define AST(num,type) ((PF_F+1)*(num)+(type))
205 /* some picky ANSI compilers go berserk without this */
207 typedef int (*PRINTER) () ;
209 typedef int (*PRINTER) (PTR, const char *,...) ;
212 /*-------------------------------------------------------*/
215 bad_conversion(cnt, who, format)
219 rt_error("improper conversion(number %d) in %s(\"%s\")",
223 /* the contents of format are preserved,
224 caller does CELL cleanup
226 This routine does both printf and sprintf (if fp==0)
229 do_printf(fp, format, argcnt, cp)
232 unsigned argcnt ; /* number of args on eval stack */
233 CELL *cp ; /* ptr to an array of arguments
234 (on the eval stack) */
238 register char *q = format ;
239 register char *target ;
240 int l_flag, h_flag ; /* seen %ld or %hd */
244 int num_conversion = 0 ; /* for error messages */
245 char *who ; /*ditto*/
246 int pf_type ; /* conversion type */
247 PRINTER printer ; /* pts at fprintf() or sprintf() */
250 char xbuff[256] ; /* splice in l qualifier here */
253 if (fp == (FILE *) 0) /* doing sprintf */
255 target = sprintf_buff ;
256 printer = (PRINTER) sprintf ;
259 else /* doing printf */
261 target = (char *) fp ; /* will never change */
262 printer = (PRINTER) fprintf ;
272 if (ferror(fp)) write_error() ;
273 /* return is ignored */
274 return (STRING *) 0 ;
276 else { putc(*q,fp) ; q++ ; }
284 if (target > sprintf_limit) /* damaged */
286 /* hope this works */
287 rt_overflow("sprintf buffer",
288 sprintf_limit - sprintf_buff) ;
290 else /* really done */
293 int len = target - sprintf_buff ;
295 retval = new_STRING0(len) ;
296 memcpy(retval->str, sprintf_buff, len) ;
300 else *target++ = *q++ ;
307 if (*++q == '%') /* %% */
309 if (fp) putc(*q, fp) ;
310 else *target++ = *q ;
315 /* mark the '%' with p */
319 while (*q == '-' || *q == '+' || *q == ' ' ||
320 *q == '#' || *q == '0')
326 if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
327 ast[ast_cnt++] = d_to_i(cp++->dval) ;
331 while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++ ;
334 if (*q == '.') /* have precision */
339 if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
340 ast[ast_cnt++] = d_to_i(cp++->dval) ;
344 while (scan_code[*(unsigned char *) q] == SC_DIGIT) q++ ;
348 rt_error("not enough arguments passed to %s(\"%s\")",
351 l_flag = h_flag = 0 ;
353 if (*q == 'l') { q++ ; l_flag = 1 ; }
354 else if (*q == 'h') { q++ ; h_flag = 1 ; }
359 bad_conversion(num_conversion, who, format) ;
360 if (cp->type < C_STRING) cast1_to_s(cp) ;
366 bad_conversion(num_conversion, who, format) ;
376 Ival = d_to_I(cp->dval) ;
380 Ival = string(cp)->str[0] ;
385 Ival = cp->type == C_STRING ?
386 string(cp)->str[0] : d_to_I(cp->dval) ;
402 if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
403 Ival = d_to_I(cp->dval) ;
413 bad_conversion(num_conversion, who, format) ;
414 if (cp->type != C_DOUBLE) cast1_to_d(cp) ;
419 bad_conversion(num_conversion, who, format) ;
428 /* need to splice in long modifier */
431 if (l_flag) /* do nothing */ ;
438 Ival = (short) Ival ;
439 /* replace the 'h' with 'l' (really!) */
441 if (xbuff[k - 1] != 'd' && xbuff[k - 1] != 'i')
447 xbuff[k] = xbuff[k - 1] ;
455 /* ready to call printf() */
456 switch (AST(ast_cnt, pf_type))
459 (*printer) ((PTR) target, p, (int) Ival) ;
463 (*printer) ((PTR) target, p, ast[0], (int) Ival) ;
467 (*printer) ((PTR) target, p, ast[0], ast[1], (int) Ival) ;
471 (*printer) ((PTR) target, p, string(cp)->str) ;
475 (*printer) ((PTR) target, p, ast[0], string(cp)->str) ;
479 (*printer) ((PTR) target, p, ast[0], ast[1], string(cp)->str) ;
483 #define FMT xbuff /* format in xbuff */
485 #define FMT p /* p -> format */
488 (*printer) ((PTR) target, FMT, Ival) ;
492 (*printer) ((PTR) target, FMT, ast[0], Ival) ;
496 (*printer) ((PTR) target, FMT, ast[0], ast[1], Ival) ;
503 (*printer) ((PTR) target, p, cp->dval) ;
507 (*printer) ((PTR) target, p, ast[0], cp->dval) ;
511 (*printer) ((PTR) target, p, ast[0], ast[1], cp->dval) ;
514 if (fp == (FILE *) 0)
515 while (*target) target++ ;
516 *q = save ; argcnt-- ; cp++ ;
531 /* k has redirection */
532 if ((--sp)->type < C_STRING) cast1_to_s(sp) ;
533 fp = (FILE *) file_find(string(sp), k) ;
534 free_STRING(string(sp)) ;
536 /* k is now number of args including format */
540 sp -= k ; /* sp points at the format string */
543 if (sp->type < C_STRING) cast1_to_s(sp) ;
544 do_printf(fp, string(sp)->str, k, sp + 1);
545 free_STRING(string(sp)) ;
547 /* cleanup arguments on eval stack */
548 for (p = sp + 1; k; k--, p++) cell_destroy(p) ;
557 int argcnt = sp->type ;
560 sp -= argcnt ; /* sp points at the format string */
563 if (sp->type != C_STRING) cast1_to_s(sp) ;
564 sval = do_printf((FILE *) 0, string(sp)->str, argcnt, sp + 1) ;
565 free_STRING(string(sp)) ;
566 sp->ptr = (PTR) sval ;
569 for (p = sp + 1; argcnt; argcnt--, p++) cell_destroy(p) ;
578 errmsg(errno, "write failure") ;