Logo Search packages:      
Sourcecode: cableswig version File versions  Download package

fio.c

/* ----------------------------------------------------------------------------- 
 * fio.c
 *
 *     This file implements a number of standard I/O operations included
 *     formatted output, readline, and splitting.
 * 
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *
 * Copyright (C) 1999-2000.  The University of Chicago
 * See the file LICENSE for information on usage and redistribution.    
 * ----------------------------------------------------------------------------- */

char cvsroot_fio_c[] = "/cvsroot/SWIG/Source/DOH/fio.c,v 1.4 2004/01/15 22:46:04 cheetah Exp";

#include "dohint.h"

#define OBUFLEN  512

static DOH *encodings = 0;              /* Encoding hash */

/* -----------------------------------------------------------------------------
 * Writen()
 *
 * Write's N characters of output and retries until all characters are
 * written.  This is useful should a write operation encounter a spurious signal.
 * ----------------------------------------------------------------------------- */

static int Writen(DOH *out, void *buffer, int len) {
  int nw = len, ret;
  char *cb = (char *) buffer;
  while (nw) {
    ret = Write(out,cb,nw);
    if (ret < 0) return -1;
    nw = nw - ret;
    cb += ret;
  }
  return len;
}

/* -----------------------------------------------------------------------------
 * DohEncoding()
 *
 * Registers a new printf encoding method.  An encoder function should accept
 * two file-like objects and operate as a filter.
 * ----------------------------------------------------------------------------- */

void 
DohEncoding(char *name, DOH *(*fn)(DOH *s)) {
  if (!encodings) encodings = NewHash();
  Setattr(encodings,(void *) name, NewVoid((void *)fn,0));
}

/* internal function for processing an encoding */
static DOH *encode(char *name,  DOH *s) {
  DOH *handle, *ns;
  DOH *(*fn)(DOH *);
  long  pos;
  if (!encodings || !(handle = Getattr(encodings,name))) {
    return Copy(s);
  }
  pos = Tell(s);
  Seek(s,0,SEEK_SET);
  fn = (DOH *(*)(DOH *)) Data(handle);
  ns = (*fn)(s);
  Seek(s,pos,SEEK_SET);
  return ns;
}

/* -----------------------------------------------------------------------------
 * DohvPrintf()
 *
 * DOH implementation of printf.  Output can be directed to any file-like object
 * including bare FILE * objects.  The same formatting codes as printf are
 * recognized with two extensions:
 *
 *       %s          - Prints a "char *" or the string representation of any
 *                     DOH object.  This will implicitly result in a call to
 *                     Str(obj).
 *
 *       %(encoder)* - Filters the output through an encoding function registered
 *                     with DohEncoder().
 *
 * Note: This function is not particularly memory efficient with large strings.
 * It's better to use Dump() or some other method instead.
 * ----------------------------------------------------------------------------- */

