ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.33
Committed: Sat Mar 12 15:50:13 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.32: +18 -10 lines
Log Message:
feat(rcalc): Added check for "cond" variable defined as constant

File Contents

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