ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.14
Committed: Mon Oct 11 10:02:15 2004 UTC (19 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 1.13: +4 -4 lines
Log Message:
Fixed bug in format parsing where extra EOL was sometimes added

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rcalc.c,v 1.13 2004/06/09 16:00:13 greg Exp $";
3 #endif
4 /*
5 * rcalc.c - record calculator program.
6 *
7 * 9/11/87
8 */
9
10 #include <stdlib.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <math.h>
15 #include <ctype.h>
16
17 #include "platform.h"
18 #include "rterror.h"
19 #include "rtmisc.h"
20 #include "rtio.h"
21 #include "calcomp.h"
22
23 #define isnum(c) (isdigit(c) || (c)=='-' || (c)=='.' \
24 || (c)=='+' || (c)=='e' || (c)=='E')
25
26 #define isblnk(c) (igneol ? isspace(c) : (c)==' '||(c)=='\t')
27
28 #define INBSIZ 4096 /* longest record */
29 #define MAXCOL 32 /* number of columns recorded */
30
31 /* field type specifications */
32 #define F_NUL 0 /* empty */
33 #define F_TYP 0x7000 /* mask for type */
34 #define F_WID 0x0fff /* mask for width */
35 #define T_LIT 0x1000 /* string literal */
36 #define T_STR 0x2000 /* string variable */
37 #define T_NUM 0x3000 /* numeric value */
38
39 struct strvar { /* string variable */
40 char *name;
41 char *val;
42 char *preset;
43 struct strvar *next;
44 };
45
46 struct field { /* record format structure */
47 int type; /* type of field (& width) */
48 union {
49 char *sl; /* string literal */
50 struct strvar *sv; /* string variable */
51 char *nv; /* numeric variable */
52 EPNODE *ne; /* numeric expression */
53 } f; /* field contents */
54 struct field *next; /* next field in record */
55 };
56
57 #define savqstr(s) strcpy(emalloc(strlen(s)+1),s)
58 #define freqstr(s) efree(s)
59
60 static int getinputrec(FILE *fp);
61 static void scaninp(void), advinp(void), resetinp(void);
62 static void putrec(void), putout(void), nbsynch(void);
63 static int getrec(void);
64 static void execute(char *file);
65 static void initinp(FILE *fp);
66 static void svpreset(char *eqn);
67 static void readfmt(char *spec, int output);
68 static int readfield(char **pp);
69 static int getfield(struct field *f);
70 static void chanset(int n, double v);
71 static void bchanset(int n, double v);
72 static struct strvar* getsvar(char *svname);
73 static double l_in(char *);
74
75 struct field *inpfmt = NULL; /* input record format */
76 struct field *outfmt = NULL; /* output record structure */
77 struct strvar *svhead = NULL; /* string variables */
78
79 int blnkeq = 1; /* blanks compare equal? */
80 int igneol = 0; /* ignore end of line? */
81 int passive = 0; /* passive mode (transmit unmatched input) */
82 char sepchar = '\t'; /* input/output separator */
83 int noinput = 0; /* no input records? */
84 int nbicols = 0; /* number of binary input columns */
85 int bocols = 0; /* produce binary output columns */
86 char inpbuf[INBSIZ]; /* input buffer */
87 double colval[MAXCOL]; /* input column values */
88 unsigned long colflg = 0; /* column retrieved flags */
89 int colpos; /* output column position */
90
91 int nowarn = 0; /* non-fatal diagnostic output */
92 int unbuff = 0; /* unbuffered output (flush each record) */
93
94 struct {
95 FILE *fin; /* input file */
96 int chr; /* next character */
97 char *beg; /* home position */
98 char *pos; /* scan position */
99 char *end; /* read position */
100 } ipb; /* circular lookahead buffer */
101
102
103 int
104 main(
105 int argc,
106 char *argv[]
107 )
108 {
109 int i;
110
111 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
112 esupport &= ~(E_REDEFW);
113
114 #ifdef BIGGERLIB
115 biggerlib();
116 #endif
117 varset("PI", ':', 3.14159265358979323846);
118 funset("in", 1, '=', &l_in);
119
120 for (i = 1; i < argc && argv[i][0] == '-'; i++)
121 switch (argv[i][1]) {
122 case 'b':
123 blnkeq = !blnkeq;
124 break;
125 case 'l':
126 igneol = !igneol;
127 break;
128 case 'p':
129 passive = !passive;
130 break;
131 case 't':
132 sepchar = argv[i][2];
133 break;
134 case 's':
135 svpreset(argv[++i]);
136 break;
137 case 'f':
138 fcompile(argv[++i]);
139 break;
140 case 'e':
141 scompile(argv[++i], NULL, 0);
142 break;
143 case 'n':
144 noinput = 1;
145 break;
146 case 'i':
147 switch (argv[i][2]) {
148 case '\0':
149 nbicols = 0;
150 readfmt(argv[++i], 0);
151 break;
152 case 'a':
153 nbicols = 0;
154 break;
155 case 'd':
156 if (isdigit(argv[i][3]))
157 nbicols = atoi(argv[i]+3);
158 else
159 nbicols = 1;
160 if (nbicols*sizeof(double) > INBSIZ) {
161 eputs(argv[0]);
162 eputs(": too many input columns\n");
163 quit(1);
164 }
165 break;
166 case 'f':
167 if (isdigit(argv[i][3]))
168 nbicols = -atoi(argv[i]+3);
169 else
170 nbicols = -1;
171 if (-nbicols*sizeof(float) > INBSIZ) {
172 eputs(argv[0]);
173 eputs(": too many input columns\n");
174 quit(1);
175 }
176 break;
177 default:
178 goto userr;
179 }
180 break;
181 case 'o':
182 switch (argv[i][2]) {
183 case '\0':
184 bocols = 0;
185 readfmt(argv[++i], 1);
186 break;
187 case 'a':
188 bocols = 0;
189 break;
190 case 'd':
191 bocols = 1;
192 break;
193 case 'f':
194 bocols = -1;
195 break;
196 }
197 break;
198 case 'w':
199 nowarn = !nowarn;
200 break;
201 case 'u':
202 unbuff = !unbuff;
203 break;
204 default:;
205 userr:
206 eputs("Usage: ");
207 eputs(argv[0]);
208 eputs(" [-b][-l][-n][-p][-w][-u][-tS][-s svar=sval][-e expr][-f source][-i infmt][-o outfmt] [file]\n");
209 quit(1);
210 }
211
212 if (noinput) { /* produce a single output record */
213 eclock++;
214 putout();
215 quit(0);
216 }
217
218 if (blnkeq) /* for efficiency */
219 nbsynch();
220
221 if (i == argc) /* from stdin */
222 execute(NULL);
223 else /* from one or more files */
224 for ( ; i < argc; i++)
225 execute(argv[i]);
226
227 quit(0);
228 return 0; /* pro forma return */
229 }
230
231
232 static void
233 nbsynch(void) /* non-blank starting synch character */
234 {
235 if (inpfmt == NULL || (inpfmt->type & F_TYP) != T_LIT)
236 return;
237 while (isblnk(*inpfmt->f.sl))
238 inpfmt->f.sl++;
239 if (!*inpfmt->f.sl)
240 inpfmt = inpfmt->next;
241 }
242
243
244 static int
245 getinputrec( /* get next input record */
246 FILE *fp
247 )
248 {
249 if (inpfmt != NULL)
250 return(getrec());
251 if (nbicols > 0)
252 return(fread(inpbuf, sizeof(double),
253 nbicols, fp) == nbicols);
254 if (nbicols < 0)
255 return(fread(inpbuf, sizeof(float),
256 -nbicols, fp) == -nbicols);
257 return(fgets(inpbuf, INBSIZ, fp) != NULL);
258 }
259
260
261 static void
262 execute( /* process a file */
263 char *file
264 )
265 {
266 int conditional = vardefined("cond");
267 long nrecs = 0;
268 long nout = 0;
269 FILE *fp;
270
271 if (file == NULL)
272 fp = stdin;
273 else if ((fp = fopen(file, "r")) == NULL) {
274 eputs(file);
275 eputs(": cannot open\n");
276 quit(1);
277 }
278 if (inpfmt != NULL)
279 initinp(fp);
280
281 while (getinputrec(fp)) {
282 varset("recno", '=', (double)++nrecs);
283 colflg = 0;
284 eclock++;
285 if (!conditional || varvalue("cond") > 0.0) {
286 varset("outno", '=', (double)++nout);
287 putout();
288 }
289 }
290 fclose(fp);
291 }
292
293
294 static void
295 putout(void) /* produce an output record */
296 {
297
298 colpos = 0;
299 if (outfmt != NULL)
300 putrec();
301 else if (bocols)
302 chanout(bchanset);
303 else
304 chanout(chanset);
305 if (colpos && !bocols)
306 putchar('\n');
307 if (unbuff)
308 fflush(stdout);
309 }
310
311
312 static double
313 l_in(char *funame) /* function call for $channel */
314 {
315 int n;
316 register char *cp;
317 /* get argument as integer */
318 n = (int)(argument(1) + .5);
319 if (n != 0) /* return channel value */
320 return(chanvalue(n));
321 /* determine number of channels */
322 if (noinput || inpfmt != NULL)
323 return(0);
324 if (nbicols > 0)
325 return(nbicols);
326 if (nbicols < 0)
327 return(-nbicols);
328 cp = inpbuf; /* need to count */
329 for (n = 0; *cp; )
330 if (blnkeq && isspace(sepchar)) {
331 while (isspace(*cp))
332 cp++;
333 n += *cp != '\0';
334 while (*cp && !isspace(*cp))
335 cp++;
336 } else {
337 n += *cp != '\n';
338 while (*cp && *cp++ != sepchar)
339 ;
340 }
341 return(n);
342 }
343
344 double
345 chanvalue( /* return value for column n */
346 int n
347 )
348 {
349 int i;
350 register char *cp;
351
352 if (noinput || inpfmt != NULL) {
353 eputs("no column input\n");
354 quit(1);
355 }
356 if (n < 1) {
357 eputs("illegal channel number\n");
358 quit(1);
359 }
360 if (nbicols > 0) {
361 if (n > nbicols)
362 return(0.0);
363 cp = inpbuf + (n-1)*sizeof(double);
364 return(*(double *)cp);
365 }
366 if (nbicols < 0) {
367 if (n > -nbicols)
368 return(0.0);
369 cp = inpbuf + (n-1)*sizeof(float);
370 return(*(float *)cp);
371 }
372 if (n <= MAXCOL && colflg & 1L<<(n-1))
373 return(colval[n-1]);
374
375 cp = inpbuf;
376 for (i = 1; i < n; i++)
377 if (blnkeq && isspace(sepchar)) {
378 while (isspace(*cp))
379 cp++;
380 while (*cp && !isspace(*cp))
381 cp++;
382 } else
383 while (*cp && *cp++ != sepchar)
384 ;
385
386 while (isspace(*cp)) /* some atof()'s don't like tabs */
387 cp++;
388
389 if (n <= MAXCOL) {
390 colflg |= 1L<<(n-1);
391 return(colval[n-1] = atof(cp));
392 } else
393 return(atof(cp));
394 }
395
396
397 void
398 chanset( /* output column n */
399 int n,
400 double v
401 )
402 {
403 if (colpos == 0) /* no leading separator */
404 colpos = 1;
405 while (colpos < n) {
406 putchar(sepchar);
407 colpos++;
408 }
409 printf("%.9g", v);
410 }
411
412
413 void
414 bchanset( /* output binary channel n */
415 int n,
416 double v
417 )
418 {
419 static char zerobuf[sizeof(double)];
420
421 while (++colpos < n)
422 fwrite(zerobuf,
423 bocols>0 ? sizeof(double) : sizeof(float),
424 1, stdout);
425 if (bocols > 0)
426 fwrite(&v, sizeof(double), 1, stdout);
427 else {
428 float fval = v;
429 fwrite(&fval, sizeof(float), 1, stdout);
430 }
431 }
432
433
434 static void
435 readfmt( /* read record format */
436 char *spec,
437 int output
438 )
439 {
440 int fd;
441 char *inptr;
442 struct field fmt;
443 int res;
444 register struct field *f;
445 /* check for inline format */
446 for (inptr = spec; *inptr; inptr++)
447 if (*inptr == '$')
448 break;
449 if (*inptr) /* inline */
450 inptr = spec;
451 else { /* from file */
452 if ((fd = open(spec, 0)) == -1) {
453 eputs(spec);
454 eputs(": cannot open\n");
455 quit(1);
456 }
457 res = read(fd, inpbuf+2, INBSIZ-2);
458 if (res <= 0 || res >= INBSIZ-1) {
459 eputs(spec);
460 if (res < 0)
461 eputs(": read error\n");
462 else if (res == 0)
463 eputs(": empty file\n");
464 else if (res >= INBSIZ-1)
465 eputs(": format too long\n");
466 quit(1);
467 }
468 close(fd);
469 (inptr=inpbuf+2)[res] = '\0';
470 }
471 f = &fmt; /* get fields */
472 while ((res = readfield(&inptr)) != F_NUL) {
473 f->next = (struct field *)emalloc(sizeof(struct field));
474 f = f->next;
475 f->type = res;
476 switch (res & F_TYP) {
477 case T_LIT:
478 f->f.sl = savqstr(inpbuf);
479 break;
480 case T_STR:
481 f->f.sv = getsvar(inpbuf);
482 break;
483 case T_NUM:
484 if (output)
485 f->f.ne = eparse(inpbuf);
486 else
487 f->f.nv = savestr(inpbuf);
488 break;
489 }
490 /* add final newline if necessary */
491 if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
492 inptr = "\n";
493 }
494 f->next = NULL;
495 if (output)
496 outfmt = fmt.next;
497 else
498 inpfmt = fmt.next;
499 }
500
501
502 static int
503 readfield( /* get next field in format */
504 register char **pp
505 )
506 {
507 int type = F_NUL;
508 int width = 0;
509 register char *cp;
510
511 cp = inpbuf;
512 while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
513 width++;
514 switch (type) {
515 case F_NUL:
516 if (**pp == '$') {
517 (*pp)++;
518 width++;
519 if (**pp == '{') {
520 type = T_NUM;
521 (*pp)++;
522 continue;
523 } else if (**pp == '(') {
524 type = T_STR;
525 (*pp)++;
526 continue;
527 } else if (**pp != '$') {
528 eputs("format error\n");
529 quit(1);
530 }
531 width--;
532 }
533 type = T_LIT;
534 *cp++ = *(*pp)++;
535 continue;
536 case T_LIT:
537 if (**pp == '$') {
538 width--;
539 break;
540 }
541 *cp++ = *(*pp)++;
542 continue;
543 case T_NUM:
544 if (**pp == '}') {
545 (*pp)++;
546 break;
547 }
548 if (!isspace(**pp))
549 *cp++ = **pp;
550 (*pp)++;
551 continue;
552 case T_STR:
553 if (**pp == ')') {
554 (*pp)++;
555 break;
556 }
557 if (!isspace(**pp))
558 *cp++ = **pp;
559 (*pp)++;
560 continue;
561 }
562 break;
563 }
564 *cp = '\0';
565 return(type | width);
566 }
567
568
569 struct strvar *
570 getsvar( /* get string variable */
571 char *svname
572 )
573 {
574 register struct strvar *sv;
575
576 for (sv = svhead; sv != NULL; sv = sv->next)
577 if (!strcmp(sv->name, svname))
578 return(sv);
579 sv = (struct strvar *)emalloc(sizeof(struct strvar));
580 sv->name = savqstr(svname);
581 sv->val = sv->preset = NULL;
582 sv->next = svhead;
583 svhead = sv;
584 return(sv);
585 }
586
587
588 static void
589 svpreset( /* preset a string variable */
590 char *eqn
591 )
592 {
593 register struct strvar *sv;
594 register char *val;
595
596 for (val = eqn; *val != '='; val++)
597 if (!*val)
598 return;
599 *val++ = '\0';
600 sv = getsvar(eqn);
601 if (sv->preset != NULL)
602 freqstr(sv->preset);
603 if (sv->val != NULL)
604 freqstr(sv->val);
605 sv->val = sv->preset = savqstr(val);
606 *--val = '=';
607 }
608
609
610 static void
611 clearrec(void) /* clear input record variables */
612 {
613 register struct field *f;
614
615 for (f = inpfmt; f != NULL; f = f->next)
616 switch (f->type & F_TYP) {
617 case T_NUM:
618 dremove(f->f.nv);
619 break;
620 case T_STR:
621 if (f->f.sv->val != f->f.sv->preset) {
622 freqstr(f->f.sv->val);
623 f->f.sv->val = f->f.sv->preset;
624 }
625 break;
626 }
627 }
628
629
630 static int
631 getrec(void) /* get next record from file */
632 {
633 int eatline;
634 register struct field *f;
635
636 while (ipb.chr != EOF) {
637 eatline = !igneol && ipb.chr != '\n';
638 if (blnkeq) /* beware of nbsynch() */
639 while (isblnk(ipb.chr))
640 resetinp();
641 clearrec(); /* start with fresh record */
642 for (f = inpfmt; f != NULL; f = f->next)
643 if (getfield(f) == -1)
644 break;
645 if (f == NULL) {
646 advinp(); /* got one! */
647 return(1);
648 }
649 resetinp(); /* eat false start */
650 if (eatline) { /* eat rest of line */
651 while (ipb.chr != '\n') {
652 if (ipb.chr == EOF)
653 return(0);
654 resetinp();
655 }
656 resetinp();
657 }
658 }
659 return(0);
660 }
661
662
663 static int
664 getfield( /* get next field */
665 register struct field *f
666 )
667 {
668 static char buf[RMAXWORD+1]; /* no recursion! */
669 int delim, inword;
670 double d;
671 char *np;
672 register char *cp;
673
674 switch (f->type & F_TYP) {
675 case T_LIT:
676 cp = f->f.sl;
677 do {
678 if (blnkeq && isblnk(*cp)) {
679 if (!isblnk(ipb.chr))
680 return(-1);
681 do
682 cp++;
683 while (isblnk(*cp));
684 do
685 scaninp();
686 while (isblnk(ipb.chr));
687 } else if (*cp == ipb.chr) {
688 cp++;
689 scaninp();
690 } else
691 return(-1);
692 } while (*cp);
693 return(0);
694 case T_STR:
695 if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
696 delim = EOF;
697 else
698 delim = f->next->f.sl[0];
699 cp = buf;
700 do {
701 if (ipb.chr == EOF || ipb.chr == '\n')
702 inword = 0;
703 else if (blnkeq && delim != EOF)
704 inword = isblnk(delim) ?
705 !isblnk(ipb.chr)
706 : ipb.chr != delim;
707 else
708 inword = cp-buf < (f->type & F_WID);
709 if (inword) {
710 *cp++ = ipb.chr;
711 scaninp();
712 }
713 } while (inword && cp < &buf[RMAXWORD]);
714 *cp = '\0';
715 if (f->f.sv->val == NULL)
716 f->f.sv->val = savqstr(buf); /* first setting */
717 else if (strcmp(f->f.sv->val, buf))
718 return(-1); /* doesn't match! */
719 return(0);
720 case T_NUM:
721 if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
722 delim = EOF;
723 else
724 delim = f->next->f.sl[0];
725 np = NULL;
726 cp = buf;
727 do {
728 if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
729 inword = 0;
730 else if (blnkeq && delim != EOF)
731 inword = isblnk(delim) ?
732 !isblnk(ipb.chr)
733 : ipb.chr != delim;
734 else
735 inword = cp-buf < (f->type & F_WID);
736 if (inword) {
737 if (np==NULL && !isblnk(ipb.chr))
738 np = cp;
739 *cp++ = ipb.chr;
740 scaninp();
741 }
742 } while (inword && cp < &buf[RMAXWORD]);
743 *cp = '\0';
744 d = np==NULL ? 0. : atof(np);
745 if (!vardefined(f->f.nv))
746 varset(f->f.nv, '=', d); /* first setting */
747 else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
748 || d < -.001)
749 return(-1); /* doesn't match! */
750 return(0);
751 }
752 return -1; /* pro forma return */
753 }
754
755
756 static void
757 putrec(void) /* output a record */
758 {
759 char fmt[32];
760 register int n;
761 register struct field *f;
762 int adlast, adnext;
763
764 adlast = 0;
765 for (f = outfmt; f != NULL; f = f->next) {
766 adnext = blnkeq &&
767 f->next != NULL &&
768 !( (f->next->type&F_TYP) == T_LIT &&
769 f->next->f.sl[0] == ' ' );
770 switch (f->type & F_TYP) {
771 case T_LIT:
772 fputs(f->f.sl, stdout);
773 adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
774 break;
775 case T_STR:
776 if (f->f.sv->val == NULL) {
777 eputs(f->f.sv->name);
778 eputs(": undefined string\n");
779 quit(1);
780 }
781 n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
782 if (adlast)
783 fputs(f->f.sv->val, stdout);
784 if (!(adlast && adnext))
785 while (n-- > 0)
786 putchar(' ');
787 if (!adlast)
788 fputs(f->f.sv->val, stdout);
789 adlast = 1;
790 break;
791 case T_NUM:
792 n = f->type & F_WID;
793 if (adlast && adnext)
794 strcpy(fmt, "%g");
795 else if (adlast)
796 sprintf(fmt, "%%-%dg", n);
797 else
798 sprintf(fmt, "%%%dg", n);
799 printf(fmt, evalue(f->f.ne));
800 adlast = 1;
801 break;
802 }
803 }
804 }
805
806
807 static void
808 initinp(FILE *fp) /* prepare lookahead buffer */
809
810 {
811 ipb.fin = fp;
812 ipb.beg = ipb.end = inpbuf;
813 ipb.pos = inpbuf-1; /* position before beginning */
814 ipb.chr = '\0';
815 scaninp();
816 }
817
818
819 static void
820 scaninp(void) /* scan next character */
821 {
822 if (ipb.chr == EOF)
823 return;
824 if (++ipb.pos >= &inpbuf[INBSIZ])
825 ipb.pos = inpbuf;
826 if (ipb.pos == ipb.end) { /* new character */
827 if ((ipb.chr = getc(ipb.fin)) != EOF) {
828 *ipb.end = ipb.chr;
829 if (++ipb.end >= &inpbuf[INBSIZ])
830 ipb.end = inpbuf;
831 if (ipb.end == ipb.beg)
832 ipb.beg = NULL;
833 }
834 } else
835 ipb.chr = *ipb.pos;
836 }
837
838
839 static void
840 advinp(void) /* move home to current position */
841 {
842 ipb.beg = ipb.pos;
843 }
844
845
846 static void
847 resetinp(void) /* rewind position and advance 1 */
848 {
849 if (ipb.beg == NULL) /* full */
850 ipb.beg = ipb.end;
851 ipb.pos = ipb.beg;
852 ipb.chr = *ipb.pos;
853 if (passive) /* transmit unmatched character? */
854 fputc(ipb.chr, stdout);
855 if (++ipb.beg >= &inpbuf[INBSIZ])
856 ipb.beg = inpbuf;
857 scaninp();
858 }
859
860
861 void
862 eputs(char *msg)
863 {
864 fputs(msg, stderr);
865 }
866
867
868 void
869 wputs(char *msg)
870 {
871 if (!nowarn)
872 eputs(msg);
873 }
874
875
876 void
877 quit(int code)
878 {
879 exit(code);
880 }