int
DohvPrintf(DOH *so, const char *format, va_list ap)
{
  static char *fmt_codes = "dioxXucsSfeEgGpn";
  int state = 0;
  const char *p = format;
  char  newformat[256];
  char  obuffer[OBUFLEN];
  char *fmt = 0;
  char  temp[64];
  int   widthval = 0;
  int   precval = 0;
  int   maxwidth;
  char  *w = 0;
  int   ivalue;
  double dvalue;
  void  *pvalue;
  char  *stemp;
  int   nbytes = 0;
  char  encoder[128], *ec = 0;

  memset (newformat, 0, sizeof (char *));

  while (*p) {
    switch(state) {
    case 0:  /* Ordinary text */
      if (*p != '%') {
      Putc(*p,so);
      nbytes++;
      } else{
      fmt = newformat;
      widthval = 0;
      precval = 0;
      *(fmt++) = *p;
      encoder[0] = 0;
      state = 10;
      }
      break;
    case 10: /* Look for a width and precision */
      if (isdigit((int)*p) && (*p != '0')) {
      w = temp;
      *(w++) = *p;
      *(fmt++) = *p;
      state = 20;
      } else if (strchr(fmt_codes,*p)) {
      /* Got one of the formatting codes */
      p--;
      state = 100;
      } else if (*p == '*') {
      /* Width field is specified in the format list */
      widthval = va_arg(ap,int);
      sprintf(temp,"%d",widthval);
      for (w = temp; *w; w++) {
        *(fmt++) = *w;
      }
      state = 30;
      } else if (*p == '%') {
      Putc(*p,so);
      fmt = newformat;
      nbytes++;
      state = 0;
      } else if (*p == '(') {
      ec = encoder;
      state = 60;
      } else {
      *(fmt++) = *p;
      }
      break;
      
    case 20: /* Hmmm. At the start of a width field */
      if (isdigit((int)*p)) {
      *(w++) = *p;
      *(fmt++) = *p;
      } else if (strchr(fmt_codes,*p)) {
      /* Got one of the formatting codes */
      /* Figure out width */
      *w = 0;
      widthval = atoi(temp);
      p--;
      state = 100;
      } else if (*p == '.') {
      *w = 0;
      widthval = atoi(temp);
      w = temp;
      *(fmt++) = *p;
      state = 40;
      } else {
      /* ??? */
      *w = 0;
      widthval = atoi(temp);
      state = 50;
      }
      break;

    case 30:   /* Parsed a width from an argument.  Look for a . */
      if (*p == '.') {
      w = temp;
      *(fmt++) = *p;
      state = 40;
      } else if (strchr(fmt_codes,*p)) {
      /* Got one of the formatting codes */
      /* Figure out width */
      p--;
      state = 100;
      } else {
      /* hmmm. Something else. */
      state = 50;
      }
      break;

    case 40:
      /* Start of precision expected */
      if (isdigit((int)*p) && (*p != '0')) {
      *(fmt++) = *p;
      *(w++) = *p;
      state = 41;
      } else if (*p == '*') {
      /* Precision field is specified in the format list */
      precval = va_arg(ap,int);
      sprintf(temp,"%d",precval);
      for (w = temp; *w; w++) {
        *(fmt++) = *w;
      }
      state = 50;
      } else if (strchr(fmt_codes,*p)) {
      p--;
      state = 100;
      } else {
      *(fmt++) = *p;
      state = 50;
      }
      break;
    case 41:
      if (isdigit((int)*p)) {
      *(fmt++) = *p;
      *(w++) = *p;
      } else if (strchr(fmt_codes,*p)) {
      /* Got one of the formatting codes */
      /* Figure out width */
      *w = 0;
      precval = atoi(temp);
      p--;
      state = 100;
      } else {
      *w = 0;
      precval = atoi(temp);
      *(fmt++) = *p;
      state = 50;
      }
      break;
      /* Hang out, wait for format specifier */
    case 50:
      if (strchr(fmt_codes,*p)) {
      p--;
      state = 100;
      } else {
      *(fmt++) = *p;
      }
      break;

      /* Got an encoding header */
    case 60:
      if (*p == ')') {
      *ec = 0;
      state = 10;
      } else {
      *ec = *p;
      ec++;
      }
      break;
    case 100:
      /* Got a formatting code */
      if (widthval < precval) maxwidth = precval;
      else maxwidth = widthval;
      if ((*p == 's') || (*p == 'S')) {       /* Null-Terminated string */
      DOH    *doh;
      DOH    *Sval;
      DOH    *enc = 0;
      doh = va_arg(ap, DOH *);
      if (DohCheck(doh)) {
        /* Is a DOH object. */
        if (DohIsString(doh)) {
          Sval = doh;
        } else {
          Sval = Str(doh);
        }
        if (strlen(encoder)) {
          enc = encode(encoder,Sval);
          maxwidth = maxwidth+strlen(newformat)+Len(enc);
        } else {
          maxwidth = maxwidth+strlen(newformat)+Len(Sval);
        }
        *(fmt++) = 's';
        *fmt = 0;
        if ((maxwidth + 1) < OBUFLEN) {
          stemp = obuffer;
        } else {
          stemp = (char *) DohMalloc(maxwidth+1);
        }
        if (enc) {
          nbytes+=sprintf(stemp,newformat,Data(enc));
        } else {
          nbytes+=sprintf(stemp,newformat,Data(Sval));
        }
        if (Writen(so,stemp,strlen(stemp)) < 0) return -1;
        if ((DOH *) Sval != doh) {
          Delete(Sval);
        }
        if (enc) Delete(enc);
        if (*p == 'S') {
          Delete(doh);
        }
        if (stemp != obuffer) {
          DohFree(stemp);
        }
      } else {
        if (!doh) doh = (char *)"";
        
        if (strlen(encoder)) {
          DOH *s = NewString(doh);
          Seek(s,0, SEEK_SET);
          enc = encode(encoder,s);
          Delete(s);
          doh = Char(enc);
        } else {
          enc = 0;
        }
        maxwidth = maxwidth+strlen(newformat)+strlen((char *) doh);
        *(fmt++) = 's';
        *fmt = 0;
        if ((maxwidth+1) < OBUFLEN) {
          stemp = obuffer;
        } else {
          stemp = (char *) DohMalloc(maxwidth + 1);
        }
        nbytes+=sprintf(stemp,newformat,doh);
        if (Writen(so,stemp,strlen(stemp)) < 0) return -1;
        if (stemp != obuffer) {
          DohFree(stemp);
        }
        if (enc) Delete(enc);
      }
      } else {
      *(fmt++) = *p;
      *fmt = 0;
      maxwidth = maxwidth+strlen(newformat)+64;
      
      /* Only allocate a buffer if it is too big to fit.  Shouldn't have to do
           this very often */

      if (maxwidth < OBUFLEN)
        stemp = obuffer;
      else 
        stemp = (char *) DohMalloc(maxwidth+1);
      switch(*p) {
      case 'd':
      case 'i':
      case 'o':
      case 'u':
      case 'x':
      case 'X':
      case 'c':
        ivalue = va_arg(ap,int);
        nbytes+=sprintf(stemp,newformat,ivalue);
        break;
      case 'f':
      case 'g':
      case 'e':
      case 'E':
      case 'G':
        dvalue = va_arg(ap,double);
        nbytes+=sprintf(stemp,newformat,dvalue);
        break;
      case 'p':
        pvalue = va_arg(ap,void *);
        nbytes+=sprintf(stemp,newformat,pvalue);        
        break;
      default:
        break;
      }
      if (Writen(so,stemp,strlen(stemp)) < 0) return -1;
      if (stemp != obuffer) DohFree(stemp);
      }
      state = 0;
      break;
    }
    p++;
  }
  if (state) {
    int r;
    *fmt = 0;
    r = Writen(so,fmt,strlen(fmt));
    if (r < 0) return -1;
    nbytes += r;
  }
  return nbytes;
}

