ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.1
Committed: Sat Feb 22 02:07:20 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

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