ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.21
Committed: Sun Jun 14 00:33:16 2009 UTC (14 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R1, rad4R0
Changes since 1.20: +3 -2 lines
Log Message:
Added new genklemsamp utility and made vwright more useful

File Contents

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