/* -----------------------------------------------------------------------------
 * DohPrintf()
 *
 * Variable length argument entry point to Printf
 * ----------------------------------------------------------------------------- */

int
DohPrintf(DOH *obj, const char *format, ...) {
  va_list ap;
  int ret;
  va_start(ap,format);
  ret = DohvPrintf(obj,format,ap);
  va_end(ap);
  return ret;
}

/* -----------------------------------------------------------------------------
 * DohPrintv()
 * 
 * Print a null-terminated variable length list of DOH objects
 * ----------------------------------------------------------------------------- */

int DohPrintv(DOHFile *f, ...) {
  va_list ap;
  int ret = 0;
  DOH *obj;
  va_start(ap,f);
  while(1) {
    obj = va_arg(ap,void *);
    if ((!obj) || (obj == DohNone)) break;
    if (DohCheck(obj)) {
      ret += DohDump(obj,f);
    } else {
      ret += DohWrite(f,obj,strlen((char *) obj));
    }
  }
  va_end(ap);
  return ret;
}

/* ----------------------------------------------------------------------------- 
 * DohCopyto()
 *
 * Copies all of the input from an input stream to an output stream. Returns the
 * number of bytes copied.
 * ----------------------------------------------------------------------------- */

int
DohCopyto(DOH *in, DOH *out) {
  int nbytes = 0, ret;
  int nwrite = 0, wret;
  char *cw;
  char buffer[16384];

  if ((!in) || (!out)) return 0;
  while (1) {
    ret = Read(in,buffer,16384);
    if (ret > 0) {
      nwrite = ret;
      cw = buffer;
      while (nwrite) {
      wret = Write(out,cw,nwrite);
      if (wret < 0) return -1;
      nwrite = nwrite - wret;
      cw += wret;
      }
      nbytes += ret;
    } else {
      return nbytes;
    }
  }
}


/* -----------------------------------------------------------------------------
 * DohSplit()
 *
 * Split an input stream into a list of strings delimited by the specified
 * character.  Optionally accepts a maximum number of splits to perform.
 * ----------------------------------------------------------------------------- */

DOH *
DohSplit(DOH *in, char ch, int nsplits) {
  DOH *list;
  DOH *str;
  int c;
  
  list = NewList();

  if (DohIsString(in)) {
    Seek(in,0,SEEK_SET);
  }

  while (1) {
    str = NewString("");
    do {
      c = Getc(in);
    } while ((c != EOF) && (c == ch));
    if (c != EOF) {
      Putc(c,str);
      while (1) {
      c = Getc(in);
      if ((c == EOF) || ((c == ch) && (nsplits != 0))) break;
      Putc(c,str);
      }
      nsplits--;
    }
    Append(list,str);
    Delete(str);
    if (c == EOF) break;
  }
  return list;
}

/* -----------------------------------------------------------------------------
 * DohSplitLines()
 *
 * Split an input stream into a list of strings delimited by newline characters.
 * ----------------------------------------------------------------------------- */

DOH *
DohSplitLines(DOH *in) {
  DOH *list;
  DOH *str;
  int  c = 0;

  list = NewList();

  if (DohIsString(in)) {
    Seek(in,0,SEEK_SET);
  }

  while (c != EOF) {
    str = NewString("");
    while ((c = Getc(in)) != '\n' && c != EOF) {
      Putc(c, str);
    }
    Append(list,str);
    Delete(str);
  }
  return list;
}


/* -----------------------------------------------------------------------------
 * DohReadline()
 *
 * Read a single input line and return it as a string.
 * ----------------------------------------------------------------------------- */

DOH *
DohReadline(DOH *in) {
  char c;
  int n = 0;
  DOH *s = NewString("");
  while (1) {
    if (Read(in,&c,1) < 0) {
      if (n == 0) {
      Delete(s);
      return 0;
      }
      return s;
    }
    if (c == '\n') return s;
    if (c == '\r') continue;
    Putc(c,s);
    n++;
  }
}

  

Generated by  Doxygen 1.6.0   Back to index