ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.3
Committed: Sun Apr 27 06:08:03 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +97 -7 lines
Log Message:
Added -idN or -ifN and -od or -of options to rcalc

File Contents

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