ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.31
Committed: Mon Feb 21 23:00:55 2022 UTC (2 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.30: +157 -157 lines
Log Message:
refactor(rcalc): Replaced fputc() call with putchar() and tidied up tabs

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 1.31 static const char RCSid[] = "$Id: rcalc.c,v 1.30 2019/12/10 19:00:26 greg Exp $";
3 greg 1.1 #endif
4     /*
5 greg 1.31 * rcalc.c - record calculator program.
6 greg 1.1 *
7 greg 1.31 * 9/11/87
8 greg 1.1 */
9    
10 greg 1.31 #include <stdlib.h>
11     #include <math.h>
12     #include <ctype.h>
13    
14     #include "platform.h"
15     #include "rterror.h"
16     #include "rtmisc.h"
17     #include "rtio.h"
18     #include "calcomp.h"
19 greg 1.1
20 greg 1.31 #define isnum(c) (isdigit(c) || ((c)=='-') | ((c)=='.') \
21 greg 1.29 | ((c)=='+') | ((c)=='e') | ((c)=='E'))
22 greg 1.1
23 greg 1.31 #define isblnk(c) (igneol ? isspace(c) : ((c)==' ')|((c)=='\t'))
24 greg 1.1
25 greg 1.31 #define INBSIZ 16384 /* longest record */
26     #define MAXCOL 32 /* number of columns recorded */
27 greg 1.1
28     /* field type specifications */
29 greg 1.31 #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 greg 1.1 };
42    
43 greg 1.31 struct field { /* record format structure */
44     int type; /* type of field (& width) */
45 greg 1.1 union {
46 greg 1.31 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 greg 1.1 };
53    
54 greg 1.31 #define savqstr(s) strcpy(emalloc(strlen(s)+1),s)
55     #define freqstr(s) efree(s)
56 greg 1.1
57 greg 1.10 static int getinputrec(FILE *fp);
58 greg 1.31 static void scaninp(void), advinp(void), skipinp(void);
59 schorsch 1.5 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 greg 1.31 struct field *inpfmt = NULL; /* input record format */
73     struct field *outfmt = NULL; /* output record structure */
74     struct strvar *svhead = NULL; /* string variables */
75    
76     long incnt = 0; /* limit number of input records? */
77     long outcnt = 0; /* limit number of output records? */
78    
79     int blnkeq = 1; /* blanks compare equal? */
80     int igneol = 0; /* ignore end of line? */
81     int passive = 0; /* passive mode (transmit unmatched input) */
82     char sepchar = '\t'; /* input/output separator */
83     int noinput = 0; /* no input records? */
84     int itype = 'a'; /* input type (a/f/F/d/D) */
85     int nbicols = 0; /* number of binary input columns */
86     int otype = 'a'; /* output format (a/f/F/d/D) */
87     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 greg 1.1
92 greg 1.31 int nowarn = 0; /* non-fatal diagnostic output */
93     int unbuff = 0; /* unbuffered output (flush each record) */
94 greg 1.1
95     struct {
96 greg 1.31 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 greg 1.1
103    
104 schorsch 1.5 int
105     main(
106 greg 1.31 int argc,
107     char *argv[]
108 schorsch 1.5 )
109 greg 1.1 {
110 greg 1.31 char *fpath;
111     int i;
112 greg 1.1
113 greg 1.2 esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
114     esupport &= ~(E_REDEFW);
115 greg 1.1
116 greg 1.31 #ifdef BIGGERLIB
117 greg 1.1 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.31 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 greg 1.31 if (blnkeq) /* for efficiency */
251 greg 1.1 nbsynch();
252    
253 greg 1.31 if (i == argc) /* from stdin */
254 greg 1.1 execute(NULL);
255 greg 1.31 else /* from one or more files */
256 greg 1.1 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 greg 1.31 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 greg 1.31 FILE *fp
279 schorsch 1.5 )
280 greg 1.3 {
281     if (inpfmt != NULL)
282     return(getrec());
283 greg 1.29 if ((itype == 'd') | (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 greg 1.29 if ((itype == 'f') | (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 greg 1.31 execute( /* process a file */
303     char *file
304 schorsch 1.5 )
305 greg 1.1 {
306 greg 1.31 const int conditional = vardefined("cond");
307     const int set_recno = (varlookup("recno") != NULL);
308     const int set_outno = (varlookup("outno") != NULL);
309     long nrecs = 0;
310     long nout = 0;
311     FILE *fp;
312 greg 1.1
313     if (file == NULL)
314     fp = stdin;
315     else if ((fp = fopen(file, "r")) == NULL) {
316     eputs(file);
317     eputs(": cannot open\n");
318     quit(1);
319     }
320 greg 1.23 if (itype != 'a')
321     SET_FILE_BINARY(fp);
322     #ifdef getc_unlocked /* avoid lock/unlock overhead */
323     flockfile(fp);
324     #endif
325 greg 1.1 if (inpfmt != NULL)
326     initinp(fp);
327 greg 1.3
328     while (getinputrec(fp)) {
329 greg 1.28 ++nrecs;
330     if (set_recno)
331     varset("recno", '=', (double)nrecs);
332     if (set_outno)
333     varset("outno", '=', (double)(nout+1));
334 greg 1.1 colflg = 0;
335     eclock++;
336     if (!conditional || varvalue("cond") > 0.0) {
337     putout();
338 greg 1.21 ++nout;
339 greg 1.1 }
340 greg 1.26 if (incnt && nrecs >= incnt)
341     break;
342     if (outcnt && nout >= outcnt)
343     break;
344 greg 1.1 }
345     fclose(fp);
346     }
347    
348    
349 schorsch 1.5 static void
350 greg 1.31 putout(void) /* produce an output record */
351 greg 1.1 {
352    
353     colpos = 0;
354     if (outfmt != NULL)
355     putrec();
356 greg 1.20 else if (otype == 'a')
357     chanout(chanset);
358     else
359 greg 1.3 chanout(bchanset);
360 greg 1.20 if (colpos && otype == 'a')
361 greg 1.1 putchar('\n');
362     if (unbuff)
363     fflush(stdout);
364     }
365    
366 greg 1.10
367     static double
368     l_in(char *funame) /* function call for $channel */
369     {
370 greg 1.31 int n;
371     char *cp;
372 greg 1.10 /* get argument as integer */
373     n = (int)(argument(1) + .5);
374     if (n != 0) /* return channel value */
375     return(chanvalue(n));
376     /* determine number of channels */
377     if (noinput || inpfmt != NULL)
378     return(0);
379 greg 1.20 if (nbicols)
380 greg 1.10 return(nbicols);
381     cp = inpbuf; /* need to count */
382     for (n = 0; *cp; )
383     if (blnkeq && isspace(sepchar)) {
384     while (isspace(*cp))
385     cp++;
386     n += *cp != '\0';
387     while (*cp && !isspace(*cp))
388     cp++;
389     } else {
390     n += *cp != '\n';
391     while (*cp && *cp++ != sepchar)
392     ;
393     }
394     return(n);
395     }
396 greg 1.1
397     double
398 greg 1.31 chanvalue( /* return value for column n */
399     int n
400 schorsch 1.5 )
401 greg 1.1 {
402 greg 1.31 int i;
403     char *cp;
404 greg 1.1
405     if (noinput || inpfmt != NULL) {
406     eputs("no column input\n");
407     quit(1);
408     }
409     if (n < 1) {
410     eputs("illegal channel number\n");
411     quit(1);
412     }
413 greg 1.20 if (nbicols) {
414 greg 1.3 if (n > nbicols)
415     return(0.0);
416 greg 1.29 if ((itype == 'd') | (itype == 'D')) {
417 greg 1.20 cp = inpbuf + (n-1)*sizeof(double);
418     return(*(double *)cp);
419     }
420 greg 1.3 cp = inpbuf + (n-1)*sizeof(float);
421     return(*(float *)cp);
422     }
423 greg 1.1 if (n <= MAXCOL && colflg & 1L<<(n-1))
424     return(colval[n-1]);
425    
426     cp = inpbuf;
427     for (i = 1; i < n; i++)
428     if (blnkeq && isspace(sepchar)) {
429     while (isspace(*cp))
430     cp++;
431     while (*cp && !isspace(*cp))
432     cp++;
433     } else
434     while (*cp && *cp++ != sepchar)
435     ;
436    
437 greg 1.31 while (isspace(*cp)) /* some atof()'s don't like tabs */
438 greg 1.1 cp++;
439    
440     if (n <= MAXCOL) {
441     colflg |= 1L<<(n-1);
442     return(colval[n-1] = atof(cp));
443     } else
444     return(atof(cp));
445     }
446    
447    
448 greg 1.3 void
449 greg 1.31 chanset( /* output column n */
450     int n,
451     double v
452 schorsch 1.5 )
453 greg 1.1 {
454 greg 1.31 if (colpos == 0) /* no leading separator */
455 greg 1.1 colpos = 1;
456     while (colpos < n) {
457     putchar(sepchar);
458     colpos++;
459     }
460     printf("%.9g", v);
461 greg 1.3 }
462    
463    
464     void
465 greg 1.31 bchanset( /* output binary channel n */
466     int n,
467     double v
468 schorsch 1.5 )
469 greg 1.3 {
470     static char zerobuf[sizeof(double)];
471 greg 1.29 const int otlen = ((otype == 'd') | (otype == 'D')) ?
472     sizeof(double) : sizeof(float);
473 greg 1.20 float fval = v;
474 greg 1.3
475     while (++colpos < n)
476 greg 1.29 putbinary(zerobuf, otlen, 1, stdout);
477 greg 1.20 switch (otype) {
478     case 'D':
479     swap64((char *)&v, 1);
480     /* fall through */
481     case 'd':
482 greg 1.27 putbinary(&v, sizeof(double), 1, stdout);
483 greg 1.20 break;
484     case 'F':
485     swap32((char *)&fval, 1);
486     /* fall through */
487     case 'f':
488 greg 1.27 putbinary(&fval, sizeof(float), 1, stdout);
489 greg 1.20 break;
490 greg 1.3 }
491 greg 1.1 }
492    
493    
494 schorsch 1.5 static void
495 greg 1.31 readfmt( /* read record format */
496     char *spec,
497     int output
498 schorsch 1.5 )
499 greg 1.1 {
500 greg 1.31 int fd;
501     char *inptr;
502     struct field fmt;
503     int res;
504     struct field *f;
505 greg 1.1 /* check for inline format */
506     for (inptr = spec; *inptr; inptr++)
507     if (*inptr == '$')
508     break;
509 greg 1.31 if (*inptr) /* inline */
510 greg 1.1 inptr = spec;
511 greg 1.31 else { /* from file */
512 greg 1.1 if ((fd = open(spec, 0)) == -1) {
513     eputs(spec);
514     eputs(": cannot open\n");
515     quit(1);
516     }
517 greg 1.14 res = read(fd, inpbuf+2, INBSIZ-2);
518 greg 1.1 if (res <= 0 || res >= INBSIZ-1) {
519     eputs(spec);
520     if (res < 0)
521     eputs(": read error\n");
522     else if (res == 0)
523     eputs(": empty file\n");
524     else if (res >= INBSIZ-1)
525     eputs(": format too long\n");
526     quit(1);
527     }
528     close(fd);
529 greg 1.14 (inptr=inpbuf+2)[res] = '\0';
530 greg 1.1 }
531 greg 1.31 f = &fmt; /* get fields */
532 greg 1.1 while ((res = readfield(&inptr)) != F_NUL) {
533     f->next = (struct field *)emalloc(sizeof(struct field));
534     f = f->next;
535     f->type = res;
536     switch (res & F_TYP) {
537     case T_LIT:
538     f->f.sl = savqstr(inpbuf);
539     break;
540     case T_STR:
541     f->f.sv = getsvar(inpbuf);
542     break;
543     case T_NUM:
544     if (output)
545     f->f.ne = eparse(inpbuf);
546     else
547     f->f.nv = savestr(inpbuf);
548     break;
549     }
550     /* add final newline if necessary */
551     if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
552     inptr = "\n";
553     }
554     f->next = NULL;
555     if (output)
556     outfmt = fmt.next;
557     else
558     inpfmt = fmt.next;
559     }
560    
561    
562 schorsch 1.5 static int
563 greg 1.31 readfield( /* get next field in format */
564     char **pp
565 schorsch 1.5 )
566 greg 1.1 {
567 greg 1.31 int type = F_NUL;
568     int width = 0;
569     char *cp;
570 greg 1.1
571     cp = inpbuf;
572     while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
573     width++;
574     switch (type) {
575     case F_NUL:
576     if (**pp == '$') {
577     (*pp)++;
578     width++;
579     if (**pp == '{') {
580     type = T_NUM;
581     (*pp)++;
582     continue;
583     } else if (**pp == '(') {
584     type = T_STR;
585     (*pp)++;
586     continue;
587     } else if (**pp != '$') {
588     eputs("format error\n");
589     quit(1);
590     }
591     width--;
592     }
593     type = T_LIT;
594     *cp++ = *(*pp)++;
595     continue;
596     case T_LIT:
597     if (**pp == '$') {
598     width--;
599     break;
600     }
601     *cp++ = *(*pp)++;
602     continue;
603     case T_NUM:
604     if (**pp == '}') {
605     (*pp)++;
606     break;
607     }
608     if (!isspace(**pp))
609     *cp++ = **pp;
610     (*pp)++;
611     continue;
612     case T_STR:
613     if (**pp == ')') {
614     (*pp)++;
615     break;
616     }
617     if (!isspace(**pp))
618     *cp++ = **pp;
619     (*pp)++;
620     continue;
621     }
622     break;
623     }
624     *cp = '\0';
625     return(type | width);
626     }
627    
628    
629     struct strvar *
630 greg 1.31 getsvar( /* get string variable */
631     char *svname
632 schorsch 1.5 )
633 greg 1.1 {
634 greg 1.31 struct strvar *sv;
635 greg 1.1
636     for (sv = svhead; sv != NULL; sv = sv->next)
637     if (!strcmp(sv->name, svname))
638     return(sv);
639     sv = (struct strvar *)emalloc(sizeof(struct strvar));
640     sv->name = savqstr(svname);
641     sv->val = sv->preset = NULL;
642     sv->next = svhead;
643     svhead = sv;
644     return(sv);
645     }
646    
647    
648 schorsch 1.5 static void
649 greg 1.31 svpreset( /* preset a string variable */
650     char *eqn
651 schorsch 1.5 )
652 greg 1.1 {
653 greg 1.31 struct strvar *sv;
654     char *val;
655 greg 1.1
656     for (val = eqn; *val != '='; val++)
657     if (!*val)
658     return;
659     *val++ = '\0';
660     sv = getsvar(eqn);
661     if (sv->preset != NULL)
662     freqstr(sv->preset);
663     if (sv->val != NULL)
664     freqstr(sv->val);
665     sv->val = sv->preset = savqstr(val);
666     *--val = '=';
667     }
668    
669    
670 schorsch 1.5 static void
671     clearrec(void) /* clear input record variables */
672 greg 1.1 {
673 greg 1.31 struct field *f;
674 greg 1.1
675     for (f = inpfmt; f != NULL; f = f->next)
676     switch (f->type & F_TYP) {
677     case T_NUM:
678     dremove(f->f.nv);
679     break;
680     case T_STR:
681     if (f->f.sv->val != f->f.sv->preset) {
682     freqstr(f->f.sv->val);
683     f->f.sv->val = f->f.sv->preset;
684     }
685     break;
686     }
687     }
688    
689    
690 schorsch 1.5 static int
691 greg 1.13 getrec(void) /* get next record from file */
692 greg 1.1 {
693 greg 1.31 int eatline;
694     struct field *f;
695 greg 1.14
696 greg 1.1 while (ipb.chr != EOF) {
697 greg 1.19 if (blnkeq) { /* beware of nbsynch() */
698 greg 1.1 while (isblnk(ipb.chr))
699 greg 1.31 skipinp();
700 greg 1.19 if (ipb.chr == EOF)
701     return(0);
702     }
703 greg 1.29 eatline = !igneol & (ipb.chr != '\n');
704 greg 1.1 clearrec(); /* start with fresh record */
705     for (f = inpfmt; f != NULL; f = f->next)
706 greg 1.30 if (!getfield(f))
707 greg 1.1 break;
708     if (f == NULL) {
709 greg 1.31 advinp(); /* got one! */
710 greg 1.1 return(1);
711     }
712 greg 1.31 skipinp(); /* eat false start */
713     if (eatline) { /* eat rest of line */
714 greg 1.1 while (ipb.chr != '\n') {
715     if (ipb.chr == EOF)
716     return(0);
717 greg 1.31 skipinp();
718 greg 1.1 }
719 greg 1.31 skipinp();
720 greg 1.1 }
721     }
722     return(0);
723     }
724    
725    
726 schorsch 1.5 static int
727 greg 1.31 getfield( /* get next field */
728     struct field *f
729 schorsch 1.5 )
730 greg 1.1 {
731 greg 1.31 static char buf[RMAXWORD+1]; /* no recursion! */
732     int delim, inword;
733     double d;
734     char *np;
735     char *cp;
736 greg 1.1
737     switch (f->type & F_TYP) {
738     case T_LIT:
739     cp = f->f.sl;
740     do {
741     if (blnkeq && isblnk(*cp)) {
742     if (!isblnk(ipb.chr))
743 greg 1.30 return(0);
744 greg 1.1 do
745     cp++;
746     while (isblnk(*cp));
747     do
748     scaninp();
749     while (isblnk(ipb.chr));
750     } else if (*cp == ipb.chr) {
751     cp++;
752     scaninp();
753     } else
754 greg 1.30 return(0);
755 greg 1.1 } while (*cp);
756 greg 1.30 break;
757 greg 1.1 case T_STR:
758     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
759     delim = EOF;
760     else
761     delim = f->next->f.sl[0];
762     cp = buf;
763     do {
764 greg 1.29 if ((ipb.chr == EOF) | (ipb.chr == '\n'))
765 greg 1.1 inword = 0;
766     else if (blnkeq && delim != EOF)
767     inword = isblnk(delim) ?
768     !isblnk(ipb.chr)
769     : ipb.chr != delim;
770     else
771     inword = cp-buf < (f->type & F_WID);
772     if (inword) {
773     *cp++ = ipb.chr;
774     scaninp();
775     }
776 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
777 greg 1.1 *cp = '\0';
778     if (f->f.sv->val == NULL)
779     f->f.sv->val = savqstr(buf); /* first setting */
780     else if (strcmp(f->f.sv->val, buf))
781 greg 1.30 return(0); /* doesn't match! */
782     break;
783 greg 1.1 case T_NUM:
784     if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
785     delim = EOF;
786     else
787     delim = f->next->f.sl[0];
788     np = NULL;
789     cp = buf;
790     do {
791     if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
792     inword = 0;
793     else if (blnkeq && delim != EOF)
794     inword = isblnk(delim) ?
795     !isblnk(ipb.chr)
796     : ipb.chr != delim;
797     else
798     inword = cp-buf < (f->type & F_WID);
799     if (inword) {
800     if (np==NULL && !isblnk(ipb.chr))
801     np = cp;
802     *cp++ = ipb.chr;
803     scaninp();
804     }
805 schorsch 1.6 } while (inword && cp < &buf[RMAXWORD]);
806 greg 1.1 *cp = '\0';
807     d = np==NULL ? 0. : atof(np);
808     if (!vardefined(f->f.nv))
809     varset(f->f.nv, '=', d); /* first setting */
810     else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
811     || d < -.001)
812 greg 1.30 return(0); /* doesn't match! */
813     break;
814 greg 1.1 }
815 greg 1.30 return(1); /* success! */
816 greg 1.1 }
817    
818    
819 schorsch 1.5 static void
820 greg 1.31 putrec(void) /* output a record */
821 greg 1.1 {
822 greg 1.31 char fmt[32], typ[16];
823     int n;
824     struct field *f;
825     int adlast, adnext;
826     double dv, av;
827 greg 1.1
828     adlast = 0;
829     for (f = outfmt; f != NULL; f = f->next) {
830 greg 1.31 adnext = blnkeq &&
831 greg 1.1 f->next != NULL &&
832     !( (f->next->type&F_TYP) == T_LIT &&
833     f->next->f.sl[0] == ' ' );
834     switch (f->type & F_TYP) {
835     case T_LIT:
836     fputs(f->f.sl, stdout);
837     adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
838     break;
839     case T_STR:
840     if (f->f.sv->val == NULL) {
841     eputs(f->f.sv->name);
842     eputs(": undefined string\n");
843     quit(1);
844     }
845     n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
846     if (adlast)
847     fputs(f->f.sv->val, stdout);
848     if (!(adlast && adnext))
849     while (n-- > 0)
850     putchar(' ');
851     if (!adlast)
852     fputs(f->f.sv->val, stdout);
853     adlast = 1;
854     break;
855     case T_NUM:
856     n = f->type & F_WID;
857 greg 1.24 dv = evalue(f->f.ne);
858 greg 1.25 av = fabs(dv);
859     if (n <= 9)
860     strcpy(typ, "g");
861     else
862     sprintf(typ, ".%de", n-5);
863     if (av < 1L<<31) {
864 greg 1.24 long iv = (int)(av + .5);
865     if (iv && fabs(av-iv) <= av*1e-14)
866     strcpy(typ, ".0f");
867     }
868 greg 1.1 if (adlast && adnext)
869 greg 1.24 sprintf(fmt, "%%%s", typ);
870 greg 1.1 else if (adlast)
871 greg 1.24 sprintf(fmt, "%%-%d%s", n, typ);
872 greg 1.1 else
873 greg 1.24 sprintf(fmt, "%%%d%s", n, typ);
874     printf(fmt, dv);
875 greg 1.1 adlast = 1;
876     break;
877     }
878     }
879     }
880    
881    
882 schorsch 1.5 static void
883 greg 1.31 initinp(FILE *fp) /* prepare lookahead buffer */
884 schorsch 1.5
885 greg 1.1 {
886     ipb.fin = fp;
887     ipb.beg = ipb.end = inpbuf;
888 greg 1.31 ipb.pos = inpbuf-1; /* position before beginning */
889 greg 1.1 ipb.chr = '\0';
890     scaninp();
891     }
892    
893    
894 schorsch 1.5 static void
895 greg 1.31 scaninp(void) /* scan next character */
896 greg 1.1 {
897     if (ipb.chr == EOF)
898     return;
899     if (++ipb.pos >= &inpbuf[INBSIZ])
900     ipb.pos = inpbuf;
901 greg 1.31 if (ipb.pos == ipb.end) { /* new character */
902 greg 1.1 if ((ipb.chr = getc(ipb.fin)) != EOF) {
903     *ipb.end = ipb.chr;
904     if (++ipb.end >= &inpbuf[INBSIZ])
905     ipb.end = inpbuf;
906     if (ipb.end == ipb.beg)
907     ipb.beg = NULL;
908     }
909     } else
910     ipb.chr = *ipb.pos;
911     }
912    
913    
914 schorsch 1.5 static void
915 greg 1.31 advinp(void) /* move home to current position */
916 greg 1.1 {
917     ipb.beg = ipb.pos;
918     }
919    
920    
921 schorsch 1.5 static void
922 greg 1.31 skipinp(void) /* rewind position and advance 1 */
923 greg 1.1 {
924 greg 1.31 if (ipb.beg == NULL) /* full */
925 greg 1.1 ipb.beg = ipb.end;
926     ipb.pos = ipb.beg;
927     ipb.chr = *ipb.pos;
928 greg 1.13 if (passive) /* transmit unmatched character? */
929 greg 1.31 putchar(ipb.chr);
930 greg 1.1 if (++ipb.beg >= &inpbuf[INBSIZ])
931     ipb.beg = inpbuf;
932     scaninp();
933     }
934    
935    
936     void
937 greg 1.31 eputs(char *msg)
938 greg 1.1 {
939     fputs(msg, stderr);
940     }
941    
942    
943     void
944 greg 1.31 wputs(char *msg)
945 greg 1.1 {
946     if (!nowarn)
947     eputs(msg);
948     }
949    
950    
951     void
952 greg 1.31 quit(int code)
953 greg 1.1 {
954     exit(code);
955     }