ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.27
Committed: Thu Aug 18 00:52:47 2016 UTC (7 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R2, rad5R1
Changes since 1.26: +6 -6 lines
Log Message:
Switched over to more efficient fread/fwrite replacements getbinary/putbinary

File Contents

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