ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.3
Committed: Sun Apr 27 06:08:03 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +97 -7 lines
Log Message:
Added -idN or -ifN and -od or -of options to rcalc

File Contents

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