ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.12
Committed: Sun Mar 28 20:33:12 2004 UTC (20 years ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.11: +4 -2 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

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