ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.7
Committed: Sun Jul 27 22:12:01 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.6: +2 -1 lines
Log Message:
Added grouping parens to reduce ambiguity warnings.

File Contents

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