ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.32
Committed: Fri Mar 11 22:50:13 2022 UTC (2 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.31: +54 -29 lines
Log Message:
feat(rcalc): Added -P option to pass records where cond evaluates <= 0

File Contents

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