ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.37
Committed: Mon Feb 6 22:40:21 2023 UTC (14 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.36: +3 -3 lines
Log Message:
refactor: Changed some char* args to const char* to avoid warnings

File Contents

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