ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.39
Committed: Fri Feb 23 03:47:57 2024 UTC (2 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.38: +3 -1 lines
Log Message:
perf: Added array index optimization to calcomp routines

File Contents

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