ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.11
Committed: Fri Nov 14 17:31:24 2003 UTC (20 years, 5 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.10: +3 -1 lines
Log Message:
Reduced compile warnings.

File Contents

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