ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.39
Committed: Fri Feb 23 03:47:57 2024 UTC (2 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.38: +3 -1 lines
Error occurred while calculating annotation data.
Log Message:
perf: Added array index optimization to calcomp routines

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rcalc.c,v 1.38 2023/03/10 17:38:01 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 doptimize(1); /* optimize definitions */
263
264 if (i == argc) /* from stdin */
265 execute(NULL);
266 else /* from one or more files */
267 for ( ; i < argc; i++)
268 execute(argv[i]);
269
270 quit(0);
271 return 0; /* pro forma return */
272 }
273
274
275 static void
276 nbsynch(void) /* non-blank starting synch character */
277 {
278 if (inpfmt == NULL || (inpfmt->type & F_TYP) != T_LIT)
279 return;
280 while (isblnk(*inpfmt->f.sl))
281 inpfmt->f.sl++;
282 if (!*inpfmt->f.sl)
283 inpfmt = inpfmt->next;
284 }
285
286
287 static int
288 getinputrec( /* get next input record */
289 FILE *fp
290 )
291 {
292 if ((itype == 'd') | (itype == 'D')) {
293 if (getbinary(inpbuf, sizeof(double), nbicols, fp) != nbicols)
294 return(0);
295 if (itype == 'D')
296 swap64(inpbuf, nbicols);
297 return(1);
298 }
299 if ((itype == 'f') | (itype == 'F')) {
300 if (getbinary(inpbuf, sizeof(float), nbicols, fp) != nbicols)
301 return(0);
302 if (itype == 'F')
303 swap32(inpbuf, nbicols);
304 return(1);
305 }
306 return(fgets(inpbuf, INBSIZ, fp) != NULL);
307 }
308
309
310 static void
311 execute( /* process a file */
312 char *file
313 )
314 {
315 static char condVN[] = "cond";
316 static char recnoVN[] = "recno";
317 static char outnoVN[] = "outno";
318 const int conditional = vardefined(condVN);
319 const int set_recno = (varlookup(recnoVN) != NULL);
320 const int set_outno = (varlookup(outnoVN) != NULL);
321 long nrecs = 0;
322 long nout = 0;
323 FILE *fp;
324
325 if (file == NULL)
326 fp = stdin;
327 else if ((fp = fopen(file, "r")) == NULL) {
328 eputs(file);
329 eputs(": cannot open\n");
330 quit(1);
331 }
332 if (itype != 'a')
333 SET_FILE_BINARY(fp);
334 #ifdef getc_unlocked /* avoid lock/unlock overhead */
335 flockfile(fp);
336 #endif
337 if (conditional == ':') {
338 eputs(condVN);
339 eputs(": defined as constant\n");
340 quit(1);
341 }
342 if (inpfmt != NULL)
343 initinp(fp);
344
345 while (inpfmt != NULL ? getrec() : getinputrec(fp)) {
346 ++nrecs;
347 if (set_recno)
348 varset(recnoVN, '=', (double)nrecs);
349 if (set_outno)
350 varset(outnoVN, '=', (double)(nout+1));
351 colflg = 0;
352 eclock++;
353 if (!conditional || varvalue(condVN) > 0.0) {
354 if (inpfmt != NULL)
355 advinp(0);
356 putout();
357 ++nout;
358 } else if (inpfmt != NULL) {
359 advinp(1);
360 }
361 if (incnt && nrecs >= incnt)
362 break;
363 if (outcnt && nout >= outcnt)
364 break;
365 }
366 fclose(fp);
367 }
368
369
370 static void
371 putout(void) /* produce an output record */
372 {
373
374 colpos = 0;
375 if (outfmt != NULL)
376 putrec();
377 else if (otype == 'a')
378 chanout(chanset);
379 else
380 chanout(bchanset);
381 if (colpos && otype == 'a')
382 putchar('\n');
383 if (unbuff)
384 fflush(stdout);
385 }
386
387
388 static double
389 l_in(char *funame) /* function call for $channel */
390 {
391 int n;
392 char *cp;
393 /* get argument as integer */
394 n = (int)(argument(1) + .5);
395 if (n != 0) /* return channel value */
396 return(chanvalue(n));
397 /* determine number of channels */
398 if (noinput || inpfmt != NULL)
399 return(0);
400 if (nbicols)
401 return(nbicols);
402 cp = inpbuf; /* need to count */
403 for (n = 0; *cp; )
404 if (blnkeq && isspace(sepchar)) {
405 while (isspace(*cp))
406 cp++;
407 n += *cp != '\0';
408 while (*cp && !isspace(*cp))
409 cp++;
410 } else {
411 n += *cp != '\n';
412 while (*cp && *cp++ != sepchar)
413 ;
414 }
415 return(n);
416 }
417
418 double
419 chanvalue( /* return value for column n */
420 int n
421 )
422 {
423 int i;
424 char *cp;
425
426 if (noinput || inpfmt != NULL) {
427 eputs("no column input\n");
428 quit(1);
429 }
430 if (n < 1) {
431 eputs("illegal channel number\n");
432 quit(1);
433 }
434 if (nbicols) {
435 if (n > nbicols)
436 return(0.0);
437 if ((itype == 'd') | (itype == 'D')) {
438 cp = inpbuf + (n-1)*sizeof(double);
439 return(*(double *)cp);
440 }
441 cp = inpbuf + (n-1)*sizeof(float);
442 return(*(float *)cp);
443 }
444 if (n <= MAXCOL && colflg & 1L<<(n-1))
445 return(colval[n-1]);
446
447 cp = inpbuf;
448 for (i = 1; i < n; i++)
449 if (blnkeq && isspace(sepchar)) {
450 while (isspace(*cp))
451 cp++;
452 while (*cp && !isspace(*cp))
453 cp++;
454 } else
455 while (*cp && *cp++ != sepchar)
456 ;
457
458 while (isspace(*cp)) /* some atof()'s don't like tabs */
459 cp++;
460
461 if (n <= MAXCOL) {
462 colflg |= 1L<<(n-1);
463 return(colval[n-1] = atof(cp));
464 } else
465 return(atof(cp));
466 }
467
468
469 void
470 chanset( /* output column n */
471 int n,
472 double v
473 )
474 {
475 if (colpos == 0) /* no leading separator */
476 colpos = 1;
477 while (colpos < n) {
478 putchar(sepchar);
479 colpos++;
480 }
481 printf("%.9g", v);
482 }
483
484
485 void
486 bchanset( /* output binary channel n */
487 int n,
488 double v
489 )
490 {
491 static char zerobuf[sizeof(double)];
492 const int otlen = ((otype == 'd') | (otype == 'D')) ?
493 sizeof(double) : sizeof(float);
494 float fval = v;
495
496 while (++colpos < n)
497 putbinary(zerobuf, otlen, 1, stdout);
498 switch (otype) {
499 case 'D':
500 swap64((char *)&v, 1);
501 /* fall through */
502 case 'd':
503 putbinary(&v, sizeof(double), 1, stdout);
504 break;
505 case 'F':
506 swap32((char *)&fval, 1);
507 /* fall through */
508 case 'f':
509 putbinary(&fval, sizeof(float), 1, stdout);
510 break;
511 }
512 }
513
514
515 static void
516 readfmt( /* read record format */
517 char *spec,
518 int output
519 )
520 {
521 int fd;
522 char *inptr;
523 struct field fmt;
524 int res;
525 struct field *f;
526 /* check for inline format */
527 for (inptr = spec; *inptr; inptr++)
528 if (*inptr == '$')
529 break;
530 if (*inptr) /* inline */
531 inptr = spec;
532 else { /* from file */
533 if ((fd = open(spec, 0)) == -1) {
534 eputs(spec);
535 eputs(": cannot open\n");
536 quit(1);
537 }
538 res = read(fd, inpbuf+2, INBSIZ-2);
539 if (res <= 0 || res >= INBSIZ-1) {
540 eputs(spec);
541 if (res < 0)
542 eputs(": read error\n");
543 else if (res == 0)
544 eputs(": empty file\n");
545 else if (res >= INBSIZ-1)
546 eputs(": format too long\n");
547 quit(1);
548 }
549 close(fd);
550 (inptr=inpbuf+2)[res] = '\0';
551 }
552 f = &fmt; /* get fields */
553 while ((res = readfield(&inptr)) != F_NUL) {
554 f->next = (struct field *)emalloc(sizeof(struct field));
555 f = f->next;
556 f->type = res;
557 switch (res & F_TYP) {
558 case T_LIT:
559 f->f.sl = savqstr(inpbuf);
560 break;
561 case T_STR:
562 f->f.sv = getsvar(inpbuf);
563 break;
564 case T_NUM:
565 if (output)
566 f->f.ne = eparse(inpbuf);
567 else
568 f->f.nv = savestr(inpbuf);
569 break;
570 }
571 /* add final newline if necessary */
572 if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
573 inptr = "\n";
574 }
575 f->next = NULL;
576 if (output)
577 outfmt = fmt.next;
578 else
579 inpfmt = fmt.next;
580 }
581
582
583 static int
584 readfield( /* get next field in format */
585 char **pp
586 )
587 {
588 int type = F_NUL;
589 int width = 0;
590 char *cp;
591
592 cp = inpbuf;
593 while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
594 width++;
595 switch (type) {
596 case F_NUL:
597 if (**pp == '$') {
598 (*pp)++;
599 width++;
600 if (**pp == '{') {
601 type = T_NUM;
602 (*pp)++;
603 continue;
604 } else if (**pp == '(') {
605 type = T_STR;
606 (*pp)++;
607 continue;
608 } else if (**pp != '$') {
609 eputs("format error\n");
610 quit(1);
611 }
612 width--;
613 }
614 type = T_LIT;
615 *cp++ = *(*pp)++;
616 continue;
617 case T_LIT:
618 if (**pp == '$') {
619 width--;
620 break;
621 }
622 *cp++ = *(*pp)++;
623 continue;
624 case T_NUM:
625 if (**pp == '}') {
626 (*pp)++;
627 break;
628 }
629 if (!isspace(**pp))
630 *cp++ = **pp;
631 (*pp)++;
632 continue;
633 case T_STR:
634 if (**pp == ')') {
635 (*pp)++;
636 break;
637 }
638 if (!isspace(**pp))
639 *cp++ = **pp;
640 (*pp)++;
641 continue;
642 }
643 break;
644 }
645 *cp = '\0';
646 return(type | width);
647 }
648
649
650 struct strvar *
651 getsvar( /* get string variable */
652 char *svname
653 )
654 {
655 struct strvar *sv;
656
657 for (sv = svhead; sv != NULL; sv = sv->next)
658 if (!strcmp(sv->name, svname))
659 return(sv);
660 sv = (struct strvar *)emalloc(sizeof(struct strvar));
661 sv->name = savqstr(svname);
662 sv->val = sv->preset = NULL;
663 sv->next = svhead;
664 svhead = sv;
665 return(sv);
666 }
667
668
669 static void
670 svpreset( /* preset a string variable */
671 char *eqn
672 )
673 {
674 struct strvar *sv;
675 char *val;
676
677 for (val = eqn; *val != '='; val++)
678 if (!*val)
679 return;
680 *val++ = '\0';
681 sv = getsvar(eqn);
682 if (sv->preset != NULL)
683 freqstr(sv->preset);
684 if (sv->val != NULL)
685 freqstr(sv->val);
686 sv->val = sv->preset = savqstr(val);
687 *--val = '=';
688 }
689
690
691 static void
692 clearrec(void) /* clear input record variables */
693 {
694 struct field *f;
695
696 for (f = inpfmt; f != NULL; f = f->next)
697 switch (f->type & F_TYP) {
698 case T_NUM:
699 dremove(f->f.nv);
700 break;
701 case T_STR:
702 if (f->f.sv->val != f->f.sv->preset) {
703 freqstr(f->f.sv->val);
704 f->f.sv->val = f->f.sv->preset;
705 }
706 break;
707 }
708 }
709
710
711 static int
712 getrec(void) /* get next record from file */
713 {
714 int eatline;
715 struct field *f;
716
717 while (ipb.chr != EOF) {
718 if (blnkeq) { /* beware of nbsynch() */
719 while (isblnk(ipb.chr))
720 skipinp();
721 if (ipb.chr == EOF)
722 return(0);
723 }
724 eatline = !igneol & (ipb.chr != '\n');
725 clearrec(); /* start with fresh record */
726 for (f = inpfmt; f != NULL; f = f->next)
727 if (!getfield(f))
728 break;
729 if (f == NULL) /* got one? */
730 return(1);
731 skipinp(); /* else eat false start */
732 if (eatline) { /* eat rest of line */
733 while (ipb.chr != '\n') {
734 if (ipb.chr == EOF)
735 return(0);
736 skipinp();
737 }
738 skipinp();
739 }
740 }
741 return(0);
742 }
743
744
745 static int
746 getfield( /* get next field */
747 struct field *f
748 )
749 {
750 static char buf[RMAXWORD+1]; /* no recursion! */
751 int delim, inword;
752 double d;
753 char *np;
754 char *cp;
755
756 switch (f->type & F_TYP) {
757 case T_LIT:
758 cp = f->f.sl;
759 do {
760 if (blnkeq && isblnk(*cp)) {
761 if (!isblnk(ipb.chr))
762 return(0);
763 do
764 cp++;
765 while (isblnk(*cp));
766 do
767 scaninp();
768 while (isblnk(ipb.chr));
769 } else if (*cp == ipb.chr) {
770 cp++;
771 scaninp();
772 } else
773 return(0);
774 } while (*cp);
775 break;
776 case T_STR:
777 if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
778 delim = EOF;
779 else
780 delim = f->next->f.sl[0];
781 cp = buf;
782 do {
783 if ((ipb.chr == EOF) | (ipb.chr == '\n'))
784 inword = 0;
785 else if (blnkeq && delim != EOF)
786 inword = isblnk(delim) ?
787 !isblnk(ipb.chr)
788 : ipb.chr != delim;
789 else
790 inword = cp-buf < (f->type & F_WID);
791 if (inword) {
792 *cp++ = ipb.chr;
793 scaninp();
794 }
795 } while (inword && cp < &buf[RMAXWORD]);
796 *cp = '\0';
797 if (f->f.sv->val == NULL)
798 f->f.sv->val = savqstr(buf); /* first setting */
799 else if (strcmp(f->f.sv->val, buf))
800 return(0); /* doesn't match! */
801 break;
802 case T_NUM:
803 if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
804 delim = EOF;
805 else
806 delim = f->next->f.sl[0];
807 np = NULL;
808 cp = buf;
809 do {
810 if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
811 inword = 0;
812 else if (blnkeq && delim != EOF)
813 inword = isblnk(delim) ?
814 !isblnk(ipb.chr)
815 : ipb.chr != delim;
816 else
817 inword = cp-buf < (f->type & F_WID);
818 if (inword) {
819 if (np==NULL && !isblnk(ipb.chr))
820 np = cp;
821 *cp++ = ipb.chr;
822 scaninp();
823 }
824 } while (inword && cp < &buf[RMAXWORD]);
825 *cp = '\0';
826 d = np==NULL ? 0. : atof(np);
827 if (!vardefined(f->f.nv))
828 varset(f->f.nv, '=', d); /* first setting */
829 else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
830 || d < -.001)
831 return(0); /* doesn't match! */
832 break;
833 }
834 return(1); /* success! */
835 }
836
837
838 static void
839 putrec(void) /* output a record */
840 {
841 char fmt[32], typ[16];
842 int n;
843 struct field *f;
844 int adlast, adnext;
845 double dv, av;
846
847 adlast = 0;
848 for (f = outfmt; f != NULL; f = f->next) {
849 adnext = blnkeq &&
850 f->next != NULL &&
851 !( (f->next->type&F_TYP) == T_LIT &&
852 f->next->f.sl[0] == ' ' );
853 switch (f->type & F_TYP) {
854 case T_LIT:
855 fputs(f->f.sl, stdout);
856 adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
857 break;
858 case T_STR:
859 if (f->f.sv->val == NULL) {
860 eputs(f->f.sv->name);
861 eputs(": undefined string\n");
862 quit(1);
863 }
864 n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
865 if (adlast)
866 fputs(f->f.sv->val, stdout);
867 if (!(adlast && adnext))
868 while (n-- > 0)
869 putchar(' ');
870 if (!adlast)
871 fputs(f->f.sv->val, stdout);
872 adlast = 1;
873 break;
874 case T_NUM:
875 n = f->type & F_WID;
876 dv = evalue(f->f.ne);
877 av = fabs(dv);
878 if (n <= 9)
879 strcpy(typ, "g");
880 else
881 sprintf(typ, ".%de", n-5);
882 if (av < 1L<<31) {
883 long iv = (int)(av + .5);
884 if (iv && fabs(av-iv) <= av*1e-14)
885 strcpy(typ, ".0f");
886 }
887 if (adlast && adnext)
888 sprintf(fmt, "%%%s", typ);
889 else if (adlast)
890 sprintf(fmt, "%%-%d%s", n, typ);
891 else
892 sprintf(fmt, "%%%d%s", n, typ);
893 printf(fmt, dv);
894 adlast = 1;
895 break;
896 }
897 }
898 }
899
900
901 static void
902 initinp(FILE *fp) /* prepare lookahead buffer */
903
904 {
905 ipb.fin = fp;
906 ipb.beg = ipb.end = inpbuf;
907 ipb.pos = inpbuf-1; /* position before beginning */
908 ipb.chr = '\0';
909 scaninp();
910 }
911
912
913 static void
914 scaninp(void) /* scan next character */
915 {
916 if (ipb.chr == EOF)
917 return;
918 if (++ipb.pos >= &inpbuf[INBSIZ])
919 ipb.pos = inpbuf;
920 if (ipb.pos == ipb.end) { /* new character */
921 if ((ipb.chr = getc(ipb.fin)) != EOF) {
922 *ipb.end = ipb.chr;
923 if (++ipb.end >= &inpbuf[INBSIZ])
924 ipb.end = inpbuf;
925 if (ipb.end == ipb.beg)
926 ipb.beg = NULL;
927 }
928 } else
929 ipb.chr = *ipb.pos;
930 }
931
932
933 static void
934 skipinp(void) /* rewind position and advance 1 */
935 {
936 if (ipb.beg == NULL) /* can't fully rewind? */
937 ipb.beg = ipb.end;
938 ipb.pos = ipb.beg;
939 ipb.chr = *ipb.pos;
940 if (passive) /* transmit unmatched character? */
941 putchar(ipb.chr);
942 if (++ipb.beg >= &inpbuf[INBSIZ])
943 ipb.beg = inpbuf;
944 scaninp();
945 }
946
947
948 static void
949 advinp(int skip) /* advance home to current position */
950 {
951 if (!skip | (passive >= 0)) {
952 ipb.beg = ipb.pos; /* no need to copy input */
953 return;
954 }
955 if (ipb.beg == NULL) { /* buffer overflowed a bit? */
956 wputs("buffer overflow\n");
957 puts("\n*** MISSING DATA ***");
958 ipb.beg = ipb.end;
959 }
960 while (ipb.beg != ipb.pos) { /* copy buffer to current */
961 putchar(*ipb.beg);
962 if (++ipb.beg >= &inpbuf[INBSIZ])
963 ipb.beg = inpbuf;
964 }
965 }
966
967
968 void
969 eputs(const char *msg)
970 {
971 fputs(msg, stderr);
972 }
973
974
975 void
976 wputs(const char *msg)
977 {
978 if (!nowarn)
979 eputs(msg);
980 }
981
982
983 void
984 quit(int code)
985 {
986 exit(code);
987 }