ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.38
Committed: Fri Mar 10 17:38:01 2023 UTC (13 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4
Changes since 1.37: +2 -1 lines
Log Message:
perf(rcalc): don't bother to reduce constant expressions with -n option

File Contents

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