ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.34
Committed: Sat Mar 12 18:14:45 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.33: +6 -4 lines
Log Message:
fix(rcalc): Slight improvement for buffer overflow in -P mode

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.34 static const char RCSid[] = "$Id: rcalc.c,v 1.33 2022/03/12 15:50:13 greg Exp $";
3 greg 1.1 #endif
4     /*
5 greg 1.31 * rcalc.c - record calculator program.
6 greg 1.1 *
7 greg 1.31 * 9/11/87
8 greg 1.1 */
9    
10 greg 1.31 #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 greg 1.1
20 greg 1.31 #define isnum(c) (isdigit(c) || ((c)=='-') | ((c)=='.') \
21 greg 1.29 | ((c)=='+') | ((c)=='e') | ((c)=='E'))
22 greg 1.1
23 greg 1.31 #define isblnk(c) (igneol ? isspace(c) : ((c)==' ')|((c)=='\t'))
24 greg 1.1
25 greg 1.31 #define INBSIZ 16384 /* longest record */
26     #define MAXCOL 32 /* number of columns recorded */
27 greg 1.1
28     /* field type specifications */
29 greg 1.31 #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 greg 1.1 };
42    
43 greg 1.31 struct field { /* record format structure */
44     int type; /* type of field (& width) */
45 greg 1.1 union {
46 greg 1.31 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 greg 1.1 };
53    
54 greg 1.31 #define savqstr(s) strcpy(emalloc(strlen(s)+1),s)
55     #define freqstr(s) efree(s)
56 greg 1.1
57 greg 1.10 static int getinputrec(FILE *fp);
58 greg 1.32 static void scaninp(void), advinp(void), passinp(void), skipinp(void);
59 schorsch 1.5 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 greg 1.10 static double l_in(char *);
71 greg 1.1
72 greg 1.32 struct field *inpfmt = NULL; /* input record format */
73     struct field *outfmt = NULL; /* output record structure */
74     struct strvar *svhead = NULL; /* string variables */
75 greg 1.31
76 greg 1.32 long incnt = 0; /* limit number of input records? */
77 greg 1.31 long outcnt = 0; /* limit number of output records? */
78    
79 greg 1.32 int blnkeq = 1; /* blanks compare equal? */
80     int igneol = 0; /* ignore end of line? */
81 greg 1.31 int passive = 0; /* passive mode (transmit unmatched input) */
82 greg 1.32 char sepchar = '\t'; /* input/output separator */
83     int noinput = 0; /* no input records? */
84 greg 1.31 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 greg 1.32 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 greg 1.1
92 greg 1.32 int nowarn = 0; /* non-fatal diagnostic output */
93     int unbuff = 0; /* unbuffered output (flush each record) */
94 greg 1.1
95     struct {
96 greg 1.31 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 greg 1.1
103    
104 schorsch 1.5 int
105     main(
106 greg 1.31 int argc,
107     char *argv[]
108 schorsch 1.5 )
109 greg 1.1 {
110 greg 1.31 char *fpath;
111     int i;
112 greg 1.1
113 greg 1.2 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
114     esupport &= ~(E_REDEFW);
115 greg 1.1
116 greg 1.31 #ifdef BIGGERLIB
117 greg 1.1 biggerlib();
118     #endif
119     varset("PI", ':', 3.14159265358979323846);
120 greg 1.10 funset("in", 1, '=', &l_in);
121 greg 1.1
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 greg 1.13 case 'p':
131 greg 1.32 passive = 1;
132     break;
133     case 'P':
134     passive = -1;
135 greg 1.13 break;
136 greg 1.1 case 't':
137     sepchar = argv[i][2];
138     break;
139     case 's':
140     svpreset(argv[++i]);
141     break;
142     case 'f':
143 greg 1.22 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 greg 1.1 break;
153     case 'e':
154     scompile(argv[++i], NULL, 0);
155     break;
156     case 'n':
157     noinput = 1;
158     break;
159     case 'i':
160 greg 1.3 switch (argv[i][2]) {
161     case '\0':
162 greg 1.20 itype = 'a';
163 greg 1.3 nbicols = 0;
164     readfmt(argv[++i], 0);
165     break;
166 greg 1.26 case 'n':
167     incnt = atol(argv[++i]);
168     break;
169 greg 1.3 case 'a':
170 greg 1.20 itype = 'a';
171 greg 1.3 nbicols = 0;
172     break;
173     case 'd':
174 greg 1.20 case 'D':
175     itype = argv[i][2];
176 greg 1.3 if (isdigit(argv[i][3]))
177     nbicols = atoi(argv[i]+3);
178     else
179     nbicols = 1;
180 greg 1.9 if (nbicols*sizeof(double) > INBSIZ) {
181     eputs(argv[0]);
182     eputs(": too many input columns\n");
183     quit(1);
184     }
185 greg 1.3 break;
186     case 'f':
187 greg 1.20 case 'F':
188     itype = argv[i][2];
189 greg 1.3 if (isdigit(argv[i][3]))
190 greg 1.20 nbicols = atoi(argv[i]+3);
191 greg 1.3 else
192 greg 1.20 nbicols = 1;
193     if (nbicols*sizeof(float) > INBSIZ) {
194 greg 1.9 eputs(argv[0]);
195     eputs(": too many input columns\n");
196     quit(1);
197     }
198 greg 1.3 break;
199     default:
200     goto userr;
201     }
202 greg 1.1 break;
203     case 'o':
204 greg 1.3 switch (argv[i][2]) {
205     case '\0':
206 greg 1.20 otype = 'a';
207 greg 1.3 readfmt(argv[++i], 1);
208     break;
209 greg 1.26 case 'n':
210     outcnt = atol(argv[++i]);
211     break;
212 greg 1.3 case 'a':
213 greg 1.20 otype = 'a';
214 greg 1.3 break;
215     case 'd':
216 greg 1.20 case 'D':
217 greg 1.3 case 'f':
218 greg 1.20 case 'F':
219     otype = argv[i][2];
220 greg 1.3 break;
221 greg 1.18 default:
222     goto userr;
223 greg 1.3 }
224 greg 1.1 break;
225     case 'w':
226     nowarn = !nowarn;
227     break;
228     case 'u':
229     unbuff = !unbuff;
230     break;
231 greg 1.3 default:;
232     userr:
233 greg 1.1 eputs("Usage: ");
234     eputs(argv[0]);
235 greg 1.32 eputs(" [-b][-l][-n][-p|-P][-w][-u][-tS][-s svar=sval][-e expr][-f source][-i infmt][-o outfmt] [file]\n");
236 greg 1.1 quit(1);
237     }
238 greg 1.20 if (otype != 'a')
239 greg 1.18 SET_FILE_BINARY(stdout);
240 greg 1.23 #ifdef getc_unlocked /* avoid lock/unlock overhead */
241     flockfile(stdout);
242     #endif
243 greg 1.31 if (noinput) { /* produce a single output record */
244 greg 1.17 if (i < argc) {
245     eputs(argv[0]);
246     eputs(": file argument(s) incompatible with -n\n");
247     quit(1);
248     }
249 greg 1.1 eclock++;
250     putout();
251     quit(0);
252     }
253 greg 1.32 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 greg 1.31 if (blnkeq) /* for efficiency */
259 greg 1.1 nbsynch();
260    
261 greg 1.31 if (i == argc) /* from stdin */
262 greg 1.1 execute(NULL);
263 greg 1.31 else /* from one or more files */
264 greg 1.1 for ( ; i < argc; i++)
265     execute(argv[i]);
266    
267     quit(0);
268 schorsch 1.11 return 0; /* pro forma return */
269 greg 1.1 }
270    
271    
272 schorsch 1.5 static void
273 greg 1.31 nbsynch(void) /* non-blank starting synch character */
274 greg 1.1 {
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 greg 1.10 static int
285 schorsch 1.5 getinputrec( /* get next input record */
286 greg 1.31 FILE *fp
287 schorsch 1.5 )
288 greg 1.3 {
289 greg 1.29 if ((itype == 'd') | (itype == 'D')) {
290 greg 1.27 if (getbinary(inpbuf, sizeof(double), nbicols, fp) != nbicols)
291 greg 1.20 return(0);
292     if (itype == 'D')
293     swap64(inpbuf, nbicols);
294     return(1);
295     }
296 greg 1.29 if ((itype == 'f') | (itype == 'F')) {
297 greg 1.27 if (getbinary(inpbuf, sizeof(float), nbicols, fp) != nbicols)
298 greg 1.20 return(0);
299     if (itype == 'F')
300     swap32(inpbuf, nbicols);
301     return(1);
302     }
303 greg 1.3 return(fgets(inpbuf, INBSIZ, fp) != NULL);
304     }
305    
306    
307 schorsch 1.5 static void
308 greg 1.31 execute( /* process a file */
309     char *file
310 schorsch 1.5 )
311 greg 1.1 {
312 greg 1.33 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 greg 1.1
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 greg 1.23 if (itype != 'a')
330     SET_FILE_BINARY(fp);
331     #ifdef getc_unlocked /* avoid lock/unlock overhead */
332     flockfile(fp);
333     #endif
334 greg 1.33 if (conditional == ':') {
335     eputs(condVN);
336     eputs(": defined as constant\n");
337     quit(1);
338     }
339 greg 1.1 if (inpfmt != NULL)
340     initinp(fp);
341 greg 1.3
342 greg 1.32 while (inpfmt != NULL ? getrec() : getinputrec(fp)) {
343 greg 1.28 ++nrecs;
344     if (set_recno)
345 greg 1.33 varset(recnoVN, '=', (double)nrecs);
346 greg 1.28 if (set_outno)
347 greg 1.33 varset(outnoVN, '=', (double)(nout+1));
348 greg 1.1 colflg = 0;
349     eclock++;
350 greg 1.33 if (!conditional || varvalue(condVN) > 0.0) {
351 greg 1.1 putout();
352 greg 1.21 ++nout;
353 greg 1.32 advinp();
354     } else if (inpfmt != NULL) {
355     if (passive < 0)
356     passinp();
357     else
358     advinp();
359 greg 1.1 }
360 greg 1.26 if (incnt && nrecs >= incnt)
361     break;
362     if (outcnt && nout >= outcnt)
363     break;
364 greg 1.1 }
365     fclose(fp);
366     }
367    
368    
369 schorsch 1.5 static void
370 greg 1.31 putout(void) /* produce an output record */
371 greg 1.1 {
372    
373     colpos = 0;
374     if (outfmt != NULL)
375     putrec();
376 greg 1.20 else if (otype == 'a')
377     chanout(chanset);
378     else
379 greg 1.3 chanout(bchanset);
380 greg 1.20 if (colpos && otype == 'a')
381 greg 1.1 putchar('\n');
382     if (unbuff)
383     fflush(stdout);
384     }
385    
386 greg 1.10
387     static double
388     l_in(char *funame) /* function call for $channel */
389     {
390 greg 1.31 int n;
391     char *cp;
392 greg 1.10 /* 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 greg 1.20 if (nbicols)
400 greg 1.10 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 greg 1.1
417     double
418 greg 1.31 chanvalue( /* return value for column n */
419     int n
420 schorsch 1.5 )
421 greg 1.1 {
422 greg 1.31 int i;
423     char *cp;
424 greg 1.1
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 greg 1.20 if (nbicols) {
434 greg 1.3 if (n > nbicols)
435     return(0.0);
436 greg 1.29 if ((itype == 'd') | (itype == 'D')) {
437 greg 1.20 cp = inpbuf + (n-1)*sizeof(double);
438     return(*(double *)cp);
439     }
440 greg 1.3 cp = inpbuf + (n-1)*sizeof(float);
441     return(*(float *)cp);
442     }
443 greg 1.1 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 greg 1.31 while (isspace(*cp)) /* some atof()'s don't like tabs */
458 greg 1.1 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 greg 1.3 void
469 greg 1.31 chanset( /* output column n */
470     int n,
471     double v
472 schorsch 1.5 )
473 greg 1.1 {
474 greg 1.31 if (colpos == 0) /* no leading separator */
475 greg 1.1 colpos = 1;
476     while (colpos < n) {
477     putchar(sepchar);
478     colpos++;
479     }
480     printf("%.9g", v);
481 greg 1.3 }
482    
483    
484     void
485 greg 1.31 bchanset( /* output binary channel n */
486     int n,
487     double v
488 schorsch 1.5 )
489 greg 1.3 {
490     static char zerobuf[sizeof(double)];
491 greg 1.29 const int otlen = ((otype == 'd') | (otype == 'D')) ?
492     sizeof(double) : sizeof(float);
493 greg 1.20 float fval = v;
494 greg 1.3
495     while (++colpos < n)
496 greg 1.29 putbinary(zerobuf, otlen, 1, stdout);
497 greg 1.20 switch (otype) {
498     case 'D':
499     swap64((char *)&v, 1);
500     /* fall through */
501     case 'd':
502 greg 1.27 putbinary(&v, sizeof(double), 1, stdout);
503 greg 1.20 break;
504     case 'F':
505     swap32((char *)&fval, 1);
506     /* fall through */
507     case 'f':
508 greg 1.27 putbinary(&fval, sizeof(float), 1, stdout);
509 greg 1.20 break;
510 greg 1.3 }
511 greg 1.1 }
512    
513    
514 schorsch 1.5 static void
515 greg 1.31 readfmt( /* read record format */
516     char *spec,
517     int output
518 schorsch 1.5 )
519 greg 1.1 {
520 greg 1.31 int fd;
521     char *inptr;
522     struct field fmt;
523     int res;
524     struct field *f;
525 greg 1.1 /* check for inline format */
526     for (inptr = spec; *inptr; inptr++)
527     if (*inptr == '$')
528     break;
529 greg 1.31 if (*inptr) /* inline */
530 greg 1.1 inptr = spec;
531 greg 1.31 else { /* from file */
532 greg 1.1 if ((fd = open(spec, 0)) == -1) {
533     eputs(spec);
534     eputs(": cannot open\n");
535     quit(1);
536     }
537 greg 1.14 res = read(fd, inpbuf+2, INBSIZ-2);
538 greg 1.1 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 greg 1.14 (inptr=inpbuf+2)[res] = '\0';
550 greg 1.1 }
551 greg 1.31 f = &fmt; /* get fields */
552 greg 1.1 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 schorsch 1.5 static int
583 greg 1.31 readfield( /* get next field in format */
584     char **pp
585 schorsch 1.5 )
586 greg 1.1 {
587 greg 1.31 int type = F_NUL;
588     int width = 0;
589     char *cp;
590 greg 1.1
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 greg 1.31 getsvar( /* get string variable */
651     char *svname
652 schorsch 1.5 )
653 greg 1.1 {
654 greg 1.31 struct strvar *sv;
655 greg 1.1
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 schorsch 1.5 static void
669 greg 1.31 svpreset( /* preset a string variable */
670     char *eqn
671 schorsch 1.5 )
672 greg 1.1 {
673 greg 1.31 struct strvar *sv;
674     char *val;
675 greg 1.1
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 schorsch 1.5 static void
691     clearrec(void) /* clear input record variables */
692 greg 1.1 {
693 greg 1.31 struct field *f;
694 greg 1.1
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 schorsch 1.5 static int
711 greg 1.32 getrec(void) /* get next record from file */
712 greg 1.1 {
713 greg 1.31 int eatline;
714     struct field *f;
715 greg 1.14
716 greg 1.1 while (ipb.chr != EOF) {
717 greg 1.19 if (blnkeq) { /* beware of nbsynch() */
718 greg 1.1 while (isblnk(ipb.chr))
719 greg 1.31 skipinp();
720 greg 1.19 if (ipb.chr == EOF)
721     return(0);
722     }
723 greg 1.29 eatline = !igneol & (ipb.chr != '\n');
724 greg 1.1 clearrec(); /* start with fresh record */
725     for (f = inpfmt; f != NULL; f = f->next)
726 greg 1.30 if (!getfield(f))
727 greg 1.1 break;
728 greg 1.32 if (f == NULL) /* got one? */
729 greg 1.1 return(1);
730 greg 1.32 skipinp(); /* else eat false start */
731     if (eatline) { /* eat rest of line */
732 greg 1.1 while (ipb.chr != '\n') {
733     if (ipb.chr == EOF)
734     return(0);
735 greg 1.31 skipinp();
736 greg 1.1 }
737 greg 1.31 skipinp();
738 greg 1.1 }
739     }
740     return(0);
741     }
742    
743    
744 schorsch 1.5 static int
745 greg 1.31 getfield( /* get next field */
746     struct field *f
747 schorsch 1.5 )
748 greg 1.1 {
749 greg 1.31 static char buf[RMAXWORD+1]; /* no recursion! */
750     int delim, inword;
751     double d;
752     char *np;
753     char *cp;
754 greg 1.1
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 greg 1.30 return(0);
762 greg 1.1 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 greg 1.30 return(0);
773 greg 1.1 } while (*cp);
774 greg 1.30 break;
775 greg 1.1 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 greg 1.29 if ((ipb.chr == EOF) | (ipb.chr == '\n'))
783 greg 1.1 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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
795 greg 1.1 *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 greg 1.30 return(0); /* doesn't match! */
800     break;
801 greg 1.1 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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
824 greg 1.1 *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 greg 1.30 return(0); /* doesn't match! */
831     break;
832 greg 1.1 }
833 greg 1.30 return(1); /* success! */
834 greg 1.1 }
835    
836    
837 schorsch 1.5 static void
838 greg 1.31 putrec(void) /* output a record */
839 greg 1.1 {
840 greg 1.31 char fmt[32], typ[16];
841     int n;
842     struct field *f;
843     int adlast, adnext;
844     double dv, av;
845 greg 1.1
846     adlast = 0;
847     for (f = outfmt; f != NULL; f = f->next) {
848 greg 1.31 adnext = blnkeq &&
849 greg 1.1 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 greg 1.24 dv = evalue(f->f.ne);
876 greg 1.25 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 greg 1.24 long iv = (int)(av + .5);
883     if (iv && fabs(av-iv) <= av*1e-14)
884     strcpy(typ, ".0f");
885     }
886 greg 1.1 if (adlast && adnext)
887 greg 1.24 sprintf(fmt, "%%%s", typ);
888 greg 1.1 else if (adlast)
889 greg 1.24 sprintf(fmt, "%%-%d%s", n, typ);
890 greg 1.1 else
891 greg 1.24 sprintf(fmt, "%%%d%s", n, typ);
892     printf(fmt, dv);
893 greg 1.1 adlast = 1;
894     break;
895     }
896     }
897     }
898    
899    
900 schorsch 1.5 static void
901 greg 1.31 initinp(FILE *fp) /* prepare lookahead buffer */
902 schorsch 1.5
903 greg 1.1 {
904     ipb.fin = fp;
905     ipb.beg = ipb.end = inpbuf;
906 greg 1.31 ipb.pos = inpbuf-1; /* position before beginning */
907 greg 1.1 ipb.chr = '\0';
908     scaninp();
909     }
910    
911    
912 schorsch 1.5 static void
913 greg 1.31 scaninp(void) /* scan next character */
914 greg 1.1 {
915     if (ipb.chr == EOF)
916     return;
917     if (++ipb.pos >= &inpbuf[INBSIZ])
918     ipb.pos = inpbuf;
919 greg 1.31 if (ipb.pos == ipb.end) { /* new character */
920 greg 1.1 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 schorsch 1.5 static void
933 greg 1.31 advinp(void) /* move home to current position */
934 greg 1.1 {
935     ipb.beg = ipb.pos;
936     }
937    
938    
939 schorsch 1.5 static void
940 greg 1.32 passinp(void) /* pass beginning to current position */
941     {
942 greg 1.34 if (!passive) {
943     advinp(); /* mistake to call us */
944 greg 1.32 return;
945     }
946 greg 1.34 if (ipb.beg == NULL) /* buffer overflowed a bit */
947     ipb.beg = ipb.end;
948 greg 1.32 while (ipb.beg != ipb.pos) { /* transfer buffer unaltered */
949     putchar(*ipb.beg);
950     if (++ipb.beg >= &inpbuf[INBSIZ])
951     ipb.beg = inpbuf;
952     }
953     }
954    
955    
956     static void
957     skipinp(void) /* rewind position and advance 1 */
958 greg 1.1 {
959 greg 1.34 if (ipb.beg == NULL) /* overflow - can't fully rewind */
960 greg 1.1 ipb.beg = ipb.end;
961     ipb.pos = ipb.beg;
962     ipb.chr = *ipb.pos;
963 greg 1.13 if (passive) /* transmit unmatched character? */
964 greg 1.31 putchar(ipb.chr);
965 greg 1.1 if (++ipb.beg >= &inpbuf[INBSIZ])
966     ipb.beg = inpbuf;
967     scaninp();
968     }
969    
970    
971     void
972 greg 1.31 eputs(char *msg)
973 greg 1.1 {
974     fputs(msg, stderr);
975     }
976    
977    
978     void
979 greg 1.31 wputs(char *msg)
980 greg 1.1 {
981     if (!nowarn)
982     eputs(msg);
983     }
984    
985    
986     void
987 greg 1.31 quit(int code)
988 greg 1.1 {
989     exit(code);
990     }