ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.6
Committed: Thu Jul 3 22:41:44 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.5: +4 -4 lines
Log Message:
Reduced compile problems on Windows.

File Contents

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