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

# User Rev Content
1 greg 1.1 #ifndef lint
2 schorsch 1.7 static const char RCSid[] = "$Id: rcalc.c,v 1.6 2003/07/03 22:41:44 schorsch Exp $";
3 greg 1.1 #endif
4     /*
5     * rcalc.c - record calculator program.
6     *
7     * 9/11/87
8     */
9    
10 schorsch 1.5 #include <stdlib.h>
11 greg 1.1 #include <stdio.h>
12 schorsch 1.5 #include <string.h>
13 greg 1.1 #include <math.h>
14     #include <ctype.h>
15    
16 schorsch 1.5 #include "platform.h"
17 greg 1.1 #include "calcomp.h"
18 schorsch 1.7 #include "rterror.h"
19 greg 1.1
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 schorsch 1.5 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 greg 1.1
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 greg 1.3 int nbicols = 0; /* number of binary input columns */
83     int bocols = 0; /* produce binary output columns */
84 greg 1.1 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 schorsch 1.5 int
102     main(
103     int argc,
104     char *argv[]
105     )
106 greg 1.1 {
107     int i;
108    
109 greg 1.2 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
110     esupport &= ~(E_REDEFW);
111 greg 1.1
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 greg 1.3 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 greg 1.1 break;
165     case 'o':
166 greg 1.3 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 greg 1.1 break;
182     case 'w':
183     nowarn = !nowarn;
184     break;
185     case 'u':
186     unbuff = !unbuff;
187     break;
188 greg 1.3 default:;
189     userr:
190 greg 1.1 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 schorsch 1.5 static void
216     nbsynch(void) /* non-blank starting synch character */
217 greg 1.1 {
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 greg 1.3 int
228 schorsch 1.5 getinputrec( /* get next input record */
229     FILE *fp
230     )
231 greg 1.3 {
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 schorsch 1.5 static void
245     execute( /* process a file */
246     char *file
247     )
248 greg 1.1 {
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 greg 1.3
264     while (getinputrec(fp)) {
265 greg 1.1 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 schorsch 1.5 static void
278     putout(void) /* produce an output record */
279 greg 1.1 {
280    
281     colpos = 0;
282     if (outfmt != NULL)
283     putrec();
284 greg 1.3 else if (bocols)
285     chanout(bchanset);
286 greg 1.1 else
287     chanout(chanset);
288 greg 1.4 if (colpos && !bocols)
289 greg 1.1 putchar('\n');
290     if (unbuff)
291     fflush(stdout);
292     }
293    
294    
295     double
296 schorsch 1.5 chanvalue( /* return value for column n */
297     int n
298     )
299 greg 1.1 {
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 greg 1.3 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 greg 1.1 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 greg 1.3 void
349 schorsch 1.5 chanset( /* output column n */
350     int n,
351     double v
352     )
353 greg 1.1 {
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 greg 1.3 }
362    
363    
364     void
365 schorsch 1.5 bchanset( /* output binary channel n */
366     int n,
367     double v
368     )
369 greg 1.3 {
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 greg 1.1 }
383    
384    
385 schorsch 1.5 static void
386     readfmt( /* read record format */
387     char *spec,
388     int output
389     )
390 greg 1.1 {
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 schorsch 1.5 static int
454     readfield( /* get next field in format */
455     register char **pp
456     )
457 greg 1.1 {
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 schorsch 1.5 getsvar( /* get string variable */
522     char *svname
523     )
524 greg 1.1 {
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 schorsch 1.5 static void
540     svpreset( /* preset a string variable */
541     char *eqn
542     )
543 greg 1.1 {
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 schorsch 1.5 static void
562     clearrec(void) /* clear input record variables */
563 greg 1.1 {
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 schorsch 1.5 static int
582     getrec(void) /* get next record from file */
583 greg 1.1 {
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 schorsch 1.5 static int
616     getfield( /* get next field */
617     register struct field *f
618     )
619 greg 1.1 {
620 schorsch 1.6 static char buf[RMAXWORD+1]; /* no recursion! */
621 greg 1.1 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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
666 greg 1.1 *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 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
695 greg 1.1 *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 schorsch 1.5 return -1; /* pro forma return */
705 greg 1.1 }
706    
707    
708 schorsch 1.5 static void
709     putrec(void) /* output a record */
710 greg 1.1 {
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 schorsch 1.5 static void
760     initinp(FILE *fp) /* prepare lookahead buffer */
761    
762 greg 1.1 {
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 schorsch 1.5 static void
772     scaninp(void) /* scan next character */
773 greg 1.1 {
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 schorsch 1.5 static void
792     advinp(void) /* move home to current position */
793 greg 1.1 {
794     ipb.beg = ipb.pos;
795     }
796    
797    
798 schorsch 1.5 static void
799     resetinp(void) /* rewind position and advance 1 */
800 greg 1.1 {
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 schorsch 1.5 eputs(char *msg)
813 greg 1.1 {
814     fputs(msg, stderr);
815     }
816    
817    
818     void
819 schorsch 1.5 wputs(char *msg)
820 greg 1.1 {
821     if (!nowarn)
822     eputs(msg);
823     }
824    
825    
826     void
827 schorsch 1.5 quit(int code)
828 greg 1.1 {
829     exit(code);
830     }