ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.10
Committed: Thu Nov 6 05:39:33 2003 UTC (20 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +37 -2 lines
Log Message:
Added an in(n) column function to rcalc

File Contents

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