ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.9
Committed: Wed Nov 5 19:03:03 2003 UTC (20 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +12 -2 lines
Log Message:
Added check for too many input columns for binary buffer

File Contents

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