ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.8
Committed: Fri Aug 1 14:14:23 2003 UTC (20 years, 8 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.7: +1 -5 lines
Log Message:
Eliminated CPM, MAC, and UNIX conditional compiles.

File Contents

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