ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.35
Committed: Sat Mar 12 19:20:11 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.34: +20 -29 lines
Log Message:
refactor(rcalc): Simplified buffer interface a bit

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.35 static const char RCSid[] = "$Id: rcalc.c,v 1.34 2022/03/12 18:14:45 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.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.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.35 if (inpfmt != NULL)
352     advinp(0);
353 greg 1.1 putout();
354 greg 1.21 ++nout;
355 greg 1.32 } else if (inpfmt != NULL) {
356 greg 1.35 advinp(1);
357 greg 1.1 }
358 greg 1.26 if (incnt && nrecs >= incnt)
359     break;
360     if (outcnt && nout >= outcnt)
361     break;
362 greg 1.1 }
363     fclose(fp);
364     }
365    
366    
367 schorsch 1.5 static void
368 greg 1.31 putout(void) /* produce an output record */
369 greg 1.1 {
370    
371     colpos = 0;
372     if (outfmt != NULL)
373     putrec();
374 greg 1.20 else if (otype == 'a')
375     chanout(chanset);
376     else
377 greg 1.3 chanout(bchanset);
378 greg 1.20 if (colpos && otype == 'a')
379 greg 1.1 putchar('\n');
380     if (unbuff)
381     fflush(stdout);
382     }
383    
384 greg 1.10
385     static double
386     l_in(char *funame) /* function call for $channel */
387     {
388 greg 1.31 int n;
389     char *cp;
390 greg 1.10 /* 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 greg 1.20 if (nbicols)
398 greg 1.10 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 greg 1.1
415     double
416 greg 1.31 chanvalue( /* return value for column n */
417     int n
418 schorsch 1.5 )
419 greg 1.1 {
420 greg 1.31 int i;
421     char *cp;
422 greg 1.1
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 greg 1.20 if (nbicols) {
432 greg 1.3 if (n > nbicols)
433     return(0.0);
434 greg 1.29 if ((itype == 'd') | (itype == 'D')) {
435 greg 1.20 cp = inpbuf + (n-1)*sizeof(double);
436     return(*(double *)cp);
437     }
438 greg 1.3 cp = inpbuf + (n-1)*sizeof(float);
439     return(*(float *)cp);
440     }
441 greg 1.1 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 greg 1.31 while (isspace(*cp)) /* some atof()'s don't like tabs */
456 greg 1.1 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 greg 1.3 void
467 greg 1.31 chanset( /* output column n */
468     int n,
469     double v
470 schorsch 1.5 )
471 greg 1.1 {
472 greg 1.31 if (colpos == 0) /* no leading separator */
473 greg 1.1 colpos = 1;
474     while (colpos < n) {
475     putchar(sepchar);
476     colpos++;
477     }
478     printf("%.9g", v);
479 greg 1.3 }
480    
481    
482     void
483 greg 1.31 bchanset( /* output binary channel n */
484     int n,
485     double v
486 schorsch 1.5 )
487 greg 1.3 {
488     static char zerobuf[sizeof(double)];
489 greg 1.29 const int otlen = ((otype == 'd') | (otype == 'D')) ?
490     sizeof(double) : sizeof(float);
491 greg 1.20 float fval = v;
492 greg 1.3
493     while (++colpos < n)
494 greg 1.29 putbinary(zerobuf, otlen, 1, stdout);
495 greg 1.20 switch (otype) {
496     case 'D':
497     swap64((char *)&v, 1);
498     /* fall through */
499     case 'd':
500 greg 1.27 putbinary(&v, sizeof(double), 1, stdout);
501 greg 1.20 break;
502     case 'F':
503     swap32((char *)&fval, 1);
504     /* fall through */
505     case 'f':
506 greg 1.27 putbinary(&fval, sizeof(float), 1, stdout);
507 greg 1.20 break;
508 greg 1.3 }
509 greg 1.1 }
510    
511    
512 schorsch 1.5 static void
513 greg 1.31 readfmt( /* read record format */
514     char *spec,
515     int output
516 schorsch 1.5 )
517 greg 1.1 {
518 greg 1.31 int fd;
519     char *inptr;
520     struct field fmt;
521     int res;
522     struct field *f;
523 greg 1.1 /* check for inline format */
524     for (inptr = spec; *inptr; inptr++)
525     if (*inptr == '$')
526     break;
527 greg 1.31 if (*inptr) /* inline */
528 greg 1.1 inptr = spec;
529 greg 1.31 else { /* from file */
530 greg 1.1 if ((fd = open(spec, 0)) == -1) {
531     eputs(spec);
532     eputs(": cannot open\n");
533     quit(1);
534     }
535 greg 1.14 res = read(fd, inpbuf+2, INBSIZ-2);
536 greg 1.1 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 greg 1.14 (inptr=inpbuf+2)[res] = '\0';
548 greg 1.1 }
549 greg 1.31 f = &fmt; /* get fields */
550 greg 1.1 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 schorsch 1.5 static int
581 greg 1.31 readfield( /* get next field in format */
582     char **pp
583 schorsch 1.5 )
584 greg 1.1 {
585 greg 1.31 int type = F_NUL;
586     int width = 0;
587     char *cp;
588 greg 1.1
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 greg 1.31 getsvar( /* get string variable */
649     char *svname
650 schorsch 1.5 )
651 greg 1.1 {
652 greg 1.31 struct strvar *sv;
653 greg 1.1
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 schorsch 1.5 static void
667 greg 1.31 svpreset( /* preset a string variable */
668     char *eqn
669 schorsch 1.5 )
670 greg 1.1 {
671 greg 1.31 struct strvar *sv;
672     char *val;
673 greg 1.1
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 schorsch 1.5 static void
689     clearrec(void) /* clear input record variables */
690 greg 1.1 {
691 greg 1.31 struct field *f;
692 greg 1.1
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 schorsch 1.5 static int
709 greg 1.32 getrec(void) /* get next record from file */
710 greg 1.1 {
711 greg 1.31 int eatline;
712     struct field *f;
713 greg 1.14
714 greg 1.1 while (ipb.chr != EOF) {
715 greg 1.19 if (blnkeq) { /* beware of nbsynch() */
716 greg 1.1 while (isblnk(ipb.chr))
717 greg 1.31 skipinp();
718 greg 1.19 if (ipb.chr == EOF)
719     return(0);
720     }
721 greg 1.29 eatline = !igneol & (ipb.chr != '\n');
722 greg 1.1 clearrec(); /* start with fresh record */
723     for (f = inpfmt; f != NULL; f = f->next)
724 greg 1.30 if (!getfield(f))
725 greg 1.1 break;
726 greg 1.32 if (f == NULL) /* got one? */
727 greg 1.1 return(1);
728 greg 1.32 skipinp(); /* else eat false start */
729     if (eatline) { /* eat rest of line */
730 greg 1.1 while (ipb.chr != '\n') {
731     if (ipb.chr == EOF)
732     return(0);
733 greg 1.31 skipinp();
734 greg 1.1 }
735 greg 1.31 skipinp();
736 greg 1.1 }
737     }
738     return(0);
739     }
740    
741    
742 schorsch 1.5 static int
743 greg 1.31 getfield( /* get next field */
744     struct field *f
745 schorsch 1.5 )
746 greg 1.1 {
747 greg 1.31 static char buf[RMAXWORD+1]; /* no recursion! */
748     int delim, inword;
749     double d;
750     char *np;
751     char *cp;
752 greg 1.1
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 greg 1.30 return(0);
760 greg 1.1 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 greg 1.30 return(0);
771 greg 1.1 } while (*cp);
772 greg 1.30 break;
773 greg 1.1 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 greg 1.29 if ((ipb.chr == EOF) | (ipb.chr == '\n'))
781 greg 1.1 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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
793 greg 1.1 *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 greg 1.30 return(0); /* doesn't match! */
798     break;
799 greg 1.1 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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
822 greg 1.1 *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 greg 1.30 return(0); /* doesn't match! */
829     break;
830 greg 1.1 }
831 greg 1.30 return(1); /* success! */
832 greg 1.1 }
833    
834    
835 schorsch 1.5 static void
836 greg 1.31 putrec(void) /* output a record */
837 greg 1.1 {
838 greg 1.31 char fmt[32], typ[16];
839     int n;
840     struct field *f;
841     int adlast, adnext;
842     double dv, av;
843 greg 1.1
844     adlast = 0;
845     for (f = outfmt; f != NULL; f = f->next) {
846 greg 1.31 adnext = blnkeq &&
847 greg 1.1 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 greg 1.24 dv = evalue(f->f.ne);
874 greg 1.25 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 greg 1.24 long iv = (int)(av + .5);
881     if (iv && fabs(av-iv) <= av*1e-14)
882     strcpy(typ, ".0f");
883     }
884 greg 1.1 if (adlast && adnext)
885 greg 1.24 sprintf(fmt, "%%%s", typ);
886 greg 1.1 else if (adlast)
887 greg 1.24 sprintf(fmt, "%%-%d%s", n, typ);
888 greg 1.1 else
889 greg 1.24 sprintf(fmt, "%%%d%s", n, typ);
890     printf(fmt, dv);
891 greg 1.1 adlast = 1;
892     break;
893     }
894     }
895     }
896    
897    
898 schorsch 1.5 static void
899 greg 1.31 initinp(FILE *fp) /* prepare lookahead buffer */
900 schorsch 1.5
901 greg 1.1 {
902     ipb.fin = fp;
903     ipb.beg = ipb.end = inpbuf;
904 greg 1.31 ipb.pos = inpbuf-1; /* position before beginning */
905 greg 1.1 ipb.chr = '\0';
906     scaninp();
907     }
908    
909    
910 schorsch 1.5 static void
911 greg 1.31 scaninp(void) /* scan next character */
912 greg 1.1 {
913     if (ipb.chr == EOF)
914     return;
915     if (++ipb.pos >= &inpbuf[INBSIZ])
916     ipb.pos = inpbuf;
917 greg 1.31 if (ipb.pos == ipb.end) { /* new character */
918 greg 1.1 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 schorsch 1.5 static void
931 greg 1.35 skipinp(void) /* rewind position and advance 1 */
932 greg 1.1 {
933 greg 1.35 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 greg 1.1 }
943    
944    
945 schorsch 1.5 static void
946 greg 1.35 advinp(int skip) /* advance home to current position */
947 greg 1.32 {
948 greg 1.35 if (!skip | (passive >= 0)) {
949     ipb.beg = ipb.pos; /* no need to copy input */
950 greg 1.32 return;
951     }
952 greg 1.35 if (ipb.beg == NULL) /* buffer overflowed a bit? */
953 greg 1.34 ipb.beg = ipb.end;
954 greg 1.35 while (ipb.beg != ipb.pos) { /* copy buffer to current */
955 greg 1.32 putchar(*ipb.beg);
956     if (++ipb.beg >= &inpbuf[INBSIZ])
957     ipb.beg = inpbuf;
958     }
959     }
960    
961    
962 greg 1.1 void
963 greg 1.31 eputs(char *msg)
964 greg 1.1 {
965     fputs(msg, stderr);
966     }
967    
968    
969     void
970 greg 1.31 wputs(char *msg)
971 greg 1.1 {
972     if (!nowarn)
973     eputs(msg);
974     }
975    
976    
977     void
978 greg 1.31 quit(int code)
979 greg 1.1 {
980     exit(code);
981     }