ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.24
Committed: Sat May 10 01:27:14 2014 UTC (9 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.23: +15 -6 lines
Log Message:
More adaptive handling of real output format (integers and high-precision)

File Contents

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