Back to index

radiance  4R0+20100331
rcalc.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: rcalc.c,v 1.21 2009/06/14 00:33:16 greg Exp $";
00003 #endif
00004 /*
00005  *  rcalc.c - record calculator program.
00006  *
00007  *     9/11/87
00008  */
00009 
00010 #include  <stdlib.h>
00011 #include  <fcntl.h>
00012 #include  <stdio.h>
00013 #include  <string.h>
00014 #include  <math.h>
00015 #include  <ctype.h>
00016 
00017 #include  "platform.h"
00018 #include  "rterror.h"
00019 #include  "rtmisc.h"
00020 #include  "rtio.h"
00021 #include  "calcomp.h"
00022 
00023 #define  isnum(c)       (isdigit(c) || (c)=='-' || (c)=='.' \
00024                             || (c)=='+' || (c)=='e' || (c)=='E')
00025 
00026 #define  isblnk(c)      (igneol ? isspace(c) : (c)==' '||(c)=='\t')
00027 
00028 #define  INBSIZ         16384      /* longest record */
00029 #define  MAXCOL         32      /* number of columns recorded */
00030 
00031                             /* field type specifications */
00032 #define  F_NUL          0               /* empty */
00033 #define  F_TYP          0x7000          /* mask for type */
00034 #define  F_WID          0x0fff          /* mask for width */
00035 #define  T_LIT          0x1000          /* string literal */
00036 #define  T_STR          0x2000          /* string variable */
00037 #define  T_NUM          0x3000          /* numeric value */
00038 
00039 struct strvar {                 /* string variable */
00040        char  *name;
00041        char  *val;
00042        char  *preset;
00043        struct strvar  *next;
00044 };
00045 
00046 struct field {                  /* record format structure */
00047        int  type;                      /* type of field (& width) */
00048        union {
00049               char  *sl;                      /* string literal */
00050               struct strvar  *sv;             /* string variable */
00051               char  *nv;                      /* numeric variable */
00052               EPNODE  *ne;                    /* numeric expression */
00053        } f;                            /* field contents */
00054        struct field  *next;            /* next field in record */
00055 };
00056 
00057 #define  savqstr(s)     strcpy(emalloc(strlen(s)+1),s)
00058 #define  freqstr(s)     efree(s)
00059 
00060 static int getinputrec(FILE *fp);
00061 static void scaninp(void), advinp(void), resetinp(void);
00062 static void putrec(void), putout(void), nbsynch(void);
00063 static int getrec(void);
00064 static void execute(char *file);
00065 static void initinp(FILE *fp);
00066 static void svpreset(char *eqn);
00067 static void readfmt(char *spec, int output);
00068 static int readfield(char **pp);
00069 static int getfield(struct field *f);
00070 static void chanset(int n, double v);
00071 static void bchanset(int n, double v);
00072 static struct strvar* getsvar(char *svname);
00073 static double l_in(char *);
00074 
00075 struct field  *inpfmt = NULL;   /* input record format */
00076 struct field  *outfmt = NULL;   /* output record structure */
00077 struct strvar  *svhead = NULL;  /* string variables */
00078 
00079 int  blnkeq = 1;                /* blanks compare equal? */
00080 int  igneol = 0;                /* ignore end of line? */
00081 int  passive = 0;           /* passive mode (transmit unmatched input) */
00082 char  sepchar = '\t';           /* input/output separator */
00083 int  noinput = 0;               /* no input records? */
00084 int  itype = 'a';           /* input type (a/f/F/d/D) */
00085 int  nbicols = 0;           /* number of binary input columns */
00086 int  otype = 'a';           /* output format (a/f/F/d/D) */
00087 char  inpbuf[INBSIZ];           /* input buffer */
00088 double  colval[MAXCOL];         /* input column values */
00089 unsigned long  colflg = 0;      /* column retrieved flags */
00090 int  colpos;                    /* output column position */
00091 
00092 int  nowarn = 0;                /* non-fatal diagnostic output */
00093 int  unbuff = 0;            /* unbuffered output (flush each record) */
00094 
00095 struct {
00096        FILE  *fin;                     /* input file */
00097        int  chr;                       /* next character */
00098        char  *beg;                     /* home position */
00099        char  *pos;                     /* scan position */
00100        char  *end;                     /* read position */
00101 } ipb;                          /* circular lookahead buffer */
00102 
00103 
00104 int
00105 main(
00106 int  argc,
00107 char  *argv[]
00108 )
00109 {
00110        int  i;
00111 
00112        esupport |= E_VARIABLE|E_FUNCTION|E_INCHAN|E_OUTCHAN|E_RCONST;
00113        esupport &= ~(E_REDEFW);
00114 
00115 #ifdef  BIGGERLIB
00116        biggerlib();
00117 #endif
00118        varset("PI", ':', 3.14159265358979323846);
00119        funset("in", 1, '=', &l_in);
00120 
00121        for (i = 1; i < argc && argv[i][0] == '-'; i++)
00122               switch (argv[i][1]) {
00123               case 'b':
00124                      blnkeq = !blnkeq;
00125                      break;
00126               case 'l':
00127                      igneol = !igneol;
00128                      break;
00129               case 'p':
00130                      passive = !passive;
00131                      break;
00132               case 't':
00133                      sepchar = argv[i][2];
00134                      break;
00135               case 's':
00136                      svpreset(argv[++i]);
00137                      break;
00138               case 'f':
00139                      fcompile(argv[++i]);
00140                      break;
00141               case 'e':
00142                      scompile(argv[++i], NULL, 0);
00143                      break;
00144               case 'n':
00145                      noinput = 1;
00146                      break;
00147               case 'i':
00148                      switch (argv[i][2]) {
00149                      case '\0':
00150                             itype = 'a';
00151                             nbicols = 0;
00152                             readfmt(argv[++i], 0);
00153                             break;
00154                      case 'a':
00155                             itype = 'a';
00156                             nbicols = 0;
00157                             break;
00158                      case 'd':
00159                      case 'D':
00160                             itype = argv[i][2];
00161                             if (isdigit(argv[i][3]))
00162                                    nbicols = atoi(argv[i]+3);
00163                             else
00164                                    nbicols = 1;
00165                             if (nbicols*sizeof(double) > INBSIZ) {
00166                                    eputs(argv[0]);
00167                                    eputs(": too many input columns\n");
00168                                    quit(1);
00169                             }
00170                             break;
00171                      case 'f':
00172                      case 'F':
00173                             itype = argv[i][2];
00174                             if (isdigit(argv[i][3]))
00175                                    nbicols = atoi(argv[i]+3);
00176                             else
00177                                    nbicols = 1;
00178                             if (nbicols*sizeof(float) > INBSIZ) {
00179                                    eputs(argv[0]);
00180                                    eputs(": too many input columns\n");
00181                                    quit(1);
00182                             }
00183                             break;
00184                      default:
00185                             goto userr;
00186                      }
00187                      break;
00188               case 'o':
00189                      switch (argv[i][2]) {
00190                      case '\0':
00191                             otype = 'a';
00192                             readfmt(argv[++i], 1);
00193                             break;
00194                      case 'a':
00195                             otype = 'a';
00196                             break;
00197                      case 'd':
00198                      case 'D':
00199                      case 'f':
00200                      case 'F':
00201                             otype = argv[i][2];
00202                             break;
00203                      default:
00204                             goto userr;
00205                      }
00206                      break;
00207               case 'w':
00208                      nowarn = !nowarn;
00209                      break;
00210               case 'u':
00211                      unbuff = !unbuff;
00212                      break;
00213               default:;
00214               userr:
00215                      eputs("Usage: ");
00216                      eputs(argv[0]);
00217 eputs(" [-b][-l][-n][-p][-w][-u][-tS][-s svar=sval][-e expr][-f source][-i infmt][-o outfmt] [file]\n");
00218                      quit(1);
00219               }
00220        if (otype != 'a')
00221               SET_FILE_BINARY(stdout);
00222        if (noinput) {          /* produce a single output record */
00223               if (i < argc) {
00224                      eputs(argv[0]);
00225                      eputs(": file argument(s) incompatible with -n\n");
00226                      quit(1);
00227               }
00228               eclock++;
00229               putout();
00230               quit(0);
00231        }
00232        if (itype != 'a')
00233               SET_FILE_BINARY(stdin);
00234 
00235        if (blnkeq)             /* for efficiency */
00236               nbsynch();
00237 
00238        if (i == argc)          /* from stdin */
00239               execute(NULL);
00240        else                    /* from one or more files */
00241               for ( ; i < argc; i++)
00242                      execute(argv[i]);
00243        
00244        quit(0);
00245        return 0; /* pro forma return */
00246 }
00247 
00248 
00249 static void
00250 nbsynch(void)               /* non-blank starting synch character */
00251 {
00252        if (inpfmt == NULL || (inpfmt->type & F_TYP) != T_LIT)
00253               return;
00254        while (isblnk(*inpfmt->f.sl))
00255               inpfmt->f.sl++;
00256        if (!*inpfmt->f.sl)
00257               inpfmt = inpfmt->next;
00258 }
00259 
00260 
00261 static int
00262 getinputrec(         /* get next input record */
00263 FILE  *fp
00264 )
00265 {
00266        if (inpfmt != NULL)
00267               return(getrec());
00268        if (tolower(itype) == 'd') {
00269               if (fread(inpbuf, sizeof(double), nbicols, fp) != nbicols)
00270                      return(0);
00271               if (itype == 'D')
00272                      swap64(inpbuf, nbicols);
00273               return(1);
00274        }
00275        if (tolower(itype) == 'f') {
00276               if (fread(inpbuf, sizeof(float), nbicols, fp) != nbicols)
00277                      return(0);
00278               if (itype == 'F')
00279                      swap32(inpbuf, nbicols);
00280               return(1);
00281        }
00282        return(fgets(inpbuf, INBSIZ, fp) != NULL);
00283 }
00284 
00285 
00286 static void
00287 execute(           /* process a file */
00288 char  *file
00289 )
00290 {
00291        int  conditional = vardefined("cond");
00292        long  nrecs = 0;
00293        long  nout = 0;
00294        FILE  *fp;
00295        
00296        if (file == NULL)
00297               fp = stdin;
00298        else if ((fp = fopen(file, "r")) == NULL) {
00299               eputs(file);
00300               eputs(": cannot open\n");
00301               quit(1);
00302        }
00303        if (inpfmt != NULL)
00304               initinp(fp);
00305        
00306        while (getinputrec(fp)) {
00307               varset("recno", '=', (double)++nrecs);
00308               varset("outno", '=', (double)(nout+1));
00309               colflg = 0;
00310               eclock++;
00311               if (!conditional || varvalue("cond") > 0.0) {
00312                      putout();
00313                      ++nout;
00314               }
00315        }
00316        fclose(fp);
00317 }
00318 
00319 
00320 static void
00321 putout(void)                /* produce an output record */
00322 {
00323 
00324        colpos = 0;
00325        if (outfmt != NULL)
00326               putrec();
00327        else if (otype == 'a')
00328               chanout(chanset);
00329        else
00330               chanout(bchanset);
00331        if (colpos && otype == 'a')
00332               putchar('\n');
00333        if (unbuff)
00334               fflush(stdout);
00335 }
00336 
00337 
00338 static double
00339 l_in(char *funame)   /* function call for $channel */
00340 {
00341        int  n;
00342        register char  *cp;
00343                      /* get argument as integer */
00344        n = (int)(argument(1) + .5);
00345        if (n != 0)   /* return channel value */
00346               return(chanvalue(n));
00347                      /* determine number of channels */
00348        if (noinput || inpfmt != NULL)
00349               return(0);
00350        if (nbicols)
00351               return(nbicols);
00352        cp = inpbuf;  /* need to count */
00353        for (n = 0; *cp; )
00354               if (blnkeq && isspace(sepchar)) {
00355                      while (isspace(*cp))
00356                             cp++;
00357                      n += *cp != '\0';
00358                      while (*cp && !isspace(*cp))
00359                             cp++;
00360               } else {
00361                      n += *cp != '\n';
00362                      while (*cp && *cp++ != sepchar)
00363                             ;
00364               }
00365        return(n);
00366 }
00367 
00368 double
00369 chanvalue(            /* return value for column n */
00370 int  n
00371 )
00372 {
00373        int  i;
00374        register char  *cp;
00375 
00376        if (noinput || inpfmt != NULL) {
00377               eputs("no column input\n");
00378               quit(1);
00379        }
00380        if (n < 1) {
00381               eputs("illegal channel number\n");
00382               quit(1);
00383        }
00384        if (nbicols) {
00385               if (n > nbicols)
00386                      return(0.0);
00387               if (tolower(itype) == 'd') {
00388                      cp = inpbuf + (n-1)*sizeof(double);
00389                      return(*(double *)cp);
00390               }
00391               cp = inpbuf + (n-1)*sizeof(float);
00392               return(*(float *)cp);
00393        }
00394        if (n <= MAXCOL && colflg & 1L<<(n-1))
00395               return(colval[n-1]);
00396 
00397        cp = inpbuf;
00398        for (i = 1; i < n; i++)
00399               if (blnkeq && isspace(sepchar)) {
00400                      while (isspace(*cp))
00401                             cp++;
00402                      while (*cp && !isspace(*cp))
00403                             cp++;
00404               } else
00405                      while (*cp && *cp++ != sepchar)
00406                             ;
00407 
00408        while (isspace(*cp))            /* some atof()'s don't like tabs */
00409               cp++;
00410 
00411        if (n <= MAXCOL) {
00412               colflg |= 1L<<(n-1);
00413               return(colval[n-1] = atof(cp));
00414        } else
00415               return(atof(cp));
00416 }
00417 
00418 
00419 void
00420 chanset(                   /* output column n */
00421 int  n,
00422 double  v
00423 )
00424 {
00425        if (colpos == 0)                /* no leading separator */
00426               colpos = 1;
00427        while (colpos < n) {
00428               putchar(sepchar);
00429               colpos++;
00430        }
00431        printf("%.9g", v);
00432 }
00433 
00434 
00435 void
00436 bchanset(                   /* output binary channel n */
00437 int  n,
00438 double  v
00439 )
00440 {
00441        static char   zerobuf[sizeof(double)];
00442        float  fval = v;
00443 
00444        while (++colpos < n)
00445               fwrite(zerobuf,
00446                      tolower(otype)=='d' ? sizeof(double) : sizeof(float),
00447                      1, stdout);
00448        switch (otype) {
00449        case 'D':
00450               swap64((char *)&v, 1);
00451               /* fall through */
00452        case 'd':
00453               fwrite(&v, sizeof(double), 1, stdout);
00454               break;
00455        case 'F':
00456               swap32((char *)&fval, 1);
00457               /* fall through */
00458        case 'f':
00459               fwrite(&fval, sizeof(float), 1, stdout);
00460               break;
00461        }
00462 }
00463 
00464 
00465 static void
00466 readfmt(                   /* read record format */
00467 char  *spec,
00468 int  output
00469 )
00470 {
00471        int  fd;
00472        char  *inptr;
00473        struct field  fmt;
00474        int  res;
00475        register struct field  *f;
00476                                           /* check for inline format */
00477        for (inptr = spec; *inptr; inptr++)
00478               if (*inptr == '$')
00479                      break;
00480        if (*inptr)                             /* inline */
00481               inptr = spec;
00482        else {                                  /* from file */
00483               if ((fd = open(spec, 0)) == -1) {
00484                      eputs(spec);
00485                      eputs(": cannot open\n");
00486                      quit(1);
00487               }
00488               res = read(fd, inpbuf+2, INBSIZ-2);
00489               if (res <= 0 || res >= INBSIZ-1) {
00490                      eputs(spec);
00491                      if (res < 0)
00492                             eputs(": read error\n");
00493                      else if (res == 0)
00494                             eputs(": empty file\n");
00495                      else if (res >= INBSIZ-1)
00496                             eputs(": format too long\n");
00497                      quit(1);
00498               }
00499               close(fd);
00500               (inptr=inpbuf+2)[res] = '\0';
00501        }
00502        f = &fmt;                               /* get fields */
00503        while ((res = readfield(&inptr)) != F_NUL) {
00504               f->next = (struct field *)emalloc(sizeof(struct field));
00505               f = f->next;
00506               f->type = res;
00507               switch (res & F_TYP) {
00508               case T_LIT:
00509                      f->f.sl = savqstr(inpbuf);
00510                      break;
00511               case T_STR:
00512                      f->f.sv = getsvar(inpbuf);
00513                      break;
00514               case T_NUM:
00515                      if (output)
00516                             f->f.ne = eparse(inpbuf);
00517                      else
00518                             f->f.nv = savestr(inpbuf);
00519                      break;
00520               }
00521                                    /* add final newline if necessary */
00522               if (!igneol && *inptr == '\0' && inptr[-1] != '\n')
00523                      inptr = "\n";
00524        }
00525        f->next = NULL;
00526        if (output)
00527               outfmt = fmt.next;
00528        else
00529               inpfmt = fmt.next;
00530 }
00531 
00532 
00533 static int
00534 readfield(                   /* get next field in format */
00535 register char  **pp
00536 )
00537 {
00538        int  type = F_NUL;
00539        int  width = 0;
00540        register char  *cp;
00541        
00542        cp = inpbuf;
00543        while (cp < &inpbuf[INBSIZ-1] && **pp != '\0') {
00544               width++;
00545               switch (type) {
00546               case F_NUL:
00547                      if (**pp == '$') {
00548                             (*pp)++;
00549                             width++;
00550                             if (**pp == '{') {
00551                                    type = T_NUM;
00552                                    (*pp)++;
00553                                    continue;
00554                             } else if (**pp == '(') {
00555                                    type = T_STR;
00556                                    (*pp)++;
00557                                    continue;
00558                             } else if (**pp != '$') {
00559                                    eputs("format error\n");
00560                                    quit(1);
00561                             }
00562                             width--;
00563                      }
00564                      type = T_LIT;
00565                      *cp++ = *(*pp)++;
00566                      continue;
00567               case T_LIT:
00568                      if (**pp == '$') {
00569                             width--;
00570                             break;
00571                      }
00572                      *cp++ = *(*pp)++;
00573                      continue;
00574               case T_NUM:
00575                      if (**pp == '}') {
00576                             (*pp)++;
00577                             break;
00578                      }
00579                      if (!isspace(**pp))
00580                             *cp++ = **pp;
00581                      (*pp)++;
00582                      continue;
00583               case T_STR:
00584                      if (**pp == ')') {
00585                             (*pp)++;
00586                             break;
00587                      }
00588                      if (!isspace(**pp))
00589                             *cp++ = **pp;
00590                      (*pp)++;
00591                      continue;
00592               }
00593               break;
00594        }
00595        *cp = '\0';
00596        return(type | width);
00597 }
00598 
00599 
00600 struct strvar *
00601 getsvar(                         /* get string variable */
00602 char  *svname
00603 )
00604 {
00605        register struct strvar  *sv;
00606        
00607        for (sv = svhead; sv != NULL; sv = sv->next)
00608               if (!strcmp(sv->name, svname))
00609                      return(sv);
00610        sv = (struct strvar *)emalloc(sizeof(struct strvar));
00611        sv->name = savqstr(svname);
00612        sv->val = sv->preset = NULL;
00613        sv->next = svhead;
00614        svhead = sv;
00615        return(sv);
00616 }
00617 
00618 
00619 static void
00620 svpreset(                    /* preset a string variable */
00621 char  *eqn
00622 )
00623 {
00624        register struct strvar  *sv;
00625        register char  *val;
00626 
00627        for (val = eqn; *val != '='; val++)
00628               if (!*val)
00629                      return;
00630        *val++ = '\0';
00631        sv = getsvar(eqn);
00632        if (sv->preset != NULL)
00633               freqstr(sv->preset);
00634        if (sv->val != NULL)
00635               freqstr(sv->val);
00636        sv->val = sv->preset = savqstr(val);
00637        *--val = '=';
00638 }
00639 
00640 
00641 static void
00642 clearrec(void)                     /* clear input record variables */
00643 {
00644        register struct field  *f;
00645 
00646        for (f = inpfmt; f != NULL; f = f->next)
00647               switch (f->type & F_TYP) {
00648               case T_NUM:
00649                      dremove(f->f.nv);
00650                      break;
00651               case T_STR:
00652                      if (f->f.sv->val != f->f.sv->preset) {
00653                             freqstr(f->f.sv->val);
00654                             f->f.sv->val = f->f.sv->preset;
00655                      }
00656                      break;
00657               }
00658 }
00659 
00660 
00661 static int
00662 getrec(void)                       /* get next record from file */
00663 {
00664        int  eatline;
00665        register struct field  *f;
00666 
00667        while (ipb.chr != EOF) {
00668               if (blnkeq) {        /* beware of nbsynch() */
00669                      while (isblnk(ipb.chr))
00670                             resetinp();
00671                      if (ipb.chr == EOF)
00672                             return(0);
00673               }
00674               eatline = (!igneol && ipb.chr != '\n');
00675               clearrec();          /* start with fresh record */
00676               for (f = inpfmt; f != NULL; f = f->next)
00677                      if (getfield(f) == -1)
00678                             break;
00679               if (f == NULL) {
00680                      advinp();       /* got one! */
00681                      return(1);
00682               }
00683               resetinp();          /* eat false start */
00684               if (eatline) {          /* eat rest of line */
00685                      while (ipb.chr != '\n') {
00686                             if (ipb.chr == EOF)
00687                                    return(0);
00688                             resetinp();
00689                      }
00690                      resetinp();
00691               }
00692        }
00693        return(0);
00694 }
00695 
00696 
00697 static int
00698 getfield(                             /* get next field */
00699 register struct field  *f
00700 )
00701 {
00702        static char  buf[RMAXWORD+1];            /* no recursion! */
00703        int  delim, inword;
00704        double  d;
00705        char  *np;
00706        register char  *cp;
00707 
00708        switch (f->type & F_TYP) {
00709        case T_LIT:
00710               cp = f->f.sl;
00711               do {
00712                      if (blnkeq && isblnk(*cp)) {
00713                             if (!isblnk(ipb.chr))
00714                                    return(-1);
00715                             do
00716                                    cp++;
00717                             while (isblnk(*cp));
00718                             do
00719                                    scaninp();
00720                             while (isblnk(ipb.chr));
00721                      } else if (*cp == ipb.chr) {
00722                             cp++;
00723                             scaninp();
00724                      } else
00725                             return(-1);
00726               } while (*cp);
00727               return(0);
00728        case T_STR:
00729               if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
00730                      delim = EOF;
00731               else
00732                      delim = f->next->f.sl[0];
00733               cp = buf;
00734               do {
00735                      if (ipb.chr == EOF || ipb.chr == '\n')
00736                             inword = 0;
00737                      else if (blnkeq && delim != EOF)
00738                             inword = isblnk(delim) ?
00739                                           !isblnk(ipb.chr)
00740                                           : ipb.chr != delim;
00741                      else
00742                             inword = cp-buf < (f->type & F_WID);
00743                      if (inword) {
00744                             *cp++ = ipb.chr;
00745                             scaninp();
00746                      }
00747               } while (inword && cp < &buf[RMAXWORD]);
00748               *cp = '\0';
00749               if (f->f.sv->val == NULL)
00750                      f->f.sv->val = savqstr(buf);       /* first setting */
00751               else if (strcmp(f->f.sv->val, buf))
00752                      return(-1);                 /* doesn't match! */
00753               return(0);
00754        case T_NUM:
00755               if (f->next == NULL || (f->next->type & F_TYP) != T_LIT)
00756                      delim = EOF;
00757               else
00758                      delim = f->next->f.sl[0];
00759               np = NULL;
00760               cp = buf;
00761               do {
00762                      if (!((np==NULL&&isblnk(ipb.chr)) || isnum(ipb.chr)))
00763                             inword = 0;
00764                      else if (blnkeq && delim != EOF)
00765                             inword = isblnk(delim) ?
00766                                           !isblnk(ipb.chr)
00767                                           : ipb.chr != delim;
00768                      else
00769                             inword = cp-buf < (f->type & F_WID);
00770                      if (inword) {
00771                             if (np==NULL && !isblnk(ipb.chr))
00772                                    np = cp;
00773                             *cp++ = ipb.chr;
00774                             scaninp();
00775                      }
00776               } while (inword && cp < &buf[RMAXWORD]);
00777               *cp = '\0';
00778               d = np==NULL ? 0. : atof(np);
00779               if (!vardefined(f->f.nv))
00780                      varset(f->f.nv, '=', d);    /* first setting */
00781               else if ((d = (varvalue(f->f.nv)-d)/(d==0.?1.:d)) > .001
00782                             || d < -.001)
00783                      return(-1);                 /* doesn't match! */
00784               return(0);
00785        }
00786        return -1; /* pro forma return */
00787 }
00788 
00789 
00790 static void
00791 putrec(void)                                /* output a record */
00792 {
00793        char  fmt[32];
00794        register int  n;
00795        register struct field  *f;
00796        int  adlast, adnext;
00797        
00798        adlast = 0;
00799        for (f = outfmt; f != NULL; f = f->next) {
00800               adnext =        blnkeq &&
00801                             f->next != NULL &&
00802                             !( (f->next->type&F_TYP) == T_LIT &&
00803                                    f->next->f.sl[0] == ' ' );
00804               switch (f->type & F_TYP) {
00805               case T_LIT:
00806                      fputs(f->f.sl, stdout);
00807                      adlast = f->f.sl[(f->type&F_WID)-1] != ' ';
00808                      break;
00809               case T_STR:
00810                      if (f->f.sv->val == NULL) {
00811                             eputs(f->f.sv->name);
00812                             eputs(": undefined string\n");
00813                             quit(1);
00814                      }
00815                      n = (int)(f->type & F_WID) - strlen(f->f.sv->val);
00816                      if (adlast)
00817                             fputs(f->f.sv->val, stdout);
00818                      if (!(adlast && adnext))
00819                             while (n-- > 0)
00820                                    putchar(' ');
00821                      if (!adlast)
00822                             fputs(f->f.sv->val, stdout);
00823                      adlast = 1;
00824                      break;
00825               case T_NUM:
00826                      n = f->type & F_WID;
00827                      if (adlast && adnext)
00828                             strcpy(fmt, "%g");
00829                      else if (adlast)
00830                             sprintf(fmt, "%%-%dg", n);
00831                      else
00832                             sprintf(fmt, "%%%dg", n);
00833                      printf(fmt, evalue(f->f.ne));
00834                      adlast = 1;
00835                      break;
00836               }
00837        }
00838 }
00839 
00840 
00841 static void
00842 initinp(FILE  *fp)                     /* prepare lookahead buffer */
00843 
00844 {
00845        ipb.fin = fp;
00846        ipb.beg = ipb.end = inpbuf;
00847        ipb.pos = inpbuf-1;             /* position before beginning */
00848        ipb.chr = '\0';
00849        scaninp();
00850 }
00851 
00852 
00853 static void
00854 scaninp(void)                       /* scan next character */
00855 {
00856        if (ipb.chr == EOF)
00857               return;
00858        if (++ipb.pos >= &inpbuf[INBSIZ])
00859               ipb.pos = inpbuf;
00860        if (ipb.pos == ipb.end) {               /* new character */
00861               if ((ipb.chr = getc(ipb.fin)) != EOF) {
00862                      *ipb.end = ipb.chr;
00863                      if (++ipb.end >= &inpbuf[INBSIZ])
00864                             ipb.end = inpbuf;
00865                      if (ipb.end == ipb.beg)
00866                             ipb.beg = NULL;
00867               }
00868        } else
00869               ipb.chr = *ipb.pos;
00870 }
00871 
00872 
00873 static void
00874 advinp(void)                        /* move home to current position */
00875 {
00876        ipb.beg = ipb.pos;
00877 }
00878 
00879 
00880 static void
00881 resetinp(void)                      /* rewind position and advance 1 */
00882 {
00883        if (ipb.beg == NULL)            /* full */
00884               ipb.beg = ipb.end;
00885        ipb.pos = ipb.beg;
00886        ipb.chr = *ipb.pos;
00887        if (passive)                /* transmit unmatched character? */
00888               fputc(ipb.chr, stdout);
00889        if (++ipb.beg >= &inpbuf[INBSIZ])
00890               ipb.beg = inpbuf;
00891        scaninp();
00892 }
00893 
00894 
00895 void
00896 eputs(char  *msg)
00897 {
00898        fputs(msg, stderr);
00899 }
00900 
00901 
00902 void
00903 wputs(char  *msg)
00904 {
00905        if (!nowarn)
00906               eputs(msg);
00907 }
00908 
00909 
00910 void
00911 quit(int  code)
00912 {
00913        exit(code);
00914 }