ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.19
Committed: Tue Jun 14 01:25:02 2005 UTC (18 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad3R8
Changes since 1.18: +5 -2 lines
Log Message:
Fixed bug in rcalc with -l option where it sometimes hung

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.19 static const char RCSid[] = "$Id: rcalc.c,v 1.18 2005/06/02 04:47:27 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * rcalc.c - record calculator program.
6     *
7     * 9/11/87
8     */
9    
10 schorsch 1.5 #include <stdlib.h>
11 schorsch 1.11 #include <fcntl.h>
12 greg 1.1 #include <stdio.h>
13 schorsch 1.5 #include <string.h>
14 greg 1.1 #include <math.h>
15     #include <ctype.h>
16    
17 schorsch 1.5 #include "platform.h"
18 schorsch 1.12 #include "rterror.h"
19     #include "rtmisc.h"
20     #include "rtio.h"
21 greg 1.1 #include "calcomp.h"
22    
23     #define isnum(c) (isdigit(c) || (c)=='-' || (c)=='.' \
24     || (c)=='+' || (c)=='e' || (c)=='E')
25    
26     #define isblnk(c) (igneol ? isspace(c) : (c)==' '||(c)=='\t')
27    
28 greg 1.16 #define INBSIZ 16384 /* longest record */
29 greg 1.1 #define MAXCOL 32 /* number of columns recorded */
30    
31     /* field type specifications */
32     #define F_NUL 0 /* empty */
33     #define F_TYP 0x7000 /* mask for type */
34     #define F_WID 0x0fff /* mask for width */
35     #define T_LIT 0x1000 /* string literal */
36     #define T_STR 0x2000 /* string variable */
37     #define T_NUM 0x3000 /* numeric value */
38    
39     struct strvar { /* string variable */
40     char *name;
41     char *val;
42     char *preset;
43     struct strvar *next;
44     };
45    
46     struct field { /* record format structure */
47     int type; /* type of field (& width) */
48     union {
49     char *sl; /* string literal */
50     struct strvar *sv; /* string variable */
51     char *nv; /* numeric variable */
52     EPNODE *ne; /* numeric expression */
53     } f; /* field contents */
54     struct field *next; /* next field in record */
55     };
56    
57     #define savqstr(s) strcpy(emalloc(strlen(s)+1),s)
58     #define freqstr(s) efree(s)
59    
60 greg 1.10 static int getinputrec(FILE *fp);
61 schorsch 1.5 static void scaninp(void), advinp(void), resetinp(void);
62     static void putrec(void), putout(void), nbsynch(void);
63     static int getrec(void);
64     static void execute(char *file);
65     static void initinp(FILE *fp);
66     static void svpreset(char *eqn);
67     static void readfmt(char *spec, int output);
68     static int readfield(char **pp);
69     static int getfield(struct field *f);
70     static void chanset(int n, double v);
71     static void bchanset(int n, double v);
72     static struct strvar* getsvar(char *svname);
73 greg 1.10 static double l_in(char *);
74 greg 1.1
75     struct field *inpfmt = NULL; /* input record format */
76     struct field *outfmt = NULL; /* output record structure */
77     struct strvar *svhead = NULL; /* string variables */
78    
79     int blnkeq = 1; /* blanks compare equal? */
80     int igneol = 0; /* ignore end of line? */
81 greg 1.13 int passive = 0; /* passive mode (transmit unmatched input) */
82 greg 1.1 char sepchar = '\t'; /* input/output separator */
83     int noinput = 0; /* no input records? */
84 greg 1.3 int nbicols = 0; /* number of binary input columns */
85     int bocols = 0; /* produce binary output columns */
86 greg 1.1 char inpbuf[INBSIZ]; /* input buffer */
87     double colval[MAXCOL]; /* input column values */
88     unsigned long colflg = 0; /* column retrieved flags */
89     int colpos; /* output column position */
90    
91     int nowarn = 0; /* non-fatal diagnostic output */
92     int unbuff = 0; /* unbuffered output (flush each record) */
93    
94     struct {
95     FILE *fin; /* input file */
96     int chr; /* next character */
97     char *beg; /* home position */
98     char *pos; /* scan position */
99     char *end; /* read position */
100     } ipb; /* circular lookahead buffer */
101    
102    
103 schorsch 1.5 int
104     main(
105     int argc,
106     char *argv[]
107     )
108 greg 1.1 {
109     int i;
110    
111 greg 1.2 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
112     esupport &= ~(E_REDEFW);
113 greg 1.1
114     #ifdef BIGGERLIB
115     biggerlib();
116     #endif
117     varset("PI", ':', 3.14159265358979323846);
118 greg 1.10 funset("in", 1, '=', &l_in);
119 greg 1.1
120     for (i = 1; i < argc && argv[i][0] == '-'; i++)
121     switch (argv[i][1]) {
122     case 'b':
123     blnkeq = !blnkeq;
124     break;
125     case 'l':
126     igneol = !igneol;
127     break;
128 greg 1.13 case 'p':
129     passive = !passive;
130     break;
131 greg 1.1 case 't':
132     sepchar = argv[i][2];
133     break;
134     case 's':
135     svpreset(argv[++i]);
136     break;
137     case 'f':
138     fcompile(argv[++i]);
139     break;
140     case 'e':
141     scompile(argv[++i], NULL, 0);
142     break;
143     case 'n':
144     noinput = 1;
145     break;
146     case 'i':
147 greg 1.3 switch (argv[i][2]) {
148     case '\0':
149     nbicols = 0;
150     readfmt(argv[++i], 0);
151     break;
152     case 'a':
153     nbicols = 0;
154     break;
155     case 'd':
156     if (isdigit(argv[i][3]))
157     nbicols = atoi(argv[i]+3);
158     else
159     nbicols = 1;
160 greg 1.9 if (nbicols*sizeof(double) > INBSIZ) {
161     eputs(argv[0]);
162     eputs(": too many input columns\n");
163     quit(1);
164     }
165 greg 1.3 break;
166     case 'f':
167     if (isdigit(argv[i][3]))
168     nbicols = -atoi(argv[i]+3);
169     else
170     nbicols = -1;
171 greg 1.9 if (-nbicols*sizeof(float) > INBSIZ) {
172     eputs(argv[0]);
173     eputs(": too many input columns\n");
174     quit(1);
175     }
176 greg 1.3 break;
177     default:
178     goto userr;
179     }
180 greg 1.1 break;
181     case 'o':
182 greg 1.3 switch (argv[i][2]) {
183     case '\0':
184     bocols = 0;
185     readfmt(argv[++i], 1);
186     break;
187     case 'a':
188     bocols = 0;
189     break;
190     case 'd':
191     bocols = 1;
192 greg 1.18 SET_FILE_BINARY(stdout);
193 greg 1.3 break;
194     case 'f':
195     bocols = -1;
196 greg 1.18 SET_FILE_BINARY(stdout);
197 greg 1.3 break;
198 greg 1.18 default:
199     goto userr;
200 greg 1.3 }
201 greg 1.1 break;
202     case 'w':
203     nowarn = !nowarn;
204     break;
205     case 'u':
206     unbuff = !unbuff;
207     break;
208 greg 1.3 default:;
209     userr:
210 greg 1.1 eputs("Usage: ");
211     eputs(argv[0]);
212 greg 1.13 eputs(" [-b][-l][-n][-p][-w][-u][-tS][-s svar=sval][-e expr][-f source][-i infmt][-o outfmt] [file]\n");
213 greg 1.1 quit(1);
214     }
215 greg 1.18 if (bocols)
216     SET_FILE_BINARY(stdout);
217 greg 1.1 if (noinput) { /* produce a single output record */
218 greg 1.17 if (i < argc) {
219     eputs(argv[0]);
220     eputs(": file argument(s) incompatible with -n\n");
221     quit(1);
222     }
223 greg 1.1 eclock++;
224     putout();
225     quit(0);
226     }
227 greg 1.18 if (nbicols)
228     SET_FILE_BINARY(stdin);
229 greg 1.1
230     if (blnkeq) /* for efficiency */
231     nbsynch();
232    
233     if (i == argc) /* from stdin */
234     execute(NULL);
235     else /* from one or more files */
236     for ( ; i < argc; i++)
237     execute(argv[i]);
238    
239     quit(0);
240 schorsch 1.11 return 0; /* pro forma return */
241 greg 1.1 }
242    
243    
244 schorsch 1.5 static void
245     nbsynch(void) /* non-blank starting synch character */
246 greg 1.1 {
247     if (inpfmt == NULL || (inpfmt->type & F_TYP) != T_LIT)
248     return;
249     while (isblnk(*inpfmt->f.sl))
250     inpfmt->f.sl++;
251     if (!*inpfmt->f.sl)
252     inpfmt = inpfmt->next;
253     }
254    
255    
256 greg 1.10 static int
257 schorsch 1.5 getinputrec( /* get next input record */
258     FILE *fp
259     )
260 greg 1.3 {
261     if (inpfmt != NULL)
262     return(getrec());
263     if (nbicols > 0)
264     return(fread(inpbuf, sizeof(double),
265     nbicols, fp) == nbicols);
266     if (nbicols < 0)
267     return(fread(inpbuf, sizeof(float),
268     -nbicols, fp) == -nbicols);
269     return(fgets(inpbuf, INBSIZ, fp) != NULL);
270     }
271    
272    
273 schorsch 1.5 static void
274     execute( /* process a file */
275     char *file
276     )
277 greg 1.1 {
278     int conditional = vardefined("cond");
279     long nrecs = 0;
280     long nout = 0;
281     FILE *fp;
282    
283     if (file == NULL)
284     fp = stdin;
285     else if ((fp = fopen(file, "r")) == NULL) {
286     eputs(file);
287     eputs(": cannot open\n");
288     quit(1);
289     }
290     if (inpfmt != NULL)
291     initinp(fp);
292 greg 1.3
293     while (getinputrec(fp)) {
294 greg 1.1 varset("recno", '=', (double)++nrecs);
295     colflg = 0;
296     eclock++;
297     if (!conditional || varvalue("cond") > 0.0) {
298     varset("outno", '=', (double)++nout);
299     putout();
300     }
301     }
302     fclose(fp);
303     }
304    
305    
306 schorsch 1.5 static void
307     putout(void) /* produce an output record */
308 greg 1.1 {
309    
310     colpos = 0;
311     if (outfmt != NULL)
312     putrec();
313 greg 1.3 else if (bocols)
314     chanout(bchanset);
315 greg 1.1 else
316     chanout(chanset);
317 greg 1.4 if (colpos && !bocols)
318 greg 1.1 putchar('\n');
319     if (unbuff)
320     fflush(stdout);
321     }
322    
323 greg 1.10
324     static double
325     l_in(char *funame) /* function call for $channel */
326     {
327     int n;
328     register char *cp;
329     /* get argument as integer */
330     n = (int)(argument(1) + .5);
331     if (n != 0) /* return channel value */
332     return(chanvalue(n));
333     /* determine number of channels */
334     if (noinput || inpfmt != NULL)
335     return(0);
336     if (nbicols > 0)
337     return(nbicols);
338     if (nbicols < 0)
339     return(-nbicols);
340     cp = inpbuf; /* need to count */
341     for (n = 0; *cp; )
342     if (blnkeq && isspace(sepchar)) {
343     while (isspace(*cp))
344     cp++;
345     n += *cp != '\0';
346     while (*cp && !isspace(*cp))
347     cp++;
348     } else {
349     n += *cp != '\n';
350     while (*cp && *cp++ != sepchar)
351     ;
352     }
353     return(n);
354     }
355 greg 1.1
356     double
357 schorsch 1.5 chanvalue( /* return value for column n */
358     int n
359     )
360 greg 1.1 {
361     int i;
362     register char *cp;
363    
364     if (noinput || inpfmt != NULL) {
365     eputs("no column input\n");
366     quit(1);
367     }
368     if (n < 1) {
369     eputs("illegal channel number\n");
370     quit(1);
371     }
372 greg 1.3 if (nbicols > 0) {
373     if (n > nbicols)
374     return(0.0);
375     cp = inpbuf + (n-1)*sizeof(double);
376     return(*(double *)cp);
377     }
378     if (nbicols < 0) {
379     if (n > -nbicols)
380     return(0.0);
381     cp = inpbuf + (n-1)*sizeof(float);
382     return(*(float *)cp);
383     }
384 greg 1.1 if (n <= MAXCOL && colflg & 1L<<(n-1))
385     return(colval[n-1]);
386    
387     cp = inpbuf;
388     for (i = 1; i < n; i++)
389     if (blnkeq && isspace(sepchar)) {
390     while (isspace(*cp))
391     cp++;
392     while (*cp && !isspace(*cp))
393     cp++;
394     } else
395     while (*cp && *cp++ != sepchar)
396     ;
397    
398     while (isspace(*cp)) /* some atof()'s don't like tabs */
399     cp++;
400    
401     if (n <= MAXCOL) {
402     colflg |= 1L<<(n-1);
403     return(colval[n-1] = atof(cp));
404     } else
405     return(atof(cp));
406     }
407    
408    
409 greg 1.3 void
410 schorsch 1.5 chanset( /* output column n */
411     int n,
412     double v
413     )
414 greg 1.1 {
415     if (colpos == 0) /* no leading separator */
416     colpos = 1;
417     while (colpos < n) {
418     putchar(sepchar);
419     colpos++;
420     }
421     printf("%.9g", v);
422 greg 1.3 }
423    
424    
425     void
426 schorsch 1.5 bchanset( /* output binary channel n */
427     int n,
428     double v
429     )
430 greg 1.3 {
431     static char zerobuf[sizeof(double)];
432    
433     while (++colpos < n)
434     fwrite(zerobuf,
435     bocols>0 ? sizeof(double) : sizeof(float),
436     1, stdout);
437     if (bocols > 0)
438     fwrite(&v, sizeof(double), 1, stdout);
439     else {
440     float fval = v;
441     fwrite(&fval, sizeof(float), 1, stdout);
442     }
443 greg 1.1 }
444    
445    
446 schorsch 1.5 static void
447     readfmt( /* read record format */
448     char *spec,
449     int output
450     )
451 greg 1.1 {
452     int fd;
453     char *inptr;
454     struct field fmt;
455     int res;
456     register struct field *f;
457     /* check for inline format */
458     for (inptr = spec; *inptr; inptr++)
459     if (*inptr == '$')
460     break;
461     if (*inptr) /* inline */
462     inptr = spec;
463     else { /* from file */
464     if ((fd = open(spec, 0)) == -1) {
465     eputs(spec);
466     eputs(": cannot open\n");
467     quit(1);
468     }
469 greg 1.14 res = read(fd, inpbuf+2, INBSIZ-2);
470 greg 1.1 if (res <= 0 || res >= INBSIZ-1) {
471     eputs(spec);
472     if (res < 0)
473     eputs(": read error\n");
474     else if (res == 0)
475     eputs(": empty file\n");
476     else if (res >= INBSIZ-1)
477     eputs(": format too long\n");
478     quit(1);
479     }
480     close(fd);
481 greg 1.14 (inptr=inpbuf+2)[res] = '\0';
482 greg 1.1 }
483     f = &fmt; /* get fields */
484     while ((res = readfield(&inptr)) != F_NUL) {
485     f->next = (struct field *)emalloc(sizeof(struct field));
486     f = f->next;
487     f->type = res;
488     switch (res & F_TYP) {
489     case T_LIT:
490     f->f.sl = savqstr(inpbuf);
491     break;
492     case T_STR:
493     f->f.sv = getsvar(inpbuf);
494     break;
495     case T_NUM:
496     if (output)
497     f->f.ne = eparse(inpbuf);
498     else
499     f->f.nv = savestr(inpbuf);
500     break;
501     }
502     /* add final newline if necessary */
503     if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
504     inptr = "\n";
505     }
506     f->next = NULL;
507     if (output)
508     outfmt = fmt.next;
509     else
510     inpfmt = fmt.next;
511     }
512    
513    
514 schorsch 1.5 static int
515     readfield( /* get next field in format */
516     register char **pp
517     )
518 greg 1.1 {
519     int type = F_NUL;
520     int width = 0;
521     register char *cp;
522    
523     cp = inpbuf;
524     while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
525     width++;
526     switch (type) {
527     case F_NUL:
528     if (**pp == '$') {
529     (*pp)++;
530     width++;
531     if (**pp == '{') {
532     type = T_NUM;
533     (*pp)++;
534     continue;
535     } else if (**pp == '(') {
536     type = T_STR;
537     (*pp)++;
538     continue;
539     } else if (**pp != '$') {
540     eputs("format error\n");
541     quit(1);
542     }
543     width--;
544     }
545     type = T_LIT;
546     *cp++ = *(*pp)++;
547     continue;
548     case T_LIT:
549     if (**pp == '$') {
550     width--;
551     break;
552     }
553     *cp++ = *(*pp)++;
554     continue;
555     case T_NUM:
556     if (**pp == '}') {
557     (*pp)++;
558     break;
559     }
560     if (!isspace(**pp))
561     *cp++ = **pp;
562     (*pp)++;
563     continue;
564     case T_STR:
565     if (**pp == ')') {
566     (*pp)++;
567     break;
568     }
569     if (!isspace(**pp))
570     *cp++ = **pp;
571     (*pp)++;
572     continue;
573     }
574     break;
575     }
576     *cp = '\0';
577     return(type | width);
578     }
579    
580    
581     struct strvar *
582 schorsch 1.5 getsvar( /* get string variable */
583     char *svname
584     )
585 greg 1.1 {
586     register struct strvar *sv;
587    
588     for (sv = svhead; sv != NULL; sv = sv->next)
589     if (!strcmp(sv->name, svname))
590     return(sv);
591     sv = (struct strvar *)emalloc(sizeof(struct strvar));
592     sv->name = savqstr(svname);
593     sv->val = sv->preset = NULL;
594     sv->next = svhead;
595     svhead = sv;
596     return(sv);
597     }
598    
599    
600 schorsch 1.5 static void
601     svpreset( /* preset a string variable */
602     char *eqn
603     )
604 greg 1.1 {
605     register struct strvar *sv;
606     register char *val;
607    
608     for (val = eqn; *val != '='; val++)
609     if (!*val)
610     return;
611     *val++ = '\0';
612     sv = getsvar(eqn);
613     if (sv->preset != NULL)
614     freqstr(sv->preset);
615     if (sv->val != NULL)
616     freqstr(sv->val);
617     sv->val = sv->preset = savqstr(val);
618     *--val = '=';
619     }
620    
621    
622 schorsch 1.5 static void
623     clearrec(void) /* clear input record variables */
624 greg 1.1 {
625     register struct field *f;
626    
627     for (f = inpfmt; f != NULL; f = f->next)
628     switch (f->type & F_TYP) {
629     case T_NUM:
630     dremove(f->f.nv);
631     break;
632     case T_STR:
633     if (f->f.sv->val != f->f.sv->preset) {
634     freqstr(f->f.sv->val);
635     f->f.sv->val = f->f.sv->preset;
636     }
637     break;
638     }
639     }
640    
641    
642 schorsch 1.5 static int
643 greg 1.13 getrec(void) /* get next record from file */
644 greg 1.1 {
645     int eatline;
646     register struct field *f;
647 greg 1.14
648 greg 1.1 while (ipb.chr != EOF) {
649 greg 1.19 if (blnkeq) { /* beware of nbsynch() */
650 greg 1.1 while (isblnk(ipb.chr))
651 greg 1.13 resetinp();
652 greg 1.19 if (ipb.chr == EOF)
653     return(0);
654     }
655 greg 1.15 eatline = (!igneol && ipb.chr != '\n');
656 greg 1.1 clearrec(); /* start with fresh record */
657     for (f = inpfmt; f != NULL; f = f->next)
658     if (getfield(f) == -1)
659     break;
660     if (f == NULL) {
661 greg 1.13 advinp(); /* got one! */
662 greg 1.1 return(1);
663     }
664 greg 1.13 resetinp(); /* eat false start */
665 greg 1.1 if (eatline) { /* eat rest of line */
666     while (ipb.chr != '\n') {
667     if (ipb.chr == EOF)
668     return(0);
669 greg 1.13 resetinp();
670 greg 1.1 }
671 greg 1.13 resetinp();
672 greg 1.1 }
673     }
674     return(0);
675     }
676    
677    
678 schorsch 1.5 static int
679     getfield( /* get next field */
680     register struct field *f
681     )
682 greg 1.1 {
683 schorsch 1.6 static char buf[RMAXWORD+1]; /* no recursion! */
684 greg 1.1 int delim, inword;
685     double d;
686     char *np;
687     register char *cp;
688    
689     switch (f->type & F_TYP) {
690     case T_LIT:
691     cp = f->f.sl;
692     do {
693     if (blnkeq && isblnk(*cp)) {
694     if (!isblnk(ipb.chr))
695     return(-1);
696     do
697     cp++;
698     while (isblnk(*cp));
699     do
700     scaninp();
701     while (isblnk(ipb.chr));
702     } else if (*cp == ipb.chr) {
703     cp++;
704     scaninp();
705     } else
706     return(-1);
707     } while (*cp);
708     return(0);
709     case T_STR:
710     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
711     delim = EOF;
712     else
713     delim = f->next->f.sl[0];
714     cp = buf;
715     do {
716 greg 1.9 if (ipb.chr == EOF || ipb.chr == '\n')
717 greg 1.1 inword = 0;
718     else if (blnkeq && delim != EOF)
719     inword = isblnk(delim) ?
720     !isblnk(ipb.chr)
721     : ipb.chr != delim;
722     else
723     inword = cp-buf < (f->type & F_WID);
724     if (inword) {
725     *cp++ = ipb.chr;
726     scaninp();
727     }
728 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
729 greg 1.1 *cp = '\0';
730     if (f->f.sv->val == NULL)
731     f->f.sv->val = savqstr(buf); /* first setting */
732     else if (strcmp(f->f.sv->val, buf))
733     return(-1); /* doesn't match! */
734     return(0);
735     case T_NUM:
736     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
737     delim = EOF;
738     else
739     delim = f->next->f.sl[0];
740     np = NULL;
741     cp = buf;
742     do {
743     if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
744     inword = 0;
745     else if (blnkeq && delim != EOF)
746     inword = isblnk(delim) ?
747     !isblnk(ipb.chr)
748     : ipb.chr != delim;
749     else
750     inword = cp-buf < (f->type & F_WID);
751     if (inword) {
752     if (np==NULL && !isblnk(ipb.chr))
753     np = cp;
754     *cp++ = ipb.chr;
755     scaninp();
756     }
757 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
758 greg 1.1 *cp = '\0';
759     d = np==NULL ? 0. : atof(np);
760     if (!vardefined(f->f.nv))
761     varset(f->f.nv, '=', d); /* first setting */
762     else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
763     || d < -.001)
764     return(-1); /* doesn't match! */
765     return(0);
766     }
767 schorsch 1.5 return -1; /* pro forma return */
768 greg 1.1 }
769    
770    
771 schorsch 1.5 static void
772     putrec(void) /* output a record */
773 greg 1.1 {
774     char fmt[32];
775     register int n;
776     register struct field *f;
777     int adlast, adnext;
778    
779     adlast = 0;
780     for (f = outfmt; f != NULL; f = f->next) {
781     adnext = blnkeq &&
782     f->next != NULL &&
783     !( (f->next->type&F_TYP) == T_LIT &&
784     f->next->f.sl[0] == ' ' );
785     switch (f->type & F_TYP) {
786     case T_LIT:
787     fputs(f->f.sl, stdout);
788     adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
789     break;
790     case T_STR:
791     if (f->f.sv->val == NULL) {
792     eputs(f->f.sv->name);
793     eputs(": undefined string\n");
794     quit(1);
795     }
796     n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
797     if (adlast)
798     fputs(f->f.sv->val, stdout);
799     if (!(adlast && adnext))
800     while (n-- > 0)
801     putchar(' ');
802     if (!adlast)
803     fputs(f->f.sv->val, stdout);
804     adlast = 1;
805     break;
806     case T_NUM:
807     n = f->type & F_WID;
808     if (adlast && adnext)
809     strcpy(fmt, "%g");
810     else if (adlast)
811     sprintf(fmt, "%%-%dg", n);
812     else
813     sprintf(fmt, "%%%dg", n);
814     printf(fmt, evalue(f->f.ne));
815     adlast = 1;
816     break;
817     }
818     }
819     }
820    
821    
822 schorsch 1.5 static void
823     initinp(FILE *fp) /* prepare lookahead buffer */
824    
825 greg 1.1 {
826     ipb.fin = fp;
827     ipb.beg = ipb.end = inpbuf;
828     ipb.pos = inpbuf-1; /* position before beginning */
829     ipb.chr = '\0';
830     scaninp();
831     }
832    
833    
834 schorsch 1.5 static void
835     scaninp(void) /* scan next character */
836 greg 1.1 {
837     if (ipb.chr == EOF)
838     return;
839     if (++ipb.pos >= &inpbuf[INBSIZ])
840     ipb.pos = inpbuf;
841     if (ipb.pos == ipb.end) { /* new character */
842     if ((ipb.chr = getc(ipb.fin)) != EOF) {
843     *ipb.end = ipb.chr;
844     if (++ipb.end >= &inpbuf[INBSIZ])
845     ipb.end = inpbuf;
846     if (ipb.end == ipb.beg)
847     ipb.beg = NULL;
848     }
849     } else
850     ipb.chr = *ipb.pos;
851     }
852    
853    
854 schorsch 1.5 static void
855     advinp(void) /* move home to current position */
856 greg 1.1 {
857     ipb.beg = ipb.pos;
858     }
859    
860    
861 schorsch 1.5 static void
862     resetinp(void) /* rewind position and advance 1 */
863 greg 1.1 {
864     if (ipb.beg == NULL) /* full */
865     ipb.beg = ipb.end;
866     ipb.pos = ipb.beg;
867     ipb.chr = *ipb.pos;
868 greg 1.13 if (passive) /* transmit unmatched character? */
869     fputc(ipb.chr, stdout);
870 greg 1.1 if (++ipb.beg >= &inpbuf[INBSIZ])
871     ipb.beg = inpbuf;
872     scaninp();
873     }
874    
875    
876     void
877 schorsch 1.5 eputs(char *msg)
878 greg 1.1 {
879     fputs(msg, stderr);
880     }
881    
882    
883     void
884 schorsch 1.5 wputs(char *msg)
885 greg 1.1 {
886     if (!nowarn)
887     eputs(msg);
888     }
889    
890    
891     void
892 schorsch 1.5 quit(int code)
893 greg 1.1 {
894     exit(code);
895     }