/* xlfio.c - xlisp file i/o */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "xlisp.h" #include /* external variables */ extern LVAL k_direction,k_input,k_output; extern LVAL s_stdin,s_stdout,true; extern int xlfsize; #ifdef BETTERIO extern LVAL k_io, k_elementtype; extern LVAL a_fixnum, a_char; #endif /* forward declarations */ #ifdef ANSI LVAL getstroutput(LVAL stream); LVAL printit(int pflag, int tflag); LVAL flatsize(int pflag); #else FORWARD LVAL getstroutput(); FORWARD LVAL printit(); FORWARD LVAL flatsize(); #endif /* xread - read an expression */ LVAL xread() { LVAL fptr,eof,val; /* get file pointer and eof value */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); eof = (moreargs() ? xlgetarg() : NIL); if (moreargs()) xlgetarg(); /* toss now unused argument */ xllastarg(); /* read an expression */ if (!xlread(fptr,&val)) val = eof; /* return the expression */ return (val); } /* xprint - built-in function 'print' */ LVAL xprint() { return (printit(TRUE,TRUE)); } /* xprin1 - built-in function 'prin1' */ LVAL xprin1() { return (printit(TRUE,FALSE)); } /* xprinc - built-in function princ */ LVAL xprinc() { return (printit(FALSE,FALSE)); } /* xterpri - terminate the current print line */ LVAL xterpri() { LVAL fptr; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* terminate the print line and return nil */ xlterpri(fptr); return (NIL); } /* printit - common print function */ LOCAL LVAL printit(pflag,tflag) int pflag,tflag; { LVAL fptr,val; /* get expression to print and file pointer */ val = xlgetarg(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* print the value */ xlprint(fptr,val,pflag); /* terminate the print line if necessary */ if (tflag) xlterpri(fptr); /* return the result */ return (val); } /* xflatsize - compute the size of a printed representation using prin1 */ LVAL xflatsize() { return (flatsize(TRUE)); } /* xflatc - compute the size of a printed representation using princ */ LVAL xflatc() { return (flatsize(FALSE)); } /* flatsize - compute the size of a printed expression */ LOCAL LVAL flatsize(pflag) int pflag; { LVAL val; /* get the expression */ val = xlgetarg(); xllastarg(); /* print the value to compute its size */ xlfsize = 0; xlprint(NIL,val,pflag); /* return the length of the expression */ return (cvfixnum((FIXTYPE)xlfsize)); } /* xopen - open a file */ LVAL xopen() { char *name,*mode; FILE *fp; LVAL dir; #ifdef BETTERIO LVAL typ; #endif /* get the file name and direction */ name = (char *)getstring(xlgetfname()); if (!xlgetkeyarg(k_direction,&dir)) dir = k_input; #ifdef BETTERIO if (xlgetkeyarg(k_elementtype,&typ)) { if (typ != a_fixnum && typ != a_char) xlerror("illegal stream element type",typ); } else typ = a_char; #endif /* get the mode */ if (dir == k_input) mode = "r"; else if (dir == k_output) mode = "w"; #ifdef BETTERIO else if (dir == k_io) { mode = "r+"; /* try for existing file */ #ifdef __ZTC__ if ((fp = ((typ == a_fixnum? &osbopen : &osaopen)(name,mode))) != 0) return cvfile(fp); #else if ((fp = ((typ == a_fixnum? osbopen : osaopen)(name,mode))) != 0) return cvfile(fp); #endif mode = "w+"; /* create new file */ } #endif else xlerror("bad direction",dir); /* try to open the file */ #ifdef BETTERIO #ifdef __ZTC__ return (((fp = ((typ == a_fixnum ? &osbopen : &osaopen)(name,mode))) != 0) ? cvfile(fp) : NIL); #else return (((fp = ((typ == a_fixnum ? osbopen : osaopen)(name,mode))) != 0) ? cvfile(fp) : NIL); #endif #else return (((fp = osaopen(name,mode)) != 0) ? cvfile(fp) : NIL); #endif } #ifdef BETTERIO /* xfileposition - get position of file stream */ LVAL xfileposition() { long i,j; int t=0; LVAL fptr; FILE *fp; /* get file pointer */ fp = getfile(fptr = xlgastream()); /* make sure the file exists */ if (fp == NULL) xlfail("file not open"); /* get current position, adjusting for posible "unget" */ j = ftell(fp) + (getsavech(fptr) ? -1L : 0L); if (moreargs()) { /* must be set position */ i = getfixnum(xlgafixnum()); xllastarg(); setsavech(fptr,'\0'); /* toss unget character, if any */ fptr->n_sflags = 0; /* neither reading or writing currently */ if (i < 0 || (t=fseek(fp,i,SEEK_SET))!=0 || ftell(fp) != i) { if (t) return NIL; fseek(fp,j,SEEK_SET); xlfail("position outside of file"); } return true; } return (j == -1L ? NIL : cvfixnum(j)); } /* xfilelength - returns length of file */ LVAL xfilelength() { FILE *fp; long i,j; /* get file pointer */ fp = getfile(xlgastream()); xllastarg(); /* make sure the file exists */ if (fp == NULL) xlfail("file not open"); if ((i=ftell(fp)) == -1L || fseek(fp,0L,SEEK_END) || (j = ftell(fp)) == -1L || fseek(fp,i,SEEK_SET)) { return NIL; } return cvfixnum(j); } #endif /* xclose - close a file */ LVAL xclose() { LVAL fptr; /* get file pointer */ fptr = xlgastream(); xllastarg(); /* make sure the file exists */ if (getfile(fptr) == NULL) xlfail("file not open"); /* close the file */ osclose(getfile(fptr)); setfile(fptr,NULL); /* return nil */ return (NIL); } /* xrdchar - read a character from a file */ LVAL xrdchar() { LVAL fptr; int ch; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ return ((ch = xlgetc(fptr)) == EOF ? NIL : cvchar(ch)); } /* xrdbyte - read a byte from a file */ LVAL xrdbyte() { LVAL fptr; int ch; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ return ((ch = xlgetc(fptr)) == EOF ? NIL : cvfixnum((FIXTYPE)ch)); } /* xpkchar - peek at a character from a file */ LVAL xpkchar() { LVAL flag,fptr; int ch; /* peek flag and get file pointer */ flag = (moreargs() ? xlgetarg() : NIL); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* skip leading white space and get a character */ if (flag) while ((ch = xlpeek(fptr)) != EOF && isspace(ch)) xlgetc(fptr); else ch = xlpeek(fptr); /* return the character */ return (ch == EOF ? NIL : cvchar(ch)); } /* xwrchar - write a character to a file */ LVAL xwrchar() { LVAL fptr,chr; /* get the character and file pointer */ chr = xlgachar(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* put character to the file */ xlputc(fptr,getchcode(chr)); /* return the character */ return (chr); } /* xwrbyte - write a byte to a file */ LVAL xwrbyte() { LVAL fptr,chr; /* get the byte and file pointer */ chr = xlgafixnum(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* put byte to the file */ xlputc(fptr,(int)getfixnum(chr)); /* return the character */ return (chr); } /* xreadline - read a line from a file */ LVAL xreadline() { char buf[STRMAX+1],*p,*sptr; LVAL fptr,str,newstr; int len,blen,ch; /* protect some pointers */ xlsave1(str); /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ len = blen = 0; p = buf; while ((ch = xlgetc(fptr)) != EOF && ch != '\n') { /* check for buffer overflow */ if (blen >= STRMAX) { newstr = newstring(len + STRMAX + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *)sptr,(char *)getstring(str)); *p = '\0'; strcat((char *)sptr,(char *)buf); p = buf; blen = 0; len += STRMAX; str = newstr; } /* store the character */ *p++ = ch; ++blen; } /* check for end of file */ if (len == 0 && p == buf && ch == EOF) { xlpop(); return (NIL); } /* append the last substring */ if (str == NIL || blen) { newstr = newstring(len + blen + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *)sptr,(char *)getstring(str)); *p = '\0'; strcat((char *)sptr,(char *)buf); str = newstr; } /* restore the stack */ xlpop(); /* return the string */ return (str); } /* xmkstrinput - make a string input stream */ LVAL xmkstrinput() { int start,end,len,i; char *str; LVAL string,val; /* protect the return value */ xlsave1(val); /* get the string and length */ string = xlgastring(); str = getstring(string); len = getslength(string) - 1; /* get the starting offset */ if (moreargs()) { val = xlgafixnum(); start = (int)getfixnum(val); } else start = 0; /* get the ending offset */ if (moreargs()) { /* TAA mod to allow NIL for end offset */ val = nextarg(); if (val == NIL) end = len; else if (fixp(val)) end = (int)getfixnum(val); else xlbadtype(val); } else end = len; xllastarg(); /* check the bounds */ if (start < 0 || start > len) xlerror("string index out of bounds",cvfixnum((FIXTYPE)start)); if (end < 0 || end > len) xlerror("string index out of bounds",cvfixnum((FIXTYPE)end)); /* make the stream */ val = newustream(); /* copy the substring into the stream */ for (i = start; i < end; ++i) xlputc(val,str[i]); /* restore the stack */ xlpop(); /* return the new stream */ return (val); } /* xmkstroutput - make a string output stream */ LVAL xmkstroutput() { return (newustream()); } /* xgetstroutput - get output stream string */ LVAL xgetstroutput() { LVAL stream; stream = xlgaustream(); xllastarg(); return (getstroutput(stream)); } /* xgetlstoutput - get output stream list */ LVAL xgetlstoutput() { LVAL stream,val; /* get the stream */ stream = xlgaustream(); xllastarg(); /* get the output character list */ val = gethead(stream); /* empty the character list */ sethead(stream,NIL); settail(stream,NIL); /* return the list */ return (val); } #ifdef ENHFORMAT /* decode prefix parameters and modifiers for a format directive */ #ifdef ANSI static char *decode_pp(char *fmt, FIXTYPE *pp, int maxnpp, int *npp, int *colon, int *atsign) #else LOCAL char *decode_pp( fmt, pp, maxnpp, npp, colon, atsign ) char *fmt; FIXTYPE pp[]; /* prefix parameters */ int maxnpp; /* maximum number of them */ int *npp; /* actual number of them */ int *colon; /* colon modifier given? */ int *atsign; /* atsign modifier given? */ #endif { int gotpp = 0; /* set to 1 when pp encountered */ *npp = 0; *colon = 0; *atsign = 0; pp[0] = 0; do { if( *fmt == ':' ) *colon = 1; else if( *fmt == '@' ) *atsign = 1; else if( *colon || *atsign ) /* nothing else may follow : or @ */ break; else if( isdigit(*fmt) ) { pp[*npp] = (pp[*npp] * 10) + (int)(*fmt - '0'); gotpp = 1; } else if( *fmt == ',' ) { if( ++(*npp) >= maxnpp ) xlerror("too many prefix parameters in format",cvstring(fmt)); pp[*npp] = 0; gotpp = 1; } else if( *fmt == '\'' ) { pp[*npp] = *(++fmt); gotpp = 1; } else if( *fmt == 'v' || *fmt == 'V' ) { pp[*npp] = getfixnum(xlgafixnum()); gotpp = 1; } else break; fmt++; } while( 1 ); *npp += gotpp; /* fix up the count */ return fmt; } #define mincol pp[0] #define colinc pp[1] #define minpad pp[2] #define padchar pp[3] /* opt_print - print a value using prefix parameter options */ #ifdef ANSI static VOID opt_print(LVAL stream, LVAL val, int pflag, FIXTYPE *pp, int npp, int colon, int atsign) #else LOCAL VOID opt_print(stream,val,pflag,pp,npp,colon,atsign) LVAL stream; LVAL val; int pflag; /* quoting or not */ FIXTYPE pp[]; /* prefix parameters */ int npp; /* number of them */ int colon; /* colon modifier given? */ int atsign; /* at-sign modifier given? */ #endif { int flatsize; int i; switch( npp ) { /* default values of prefix parameters */ case 0: mincol = 0; /* see CLtL, page 387 */ case 1: colinc = 1; case 2: minpad = 0; case 3: padchar = ' '; } if( colinc <= 1 ) colinc = 1; if( mincol < minpad ) mincol = minpad; if( mincol > 0 && atsign ) { /* padding may be required on left */ xlfsize = 0; xlprint(NIL,val,pflag); /* print to get the flat size */ flatsize = xlfsize; for( i = 0; i < minpad; flatsize++, i++ ) xlputc(stream,(int)padchar); while( flatsize < mincol ) { for( i = 0; i < colinc; i++ ) xlputc(stream,(int)padchar); flatsize += (int)colinc; } } xlfsize = 0; /* print the value */ if( colon && val == NIL ) xlputstr(stream,"()"); else xlprint(stream,val,pflag); flatsize = xlfsize; if( mincol > 0 && !atsign ) { /* padding required on right */ for( i = 0; i < minpad; flatsize++, i++ ) xlputc(stream,(int)padchar); while( flatsize < mincol ) { for( i = 0; i < colinc; i++ ) xlputc(stream,(int)padchar); flatsize += (int)colinc; } } } #define MAXNPP 4 #endif /* xformat - formatted output function */ LVAL xformat() { char *fmt; LVAL stream,val; int ch; #ifdef ENHFORMAT int npp; /* number of prefix parameters */ FIXTYPE pp[MAXNPP]; /* list of prefix parameters */ int colon, atsign; /* : and @ modifiers given? */ #endif xlsave1(val); /* TAA fix */ /* get the stream and format string */ stream = xlgetarg(); if (stream == NIL) { val = stream = newustream(); } else { if (stream == true) stream = getvalue(s_stdout); /* fix from xlispbug.417 */ else if (streamp(stream)) { /* copied from xlgetfile() */ if (getfile(stream) == NULL) xlfail("file not open"); } else if (!ustreamp(stream)) xlbadtype(stream); val = NIL; } fmt = getstring(xlgastring()); /* process the format string */ while ((ch = *fmt++) != 0) if (ch == '~') { #ifdef ENHFORMAT fmt = decode_pp( fmt, pp, MAXNPP, &npp, &colon, &atsign ); #endif switch (*fmt++) { case '\0': xlerror("expecting a format directive",cvstring(fmt-1)); case 'a': case 'A': #ifdef ENHFORMAT opt_print(stream,xlgetarg(),FALSE,pp,npp,colon,atsign); #else xlprint(stream,xlgetarg(),FALSE); #endif break; case 's': case 'S': #ifdef ENHFORMAT opt_print(stream,xlgetarg(),TRUE,pp,npp,colon,atsign); #else xlprint(stream,xlgetarg(),TRUE); #endif break; case '%': #ifdef ENHFORMAT if( pp[0] <= 0 ) pp[0] = 1; while( (pp[0])-- > 0 ) xlterpri(stream); #else xlterpri(stream); #endif break; case '~': #ifdef ENHFORMAT if( pp[0] <= 0 ) pp[0] = 1; while( (pp[0])-- > 0 ) xlputc(stream,'~'); #else xlputc(stream,'~'); #endif break; case '\n': #ifdef ENHFORMAT if( colon ) break; if( atsign ) xlterpri(stream); #endif while (*fmt && *fmt != '\n' && isspace(*fmt)) ++fmt; break; default: xlerror("unknown format directive",cvstring(fmt-1)); } } else xlputc(stream,ch); /* unprotect */ xlpop(); /* return the value */ return (val ? getstroutput(val) : NIL); } /* getstroutput - get the output stream string (internal) */ LOCAL LVAL getstroutput(stream) LVAL stream; { char *str; LVAL next,val; int len,ch; /* compute the length of the stream */ for (len = 0, next = gethead(stream); next != NIL; next = cdr(next)) ++len; /* create a new string */ val = newstring(len + 1); /* copy the characters into the new string */ str = getstring(val); while ((ch = xlgetc(stream)) != EOF) *str++ = ch; *str = '\0'; /* return the string */ return (val); }