/tags/rel-1-3-26/SWIG/Source/DOH/fio.c
# · C · 555 lines · 421 code · 43 blank · 91 comment · 143 complexity · 19da04ece0a840ff17bd63683f4a714d MD5 · raw file
- /* -----------------------------------------------------------------------------
- * 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[] = "$Header$";
- #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 (newformat));
- 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++;
- }
- }