ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.30
Committed: Tue Dec 10 19:00:26 2019 UTC (4 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 1.29: +10 -10 lines
Log Message:
Minor logic improvement -- should not affect behavior

File Contents

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