ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.17
Committed: Wed Feb 16 17:20:22 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.16: +6 -1 lines
Log Message:
Added error check for files given with -n option

File Contents

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