Git init
[external/mawk.git] / print.c
1
2 /********************************************
3 print.c
4 copyright 1991-1993.  Michael D. Brennan
5
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
8
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
12
13 /* $Log: print.c,v $
14  * Revision 1.7  1996/09/18 01:04:36  mike
15  * Check ferror() after print and printf.
16  *
17  * Revision 1.6  1995/10/13  16:56:45  mike
18  * Some assumptions that int==long were still in do_printf -- now removed.
19  *
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
23  * that int==long.
24  *
25  * Revision 1.4  1994/10/08  19:15:50  mike
26  * remove SM_DOS
27  *
28  * Revision 1.3  1993/07/15  23:38:19  mike
29  * SIZE_T and indent
30  *
31  * Revision 1.2  1993/07/07  00:07:50  mike
32  * more work on 1.2
33  *
34  * Revision 1.1.1.1  1993/07/03  18:58:18  mike
35  * move source to cvs
36  *
37  * Revision 5.6  1993/02/13  21:57:30  mike
38  * merge patch3
39  *
40  * Revision 5.5  1993/01/01  21:30:48  mike
41  * split new_STRING() into new_STRING and new_STRING0
42  *
43  * Revision 5.4.1.2  1993/01/20  12:53:11  mike
44  * d_to_l()
45  *
46  * Revision 5.4.1.1  1993/01/15  03:33:47  mike
47  * patch3: safer double to int conversion
48  *
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
52  *
53  * Revision 5.3  1992/08/17  14:23:21  brennan
54  * patch2: After parsing, only bi_sprintf() uses string_buff.
55  *
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
59  *
60  * Revision 5.1  91/12/05  07:56:22  brennan
61  * 1.1 pre-release
62  *
63 */
64
65 #include "mawk.h"
66 #include "bi_vars.h"
67 #include "bi_funct.h"
68 #include "memory.h"
69 #include "field.h"
70 #include "scan.h"
71 #include "files.h"
72
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)) ;
77
78 /* prototyping fprintf() or sprintf() is a loser as ellipses will
79    always cause problems with ansi compilers depending on what
80    they've already seen,
81    but we need them here and sometimes they are missing
82 */
83
84 #ifdef NO_FPRINTF_IN_STDIO
85 int PROTO(fprintf, (FILE *, const char *,...)) ;
86 #endif
87 #ifdef NO_SPRINTF_IN_STDIO
88 int PROTO(sprintf, (char *, const char *,...)) ;
89 #endif
90
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 ;
94
95 /* Once execute() starts the sprintf code is (belatedly) the only
96    code allowed to use string_buff  */
97
98 static void
99 print_cell(p, fp)
100    register CELL *p ;
101    register FILE *fp ;
102 {
103    int len ;
104
105    switch (p->type)
106    {
107       case C_NOINIT:
108          break ;
109       case C_MBSTRN:
110       case C_STRING:
111       case C_STRNUM:
112          switch (len = string(p)->len)
113          {
114             case 0:
115                break ;
116             case 1:
117                putc(string(p)->str[0], fp) ;
118                break ;
119
120             default:
121                fwrite(string(p)->str, 1, len, fp) ;
122          }
123          break ;
124
125       case C_DOUBLE:
126          {
127             Int ival = d_to_I(p->dval) ;
128
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) ;
132          }
133          break ;
134
135       default:
136          bozo("bad cell passed to print_cell") ;
137    }
138 }
139
140 /* on entry to bi_print or bi_printf the stack is:
141
142    sp[0] = an integer k
143        if ( k < 0 )  output is to a file with name in sp[-1]
144        { so open file and sp -= 2 }
145
146    sp[0] = k >= 0 is the number of print args
147    sp[-k]   holds the first argument
148 */
149
150 CELL *
151 bi_print(sp)
152    CELL *sp ;                    /* stack ptr passed in */
153 {
154    register CELL *p ;
155    register int k ;
156    FILE *fp ;
157
158    k = sp->type ;
159    if (k < 0)
160    {
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)) ;
165       k = (--sp)->type ;
166       /* k now has number of arguments */
167    }
168    else  fp = stdout ;
169
170    if (k)
171    {
172       p = sp - k ;               /* clear k variables off the stack */
173       sp = p - 1 ;
174       k-- ;
175
176       while (k > 0)
177       {
178          print_cell(p,fp) ; print_cell(OFS,fp) ;
179          cell_destroy(p) ;
180          p++ ; k-- ;
181       }
182
183       print_cell(p, fp) ;  cell_destroy(p) ;
184    }
185    else
186    {                            /* print $0 */
187       sp-- ;
188       print_cell(&field[0], fp) ;
189    }
190
191    print_cell(ORS, fp) ;
192    if (ferror(fp)) write_error() ;
193    return sp ;
194 }
195
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 */
201
202 /* for switch on number of '*' and type */
203 #define  AST(num,type)  ((PF_F+1)*(num)+(type))
204
205 /* some picky ANSI compilers go berserk without this */
206 #ifdef NO_PROTOS
207 typedef int (*PRINTER) () ;
208 #else
209 typedef int (*PRINTER) (PTR, const char *,...) ;
210 #endif
211
212 /*-------------------------------------------------------*/
213
214 static void
215 bad_conversion(cnt, who, format)
216    int cnt ;
217    char *who, *format ;
218 {
219    rt_error("improper conversion(number %d) in %s(\"%s\")",
220             cnt, who, format) ;
221 }
222
223 /* the contents of format are preserved,
224    caller does CELL cleanup
225
226    This routine does both printf and sprintf (if fp==0)
227 */
228 static STRING *
229 do_printf(fp, format, argcnt, cp)
230    FILE *fp ;
231    char *format ;
232    unsigned argcnt ;             /* number of args on eval stack */
233    CELL *cp ;                    /* ptr to an array of arguments 
234                                     (on the eval stack) */
235 {
236    char save ;
237    char *p ;
238    register char *q = format ;
239    register char *target ;
240    int l_flag, h_flag ;          /* seen %ld or %hd  */
241    int ast_cnt ;
242    int ast[2] ;
243    Int Ival ;
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() */
248
249 #ifdef   SHORT_INTS
250    char xbuff[256] ;             /* splice in l qualifier here */
251 #endif
252
253    if (fp == (FILE *) 0)        /* doing sprintf */
254    {
255       target = sprintf_buff ;
256       printer = (PRINTER) sprintf ;
257       who = "sprintf" ;
258    }
259    else  /* doing printf */
260    {
261       target = (char *) fp ;     /* will never change */
262       printer = (PRINTER) fprintf ;
263       who = "printf" ;
264    }
265
266    while (1)
267    {
268       if (fp)                   /* printf */
269       {
270          while (*q != '%') {
271             if (*q == 0)  {
272                if (ferror(fp)) write_error() ;
273                /* return is ignored */
274                return (STRING *) 0 ;
275             }
276             else  { putc(*q,fp) ; q++ ; }
277          }
278       }
279       else  /* sprintf */
280       {
281          while (*q != '%')
282             if (*q == 0)
283             {
284                if (target > sprintf_limit)      /* damaged */
285                {
286                   /* hope this works */
287                   rt_overflow("sprintf buffer",
288                               sprintf_limit - sprintf_buff) ;
289                }
290                else  /* really done */
291                {
292                   STRING *retval ;
293                   int len = target - sprintf_buff ;
294
295                   retval = new_STRING0(len) ;
296                   memcpy(retval->str, sprintf_buff, len) ;
297                   return retval ;
298                }
299             }
300             else  *target++ = *q++ ;
301       }
302
303
304       /* *q == '%' */
305       num_conversion++ ;
306
307       if (*++q == '%')          /* %% */
308       {
309          if (fp)  putc(*q, fp) ;
310          else  *target++ = *q ;
311
312          q++ ; continue ;
313       }
314
315       /* mark the '%' with p */
316       p = q - 1 ;
317
318       /* eat the flags */
319       while (*q == '-' || *q == '+' || *q == ' ' ||
320              *q == '#' || *q == '0')
321          q++ ;
322
323       ast_cnt = 0 ;
324       if (*q == '*')
325       {
326          if (cp->type != C_DOUBLE)  cast1_to_d(cp) ;
327          ast[ast_cnt++] = d_to_i(cp++->dval) ;
328          argcnt-- ; q++ ;
329       }
330       else
331          while (scan_code[*(unsigned char *) q] == SC_DIGIT)  q++ ;
332       /* width is done */
333
334       if (*q == '.')            /* have precision */
335       {
336          q++ ;
337          if (*q == '*')
338          {
339             if (cp->type != C_DOUBLE)  cast1_to_d(cp) ;
340             ast[ast_cnt++] = d_to_i(cp++->dval) ;
341             argcnt-- ; q++ ;
342          }
343          else
344             while (scan_code[*(unsigned char *) q] == SC_DIGIT)  q++ ;
345       }
346
347       if (argcnt <= 0)
348          rt_error("not enough arguments passed to %s(\"%s\")",
349                   who, format) ;
350
351       l_flag = h_flag = 0 ;
352
353       if (*q == 'l')  { q++ ; l_flag = 1 ; }
354       else if (*q == 'h')  { q++ ; h_flag = 1 ; }
355       switch (*q++)
356       {
357          case 's':
358             if (l_flag + h_flag)
359                bad_conversion(num_conversion, who, format) ;
360             if (cp->type < C_STRING)  cast1_to_s(cp) ;
361             pf_type = PF_S ;
362             break ;
363
364          case 'c':
365             if (l_flag + h_flag)
366                bad_conversion(num_conversion, who, format) ;
367
368             switch (cp->type)
369             {
370                case C_NOINIT:
371                   Ival = 0 ;
372                   break ;
373
374                case C_STRNUM:
375                case C_DOUBLE:
376                   Ival =  d_to_I(cp->dval) ;
377                   break ;
378
379                case C_STRING:
380                   Ival = string(cp)->str[0] ;
381                   break ;
382
383                case C_MBSTRN:
384                   check_strnum(cp) ;
385                   Ival = cp->type == C_STRING ?
386                      string(cp)->str[0] : d_to_I(cp->dval) ;
387                   break ;
388
389                default:
390                   bozo("printf %c") ;
391             }
392
393             pf_type = PF_C ;
394             break ;
395
396          case 'd':
397          case 'o':
398          case 'x':
399          case 'X':
400          case 'i':
401          case 'u':
402             if (cp->type != C_DOUBLE)  cast1_to_d(cp) ;
403             Ival = d_to_I(cp->dval) ;
404             pf_type = PF_D ;
405             break ;
406
407          case 'e':
408          case 'g':
409          case 'f':
410          case 'E':
411          case 'G':
412             if (h_flag + l_flag)
413                bad_conversion(num_conversion, who, format) ;
414             if (cp->type != C_DOUBLE)  cast1_to_d(cp) ;
415             pf_type = PF_F ;
416             break ;
417
418          default:
419             bad_conversion(num_conversion, who, format) ;
420       }
421
422       save = *q ;
423       *q = 0 ;
424
425 #ifdef  SHORT_INTS
426       if (pf_type == PF_D)
427       {
428          /* need to splice in long modifier */
429          strcpy(xbuff, p) ;
430
431          if (l_flag) /* do nothing */ ;
432          else
433          {
434             int k = q - p ;
435
436             if (h_flag)
437             {
438                Ival = (short) Ival ;
439                /* replace the 'h' with 'l' (really!) */
440                xbuff[k - 2] = 'l' ;
441                if (xbuff[k - 1] != 'd' && xbuff[k - 1] != 'i')
442                   Ival &= 0xffff ;
443             }
444             else
445             {
446                /* the usual case */
447                xbuff[k] = xbuff[k - 1] ;
448                xbuff[k - 1] = 'l' ;
449                xbuff[k + 1] = 0 ;
450             }
451          }
452       }
453 #endif
454
455       /* ready to call printf() */
456       switch (AST(ast_cnt, pf_type))
457       {
458          case AST(0, PF_C):
459             (*printer) ((PTR) target, p, (int) Ival) ;
460             break ;
461
462          case AST(1, PF_C):
463             (*printer) ((PTR) target, p, ast[0], (int) Ival) ;
464             break ;
465
466          case AST(2, PF_C):
467             (*printer) ((PTR) target, p, ast[0], ast[1], (int) Ival) ;
468             break ;
469
470          case AST(0, PF_S):
471             (*printer) ((PTR) target, p, string(cp)->str) ;
472             break ;
473
474          case AST(1, PF_S):
475             (*printer) ((PTR) target, p, ast[0], string(cp)->str) ;
476             break ;
477
478          case AST(2, PF_S):
479             (*printer) ((PTR) target, p, ast[0], ast[1], string(cp)->str) ;
480             break ;
481
482 #ifdef  SHORT_INTS
483 #define FMT     xbuff           /* format in xbuff */
484 #else
485 #define FMT     p               /* p -> format */
486 #endif
487          case AST(0, PF_D):
488             (*printer) ((PTR) target, FMT, Ival) ;
489             break ;
490
491          case AST(1, PF_D):
492             (*printer) ((PTR) target, FMT, ast[0], Ival) ;
493             break ;
494
495          case AST(2, PF_D):
496             (*printer) ((PTR) target, FMT, ast[0], ast[1], Ival) ;
497             break ;
498
499 #undef  FMT
500
501
502          case AST(0, PF_F):
503             (*printer) ((PTR) target, p, cp->dval) ;
504             break ;
505
506          case AST(1, PF_F):
507             (*printer) ((PTR) target, p, ast[0], cp->dval) ;
508             break ;
509
510          case AST(2, PF_F):
511             (*printer) ((PTR) target, p, ast[0], ast[1], cp->dval) ;
512             break ;
513       }
514       if (fp == (FILE *) 0)
515          while (*target)  target++ ;
516       *q = save ; argcnt-- ; cp++ ;
517    }
518 }
519
520 CELL *
521 bi_printf(sp)
522    register CELL *sp ;
523 {
524    register int k ;
525    register CELL *p ;
526    FILE *fp ;
527
528    k = sp->type ;
529    if (k < 0)
530    {
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)) ;
535       k = (--sp)->type ;
536       /* k is now number of args including format */
537    }
538    else  fp = stdout ;
539
540    sp -= k ;                     /* sp points at the format string */
541    k-- ;
542
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)) ;
546
547    /* cleanup arguments on eval stack */
548    for (p = sp + 1; k; k--, p++)  cell_destroy(p) ;
549    return --sp ;
550 }
551
552 CELL *
553 bi_sprintf(sp)
554    CELL *sp ;
555 {
556    CELL *p ;
557    int argcnt = sp->type ;
558    STRING *sval ;
559
560    sp -= argcnt ;                /* sp points at the format string */
561    argcnt-- ;
562
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 ;
567
568    /* cleanup */
569    for (p = sp + 1; argcnt; argcnt--, p++)  cell_destroy(p) ;
570
571    return sp ;
572 }
573
574
575 static void 
576 write_error()
577 {
578    errmsg(errno, "write failure") ;
579    mawk_exit(2) ;
580 }