home *** CD-ROM | disk | FTP | other *** search
- /* 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 <math.h>
-
-
- #ifdef FILETABLE
- #include <errno.h>
- #endif
-
- /* external variables */
- extern LVAL k_direction,k_input,k_output;
- extern LVAL s_stdin,s_stdout,true;
- extern LVAL k_io, k_elementtype;
- extern LVAL a_fixnum, a_char;
- extern LVAL k_exist, k_nexist, k_error, k_rename, k_newversion;
- extern LVAL k_overwrite, k_append, k_supersede, k_rendel, k_probe, k_create;
- extern LVAL k_start, k_end;
- extern int xlfsize;
-
-
- /* forward declarations */
- #ifdef ANSI
- #ifdef SERVER
- LVAL getstroutput(LVAL stream);
- #else
- LVAL XNEAR getstroutput(LVAL stream);
- #endif
- LVAL XNEAR printit(int pflag, int tflag);
- LVAL XNEAR 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(FALSE) : getvalue(s_stdin));
- eof = (moreargs() ? xlgetarg() : NIL);
- if (xlargc > 1) xltoomany(); /* toss out now unused arg */
-
- /* 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));
- }
-
- /* xfreshline - start a new line if not at begining of line */
- LVAL xfreshline()
- {
- LVAL fptr;
-
- /* get file pointer */
- fptr = (moreargs() ? xlgetfile(TRUE) : getvalue(s_stdout));
- xllastarg();
-
- /* optionally terminate the print line and return action */
- return (xlfreshline(fptr)? true : NIL);
- }
-
-
- /* xterpri - terminate the current print line */
- LVAL xterpri()
- {
- LVAL fptr;
-
- /* get file pointer */
- fptr = (moreargs() ? xlgetfile(TRUE) : getvalue(s_stdout));
- xllastarg();
-
- /* terminate the print line and return nil */
- xlterpri(fptr);
- return (NIL);
- }
-
- /* printit - common print function */
- LOCAL LVAL XNEAR printit(pflag,tflag)
- int pflag,tflag;
- {
- LVAL fptr,val;
-
- /* get expression to print and file pointer */
- val = xlgetarg();
- fptr = (moreargs() ? xlgetfile(TRUE) : 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 XNEAR 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));
- }
-
-
- enum ACTIONS {A_NIL, A_ERR, A_REN, A_OVER, A_APP, A_SUPER, A_CREATE};
-
- /* xopen - open a file */
- LVAL xopen()
- {
- #ifdef MEDMEM
- char name[STRMAX];
- #else
- char *name; /* file name strings */
- #endif
- FILEP fp; /* opened file pointer */
- LVAL fname; /* file name string LVAL */
- LVAL temp; /* key arguments */
- int iomode; /* file mode, as stored in node */
- #ifdef ANSI
- /* There doesn't seem to be any consistancy here in the handling of
- "CDECL" when dealing with pointers to procedures TAA */
- #ifdef FILETABLE
- FILEP (*opencmd)(const char *, MODETYPE);
- #else
- #ifdef __TURBOC__
- FILEP CDECL (*opencmd)(const char *, MODETYPE);
- /* file type, TRUE if binary */
- #else
- FILEP (* CDECL opencmd)(const char *, MODETYPE);
- #endif
- #endif
- #else /* not ANSI */
- FILEP (*opencmd)(); /* file type, TRUE if binary */
- #endif
- enum ACTIONS exist; /* exist action */
- enum ACTIONS nexist;/* non-exist action */
-
- /* get file name */
- #ifdef MEDMEM
- MEMCPY(name, getstring(fname = xlgetfname()), STRMAX);
- name[STRMAX-1] = 0;
- #else
- name = getstring(fname = xlgetfname());
- #endif
-
- /* get direction */
- if (xlgetkeyarg(k_direction,&temp) && temp != k_input) {
- if (temp == k_output) iomode = S_FORWRITING;
- else if (temp == k_io) iomode = S_FORREADING|S_FORWRITING;
- else if (temp == k_probe) iomode = 0;
- else goto argerror;
- }
- else iomode = S_FORREADING;
-
- /* get type */
-
- if (xlgetkeyarg(k_elementtype,&temp) && temp != a_char ) {
- if (temp == a_fixnum ) {
- if (iomode) iomode |= S_BINARY; /* mark as binary file type */
- #if defined(MSC) & !defined(FILETABLE)
- opencmd = (FILEP (* CDECL)(const char *, MODETYPE)) OSBOPEN;
- #else
- opencmd = OSBOPEN;
- #endif
- }
- else goto argerror;
- }
- else
- #if defined(MSC) & !defined(FILETABLE)
- opencmd = (FILEP (* CDECL)(const char *, MODETYPE)) OSAOPEN;
- #else
- opencmd = OSAOPEN;
- #endif
-
- /* get exists action */
-
- if (xlgetkeyarg(k_exist, &temp) &&
- (iomode & S_FORWRITING) && /* ignore value if :input or :probe */
- temp != k_rename && temp != k_newversion) {
- if (null(temp)) exist = A_NIL;
- else if (temp == k_error) exist = A_ERR;
- else if (temp == k_overwrite) exist = A_OVER;
- else if (temp == k_append) exist = A_APP;
- else if (temp == k_supersede || temp == k_rendel)
- exist = A_SUPER;
- else goto argerror;
- }
- else exist = A_REN;
-
- /* get non-exist action */
-
- if (xlgetkeyarg(k_nexist, &temp)) {
- if (null(temp)) nexist = A_NIL;
- else if (temp == k_error) nexist = A_ERR;
- else if (temp == k_create) nexist = A_CREATE;
- else goto argerror;
- }
- else { /* handle confusing mess of defaults */
- if (iomode == S_FORREADING || exist == A_OVER || exist == A_APP)
- nexist = A_ERR;
- else if (iomode & S_FORWRITING) nexist = A_CREATE;
- else nexist = A_NIL;
- }
-
- xllastarg();
-
- /* attempt to open the file */
-
- if ((fp = (*opencmd)(name, (iomode & S_FORWRITING) ? OPEN_UPDATE : OPEN_RO))!=CLOSED) {
- /* success! */
- if (iomode & S_FORWRITING) switch (exist) { /* do exist action */
- case A_ERR: /* give error */
- OSCLOSE(fp);
- xlerror("file exists", fname);
- break;
- case A_REN: /* create new version */
- OSCLOSE(fp);
- fp = CLOSED;
- if (!renamebackup(name))
- xlerror("couldn't create backup file", fname);
- break;
- case A_APP: /* position to end of file */
- OSSEEKEND(fp);
- break;
- case A_SUPER: /* supersede file */
- OSCLOSE(fp);
- fp = CLOSED;
- break;
- case A_NIL: /* return NIL */
- OSCLOSE(fp);
- return NIL;
- /*case A_OVER:*/ /* overwrite -- does nothing special */
- default: ;
- }
- }
- else { /* file does not exist */
- switch (nexist) {
- case A_ERR: /* give error */
- xlerror("file does not exist", fname);
- break;
- case A_NIL: /* return NIL */
- return NIL;
- /*case A_CREATE:*/ /* create a new file */
- default: ;
- }
- }
-
- /* we now create the file if it is not already open */
- if (fp == CLOSED)
- if ((fp = (*opencmd)(name, (iomode&S_FORREADING)? CREATE_UPDATE: CREATE_WR)) == CLOSED)
- xlerror("couldn't create file", fname);
-
- /* take concluding actions */
- if (iomode == 0) { /* probe */
- OSCLOSE(fp);
- fp = CLOSED;
- }
-
- return cvfile(fp,iomode);
-
- argerror: xlerror("invalid argument", temp);
- return NIL;
- }
-
-
- /* xfileposition - get position of file stream */
- LVAL xfileposition()
- {
- long i,j,fsize;
- int t;
- LVAL pos, fptr;
- FILEP fp;
- /* get file pointer */
- fp = getfile(fptr = xlgastream());
-
- /* make sure the file exists */
- if (fp == CLOSED)
- xlfail("file not open");
-
- /* get current position, adjusting for posible "unget" */
- j = OSTELL(fp) + (getsavech(fptr) ? -1L : 0L);
-
- if (moreargs()) { /* must be set position */
- pos = xlgetarg();
- xllastarg();
- if (pos == k_end) t=OSSEEKEND(fp);
- else if (pos == k_start) t=OSSEEK(fp,0L);
- else if (fixp(pos)) { /* check for in range, then position */
- /* STDIO allows positioning beyond end of file, so we must check
- the file size (boo his!) */
- i = getfixnum(pos);
- t = OSSEEKEND(fp);
- fsize = OSTELL(fp);
- if (t == 0 && fp != CONSOLE && (i < 0 || i > fsize)) {
- OSSEEK(fp,j);
- xlerror("position outside of file", pos);
- }
- t = OSSEEK(fp, i);
- }
- else xlbadtype(pos);
-
- setsavech(fptr,'\0'); /* toss unget character, if any */
- fptr->n_sflags &= ~(S_READING|S_WRITING);
- /* neither reading or writing currently */
- /* t is non-zero if couldn't do seek */
- return (t != 0 || fp == CONSOLE ? NIL : true);
- }
-
- return ((j == -1L || fp == CONSOLE) ? NIL : cvfixnum(j));
- }
-
- /* xfilelength - returns length of file */
- LVAL xfilelength()
- {
- FILEP fp;
- long i,j;
-
- /* get file pointer */
- fp = getfile(xlgastream());
- xllastarg();
-
- /* make sure the file exists */
- if (fp == CLOSED)
- xlfail("file not open");
-
- /* not all stdio packages will catch the following gaffe */
- if (fp == CONSOLE) return NIL;
-
- if ((i=OSTELL(fp)) == -1L ||
- OSSEEKEND(fp) ||
- (j = OSTELL(fp)) == -1L ||
- OSSEEK(fp,i)) {
- return NIL;
- }
-
- return cvfixnum(j);
- }
-
-
- #ifdef FILETABLE
- LVAL xtruename()
- {
- LVAL f = xlgetfname();
- char namebuf[FNAMEMAX+1];
-
- xllastarg();
-
-
- STRCPY(buf, getstring(f));
-
- if (!truename(buf, namebuf)) xlerror("strange file name", f);
-
- return cvstring(namebuf);
- }
-
- LVAL xdeletefile()
- {
- LVAL arg;
- FILEP fp;
-
- /* get the argument */
-
- arg = xlgetarg();
- xllastarg();
-
- if (streamp(arg) && getfile(arg) > CONSOLE) {
- /* close file first */
- fp = getfile(arg);
- STRCPY(buf, filetab[fp].tname);
- OSCLOSE(fp);
- setsavech(arg, '\0');
- setfile(arg,CLOSED);
- }
- else {
- if (symbolp(arg)) arg = getpname(arg);
- else if (!stringp(arg)) xlbadtype(arg);
-
- if (getslength(arg) >= FNAMEMAX)
- xlerror("file name too long", arg);
-
- STRCPY(buf,getstring(arg));
- }
- if (remove(buf) != 0 && errno == EACCES)
- xlerror("cannot delete file", arg);
-
- return true;
- }
-
- #endif
-
- /* xclose - close a file */
- LVAL xclose()
- {
- LVAL fptr;
- FILEP fp; /* TAA MOD to allow closing closed files,
- prohibit closing the console, return the correct
- values (true on success), and close string streams */
-
-
- /* get file pointer */
- fptr = xlgetarg();
- xllastarg();
-
- /* handle string stream case by converting to a closed file! */
- if (ustreamp(fptr)) {
- fptr->n_type = STREAM;
- setfile(fptr, CLOSED);
- setsavech(fptr, '\0');
- return (true);
- }
-
- /* give error of not file stream */
- if (!streamp(fptr)) xlbadtype(fptr);
-
-
- /* make sure the file exists */
-
- if ((fp = getfile(fptr)) == CLOSED || fp == CONSOLE)
- return (NIL);
-
- /* close the file */
- OSCLOSE(fp);
- setsavech(fptr, '\0');
- setfile(fptr,CLOSED);
-
- /* return true */
- return (true);
- }
-
- /* xrdchar - read a character from a file */
- LVAL xrdchar()
- {
- LVAL fptr;
- int ch;
-
- /* get file pointer */
- fptr = (moreargs() ? xlgetfile(FALSE) : 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(FALSE) : 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(FALSE) : getvalue(s_stdin));
- xllastarg();
-
- /* skip leading white space and get a character */
- if (!null(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(TRUE) : 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(TRUE) : 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 *p, XFAR *sptr;
- LVAL fptr,str,newstr;
- int len,blen,ch;
-
- /* protect some pointers */
- xlsave1(str);
-
- /* get file pointer */
- fptr = (moreargs() ? xlgetfile(FALSE) : 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 TAA MOD to use memcpy instead of strcat*/
- if (blen >= STRMAX) {
- newstr = newstring(len + STRMAX);
- sptr = getstring(newstr);
- if (str != NIL) MEMCPY(sptr, getstring(str), len);
- MEMCPY(sptr+len, buf, blen);
- 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 */
- /* conditional removed because code always executes! */
- newstr = newstring(len + blen);
- sptr = getstring(newstr);
- if (str != NIL) MEMCPY(sptr, getstring(str), len);
- MEMCPY(sptr+len, buf, blen);
- sptr[len+blen] = '\0';
- str = newstr;
-
- /* restore the stack */
- xlpop();
-
- /* return the string */
- return (str);
- }
-
-
- /* xmkstrinput - make a string input stream */
- /* TAA MOD - reworked for unsigned lengths */
-
- LVAL xmkstrinput()
- {
- unsigned start,end,len,i;
- FIXTYPE temp;
- char XFAR *str;
- LVAL string,val;
-
- /* protect the return value */
- xlsave1(val);
-
- /* get the string and length */
- string = xlgastring();
- str = getstring(string);
- len = getslength(string);
-
- /* get the starting offset */
- if (moreargs()) {
- val = xlgafixnum();
- temp = getfixnum(val);
- if (temp < 0 || temp > len)
- xlerror("string index out of bounds",val);
- start = (unsigned) temp;
- }
- else start = 0;
-
- /* get the ending offset */
- if (moreargs()) { /* TAA mod to allow NIL for end offset */
- val = nextarg();
- if (null(val)) end = len;
- else if (fixp(val)) {
- temp = getfixnum(val);
- if (temp < start || temp > len)
- xlerror("string index out of bounds",val);
- end = (unsigned) temp;
- }
- else xlbadtype(val);
-
- xllastarg();
- }
- else end = len;
-
- /* 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);
- }
-
-
- #define FMTMAX 256
- #ifdef ANSI
- static void toomanyopt(LVAL fmt)
- #else
- static VOID toomanyopt(fmt)
- LVAL fmt;
- #endif
- {
- xlerror("too many prefix parameters in format",fmt);
- }
-
- /* decode prefix parameters and modifiers for a format directive */
- /* TAA MOD Entirely rewritten -- return value -1 for unassigned since
- negative numbers are inappropriate for all arguments we are concerned
- with. Also clips args to reasonable values, allows both : and @ modifiers
- at once. */
- #ifdef ANSI
- static char XFAR * XNEAR decode_pp(char XFAR *fmt, FIXTYPE *pp, int maxnpp,
- int *npp, int *colon, int *atsign, LVAL lfmt)
- #else
- LOCAL char *decode_pp( fmt, pp, maxnpp, npp, colon, atsign, lfmt)
- 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? */
- LVAL lfmt; /* format string in case of failure */
- #endif
- {
- int i;
- int gotone = 0;
- FIXTYPE accum;
-
- for (i = 0; i < maxnpp; i++) pp[i] = -1; /* initially all undefined */
- *npp = 0;
- *colon = 0;
- *atsign = 0;
- do {
- if (*fmt == '\'') { /* character code */
- pp[*npp] = *(++fmt);
- gotone = 1;
- fmt++;
- }
- else if (*fmt == 'v' || *fmt == 'V') { /* lisp arg is value */
- accum = getfixnum(xlgafixnum());
- if (accum < 0) accum = 0; /* clip at reasonable values */
- else if (accum>FMTMAX) accum = FMTMAX;
- pp[*npp] = accum;
- gotone = 1;
- fmt++;
- }
- else if (isdigit(*fmt)) { /* integer literal */
- accum = 0;
- do {
- accum = accum*10 + (int)(*fmt++ - '0');
- if (accum > FMTMAX)
- accum = FMTMAX; /* Clip at reasonable value */
- } while (isdigit(*fmt));
- gotone = 1;
- pp[*npp] = accum;
- }
- else if (*fmt == ',') { /* empty field */
- gotone = 1;
- }
- else break; /* nothing to process */
-
- if (*fmt != ',') break; /* no comma -- done */
- *npp += 1; /* got an argument */
- fmt++; /* toss comma */
- if( *npp >= maxnpp ) toomanyopt(lfmt);
- } while (TRUE);
- *npp += gotone;
-
- do { /* pick up any colon or atsign modifier */
- if (*fmt == ':') *colon = 1;
- else if (*fmt == '@') *atsign = 1;
- else break;
- fmt++;
- } while (TRUE);
- 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 XNEAR opt_print(LVAL stream, LVAL val, int pflag, FIXTYPE *pp,
- int colon, int atsign)
- #else
- LOCAL VOID opt_print(stream,val,pflag,pp,colon,atsign)
- LVAL stream;
- LVAL val;
- int pflag; /* quoting or not */
- FIXTYPE pp[]; /* prefix parameters */
- int colon; /* colon modifier given? */
- int atsign; /* at-sign modifier given? */
- #endif
- {
- int flatsize;
- int i;
-
- if (mincol < 0) mincol = 0; /* handle default values */
- if (colinc < 1) colinc = 1; /* also arg of 0 for colinc */
- if (minpad < 0) minpad = 0;
- if (padchar < 0) padchar = ' ';
-
- if( mincol < minpad )
- mincol = minpad;
-
- if( mincol > 0 && atsign ) { /* padding may be required on left */
- if (colon && null(val)) /* flat size is 2 */
- flatsize = 2;
- else {
- 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;
- }
- }
-
- /* print the value */
- if( colon && null(val)) {
- xlputstr(stream,"()");
- flatsize = 2;
- }
- else {
- xlfsize = 0;
- 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 round pp[1]
- #ifdef ANSI
- static VOID XNEAR num_print(LVAL stream,LVAL val,int pflag,FIXTYPE *pp,int atsign)
- #else
- LOCAL VOID num_print(stream,val,pflag,pp,atsign)
- LVAL stream;
- LVAL val;
- int pflag; /* quoting or not */
- FIXTYPE pp[]; /* prefix parameters */
- int atsign; /* at-sign modifier given? */
- #endif
- {
- char cmd[50];
- int fillchar, i;
-
- fillchar = (int)pp[(pflag=='D'? 1 : 2)];
-
- if (fillchar < 0) fillchar = ' ';
-
- if (pflag == 'D' && fixp(val)) { /* ~d and fixnum */
- sprintf(buf, (atsign?"%+ld":"%ld"), (long) getfixnum(val));
- }
- else if (pflag == 'D' || !numberp(val)) { /* not a number */
- padchar = colinc = minpad = -1; /* zap arg if provided */
- opt_print(stream,val,FALSE,pp,0,0);
- return;
- }
- else { /* one of the floating point formats, and a number */
- #ifdef RATIOS
- FLOTYPE num;
- if (fixp(val)) num = (FLOTYPE)getfixnum(val);
- else if (ratiop(val)) num = getnumer(val) / (FLOTYPE) getdenom(val);
- else num = getflonum(val);
- #else
- FLOTYPE num = fixp(val) ? (FLOTYPE)getfixnum(val) : getflonum(val);
- #endif
- if (pflag == 'F' && fabs(num) > 1e100)
- pflag = 'E'; /* don't generate extra big number */
- strcpy(cmd,"%");
- if (atsign) strcat(cmd,"+");
- if (round >= 0) {
- sprintf(buf, ".%d", (int) round);
- strcat(cmd, buf);
- }
- buf[0] = tolower(pflag);
- buf[1] = '\0';
- strcat(cmd,buf);
- sprintf(buf, cmd, (double)num);
- }
- if (mincol > 0) { /* need to fill */
- for (i = (int)mincol-strlen(buf); i-- > 0;)
- xlputc(stream,fillchar);
- }
- xlputstr(stream,buf);
- }
-
- #undef colinc
- /* tabulate */
- #ifdef ANSI
- static void XNEAR tab_print(LVAL stream, FIXTYPE *pp, int atsign)
- #else
- LOCAL VOID tab_print(stream, pp, atsign)
- LVAL stream;
- FIXTYPE pp[];
- int atsign;
- #endif
- {
- int pos = xlgetcolumn(stream); /* where are we now??? */
- int count; /* number of spaces to insert */
- int column = (int)pp[0]; /* desired column */
- int colinc = (int)pp[1]; /* desired column increment */
-
- if (column < 0) column = 1; /* handle defaults */
- if (colinc < 0) colinc = 1;
-
- if (atsign) { /* relative */
- if (colinc == 0) colinc = 1;
- count = column + (colinc - (pos + column) % colinc) % colinc;
- }
- else { /* absolute */
- if (pos >= column) {
- if (colinc > 0) {
- int k = (pos+ (colinc-1) - column)/colinc;
- count = column-pos + k*colinc;
- if (count==0) count = colinc;
- }
- else count = 0;
- }
- else count = column - pos;
- }
- while (count-- > 0)
- xlputc(stream, ' ');
- }
-
- #define MAXNPP 4
-
-
- /* xformat - formatted output function */
- LVAL xformat()
- {
- char XFAR *fmt;
- LVAL stream,val;
- int ch;
- LVAL lfmt;
- int npp; /* number of prefix parameters */
- FIXTYPE pp[MAXNPP]; /* list of prefix parameters */
- int colon, atsign; /* : and @ modifiers given? */
-
- xlsave1(val); /* TAA fix */
-
- /* get the stream and format string */
- stream = xlgetarg();
- if (null(stream)) {
- 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) == CLOSED)
- xlfail("file not open");
- }
- else if (!ustreamp(stream))
- xlbadtype(stream);
- val = NIL;
- }
- fmt = getstring(lfmt=xlgastring());
-
- /* process the format string */
- while ((ch = *fmt++) != 0)
- if (ch == '~') {
- fmt = decode_pp( fmt, pp, MAXNPP, &npp, &colon, &atsign, lfmt);
- ch = *fmt++;
- if (islower(ch)) ch = toupper(ch);
- switch (ch) {
- case '\0':
- xlerror("expecting a format directive",cvstring(fmt-1));
- case 'A':
- opt_print(stream,xlgetarg(),FALSE,pp,colon,atsign);
- break;
- case 'S':
- opt_print(stream,xlgetarg(),TRUE,pp,colon,atsign);
- break;
- case 'D':
- if (npp > 2) toomanyopt(lfmt);
- case 'E': case 'F': case 'G':
- if (npp > 3) toomanyopt(lfmt);
- num_print(stream,xlgetarg(),ch,pp,atsign);
- break;
- case '&':
- if ( pp[0] < 0 ) pp[0] = 1;
- if ((pp[0])-- > 0)
- xlfreshline(stream);
- while( (pp[0])-- > 0 )
- xlterpri(stream);
- break;
- case 'T':
- tab_print(stream,pp,atsign);
- break;
- case '%':
- if( pp[0] < 0 ) pp[0] = 1;
- while( (pp[0])-- > 0 )
- xlterpri(stream);
- break;
- case '~':
- if( pp[0] <= 0 ) pp[0] = 1;
- while( (pp[0])-- > 0 )
- xlputc(stream,'~');
- break;
- case '\n':
- if( colon )
- break;
- if( atsign )
- xlterpri(stream);
- while (*fmt && *fmt != '\n' && isspace(*fmt))
- ++fmt;
- break;
- default:
- xlerror("unknown format directive",cvstring(fmt-1));
- }
- }
- else
- xlputc(stream,ch);
-
- /* get string if output to string */
- if (!null(val)) val = getstroutput(val);
-
- /* unprotect */
- xlpop();
-
- /* return the value */
- return val;
- }
-
-
- /* getstroutput - get the output stream string (internal) */
- #ifdef SERVER
- LVAL getstroutput(stream)
- LVAL stream;
- #else
- LOCAL LVAL XNEAR getstroutput(stream)
- LVAL stream;
- #endif
- {
- char XFAR *str;
- LVAL next,val;
- unsigned len; /* TAA MOD */
- int ch;
-
- /* compute the length of the stream */
- for (len = 0, next = gethead(stream); !null(next); next = cdr(next)) {
- if (++len > MAXSLEN) xltoolong(); /* TAA MOD addition for overflow detect */
- }
-
- /* create a new string */
- val = newstring(len);
-
- /* copy the characters into the new string */
- str = getstring(val);
- while ((ch = xlgetc(stream)) != EOF)
- *str++ = ch;
- *str = '\0';
-
- /* return the string */
- return (val);
- }
-
-