ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cal/rcalc.c
Revision: 1.32
Committed: Fri Mar 11 22:50:13 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.31: +54 -29 lines
Log Message:
feat(rcalc): Added -P option to pass records where cond evaluates <= 0

File Contents

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