/* xlfio.c - xlisp file i/o */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 30Sep06 rbd added xbigendianp * 28Apr03 dm eliminate some compiler warnings */ #include "switches.h" #include #include "xlisp.h" /* do some sanity checking: */ #ifndef XL_BIG_ENDIAN #ifndef XL_LITTLE_ENDIAN configuration error -- either XL_BIG_ or XL_LITTLE_ENDIAN must be defined in xlisp.h #endif #endif #ifdef XL_BIG_ENDIAN #ifdef XL_LITTLE_ENDIAN configuration error -- both XL_BIG_ and XL_LITTLE_ENDIAN are defined! #endif #endif /* forward declarations */ FORWARD LOCAL LVAL getstroutput(LVAL stream); FORWARD LOCAL LVAL printit(int pflag, int tflag); FORWARD LOCAL LVAL flatsize(int pflag); /* xread - read an expression */ LVAL xread(void) { LVAL fptr,eof,rflag,val; /* get file pointer and eof value */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); eof = (moreargs() ? xlgetarg() : NIL); rflag = (moreargs() ? xlgetarg() : NIL); xllastarg(); /* read an expression */ if (!xlread(fptr,&val,rflag != NIL)) val = eof; /* return the expression */ return (val); } /* xprint - built-in function 'print' */ LVAL xprint(void) { return (printit(TRUE,TRUE)); } /* xprin1 - built-in function 'prin1' */ LVAL xprin1(void) { return (printit(TRUE,FALSE)); } /* xprinc - built-in function princ */ LVAL xprinc(void) { return (printit(FALSE,FALSE)); } /* xterpri - terminate the current print line */ LVAL xterpri(void) { 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(int pflag, int 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(void) { return (flatsize(TRUE)); } /* xflatc - compute the size of a printed representation using princ */ LVAL xflatc(void) { return (flatsize(FALSE)); } /* flatsize - compute the size of a printed expression */ LOCAL LVAL flatsize(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)); } /* xlopen - open a text or binary file */ LVAL xlopen(int binaryflag) { char *name,*mode=NULL; FILE *fp; LVAL dir; /* get the file name and direction */ name = (char *)getstring(xlgetfname()); if (!xlgetkeyarg(k_direction,&dir)) dir = k_input; /* get the mode */ if (dir == k_input) mode = "r"; else if (dir == k_output) mode = "w"; else xlerror("bad direction",dir); /* try to open the file */ if (binaryflag) { fp = osbopen(name,mode); } else { fp = osaopen(name,mode); } return (fp ? cvfile(fp) : NIL); } /* xopen - open a file */ LVAL xopen(void) { return xlopen(FALSE); } /* xbopen - open a binary file */ LVAL xbopen(void) { return xlopen(TRUE); } /* xclose - close a file */ LVAL xclose(void) { 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(void) { 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)); } /* xrdint - read an integer from a file */ /* positive byte count means big-endian, negative is little-endian */ LVAL xrdint(void) { LVAL fptr; unsigned char b[4]; long i; int n = 4; int index = 0; /* where to start in array */ int incr = 1; /* how to step through array */ int rslt; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); /* get byte count */ if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = n - 1; incr = -1; } if (n > 4) { xlerror("4-byte limit", count); } } xllastarg(); for (i = 0; i < n; i++) { int ch = xlgetc(fptr); if (ch == EOF) return NIL; b[index] = ch; index += incr; } /* build result, b is now big-endian */ /* extend sign bit for short integers */ rslt = ((b[0] & 0x80) ? -1 : 0); for (i = 0; i < n; i++) { rslt = (rslt << 8) + b[i]; } /* return integer result */ return cvfixnum(rslt); } /* xrdfloat - read a float from a file */ LVAL xrdfloat(void) { LVAL fptr; union { char b[8]; float f; double d; } rslt; int n = 4; int i; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); /* get byte count */ if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = 0; incr = 1; } if (n != 4 && n != 8) { xlerror("must be 4 or 8 bytes", count); } } xllastarg(); #ifdef XL_BIG_ENDIAN /* flip the bytes */ index = n - 1 - index; incr = -incr; #endif for (i = 0; i < n; i++) { int ch = xlgetc(fptr); if (ch == EOF) return NIL; rslt.b[index] = ch; index += incr; } /* return result */ return cvflonum(n == 4 ? rslt.f : rslt.d); } /* xrdbyte - read a byte from a file */ LVAL xrdbyte(void) { 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(void) { 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(void) { 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(void) { 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); } /* xwrint - write an integer to a file */ /* positive count means write big-endian */ LVAL xwrint(void) { LVAL val, fptr; unsigned char b[4]; long i; int n = 4; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ int v; /* get the int and file pointer and optional byte count */ val = xlgafixnum(); v = getfixnum(val); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); index = n - 1; if (n < 0) { n = -n; index = 0; incr = 1; } if (n > 4) { xlerror("4-byte limit", count); } } xllastarg(); /* build output b as little-endian */ for (i = 0; i < n; i++) { b[i] = (unsigned char) v; v = v >> 8; } /* put bytes to the file */ while (n) { n--; xlputc(fptr, b[index]); index += incr; } /* return the integer */ return val; } /* xwrfloat - write a float to a file */ LVAL xwrfloat(void) { LVAL val, fptr; union { char b[8]; float f; double d; } v; int n = 4; int i; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ /* get the float and file pointer and optional byte count */ val = xlgaflonum(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = 0; incr = 1; } if (n != 4 && n != 8) { xlerror("must be 4 or 8 bytes", count); } } xllastarg(); #ifdef XL_BIG_ENDIAN /* flip the bytes */ index = n - 1 - index; incr = -incr; #endif /* build output v.b */ if (n == 4) v.f = (float) getflonum(val); else v.d = getflonum(val); /* put bytes to the file */ for (i = 0; i < n; i++) { xlputc(fptr, v.b[index]); index += incr; } /* return the flonum */ return val; } /* xreadline - read a line from a file */ LVAL xreadline(void) { unsigned 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 = new_string(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 = new_string(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(void) { int start,end,len,i; unsigned 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()) { val = xlgafixnum(); end = (int)getfixnum(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(void) { return (newustream()); } /* xgetstroutput - get output stream string */ LVAL xgetstroutput(void) { LVAL stream; stream = xlgaustream(); xllastarg(); return (getstroutput(stream)); } /* xgetlstoutput - get output stream list */ LVAL xgetlstoutput(void) { 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); } /* xformat - formatted output function */ LVAL xformat(void) { unsigned char *fmt; LVAL stream,val; int ch; /* protect stream in case it is a new ustream */ xlsave1(stream); /* get the stream and format string */ stream = xlgetarg(); if (stream == NIL) val = stream = newustream(); else { if (stream == s_true) stream = getvalue(s_stdout); else if (!streamp(stream) && !ustreamp(stream)) xlbadtype(stream); val = NIL; } fmt = getstring(xlgastring()); /* process the format string */ while ((ch = *fmt++)) if (ch == '~') { switch (*fmt++) { case '\0': xlerror("expecting a format directive",cvstring((char *) (fmt-1))); case 'a': case 'A': xlprint(stream,xlgetarg(),FALSE); break; case 's': case 'S': xlprint(stream,xlgetarg(),TRUE); break; case '%': xlterpri(stream); break; case '~': xlputc(stream,'~'); break; case '\n': case '\r': /* mac may read \r -- this should be ignored */ if (*fmt == '\r') *fmt++; while (*fmt && *fmt != '\n' && isspace(*fmt)) ++fmt; break; default: xlerror("unknown format directive",cvstring((char *) (fmt-1))); } } else xlputc(stream,ch); /* return the value */ if (val) val = getstroutput(val); xlpop(); return val; } /* getstroutput - get the output stream string (internal) */ LOCAL LVAL getstroutput(LVAL stream) { unsigned 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 = new_string(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); } LVAL xlistdir(void) { char *path; LVAL result = NULL; LVAL *tail; /* get the path */ path = (char *)getstring(xlgetfname()); /* try to start listing */ if (osdir_list_start(path)) { char *filename; xlsave1(result); tail = &result; while (filename = osdir_list_next()) { *tail = cons(NIL, NIL); rplaca(*tail, cvstring(filename)); tail = &cdr(*tail); } osdir_list_finish(); xlpop(); } return result; } /* xbigendianp -- is this a big-endian machine? T or NIL */ LVAL xbigendianp() { #ifdef XL_BIG_ENDIAN return s_true; #else return NIL; #endif }