ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.38
Committed: Fri Mar 10 17:38:01 2023 UTC (13 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4
Changes since 1.37: +2 -1 lines
Log Message:
perf(rcalc): don't bother to reduce constant expressions with -n option

File Contents

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