1 /* xlfio.c - xlisp file i/o */
2 /* Copyright (c) 1989, by David Michael Betz. */
3 /* You may give out copies of this software; for conditions see the file */
4 /* COPYING included with this distribution. */
17 /* forward declarations */
18 LOCAL LVAL printit
P2H(int, int);
19 LOCAL FIXTYPE flatsize
P2H(LVAL
, int);
20 LOCAL FILEP opencmd
P3H(char *, char *, int);
21 LOCAL VOID toomanyopt
P1H(LVAL
);
22 LOCAL
char * skip_pp
P3H(char *, int *, int *);
23 LOCAL
char * decode_pp
P7H(char *, FIXTYPE
*, int, int *, int *, int *, LVAL
);
24 LOCAL VOID opt_print
P6H(LVAL
, LVAL
, int, FIXTYPE
*, int, int);
25 LOCAL
int trimzeros
P2H(char *, int);
26 LOCAL
int allzeros
P1H(char *);
27 LOCAL VOID write_double_ffmt
P4H(char *, double, int, int);
28 LOCAL VOID integer_print
P5H(LVAL
, LVAL
, int, FIXTYPE
*,int);
29 LOCAL VOID flonum_fprint
P4H(LVAL
, LVAL
, FIXTYPE
*,int);
30 LOCAL VOID flonum_eprint
P4H(LVAL
, LVAL
, FIXTYPE
*,int);
31 LOCAL VOID flonum_gprint
P4H(LVAL
, LVAL
, FIXTYPE
*,int);
32 LOCAL VOID tab_print
P3H(LVAL
, FIXTYPE
*, int);
33 LOCAL VOID indirect_print
P2H(LVAL
, int);
34 LOCAL VOID case_convert_print
P4H(char *, LVAL
, int, int);
35 LOCAL VOID conditional_print
P5H(char *, LVAL
, FIXTYPE
, int, int);
36 LOCAL VOID iterative_print
P5H(char *, LVAL
, FIXTYPE
, int, int);
37 LOCAL
char *skip_past_directive
P3H(char *, int, int);
39 /* xread - read an expression */
40 /* eof-error-p added - L. Tierney */
44 int eof_error_p
, recursive_p
= FALSE
;
46 /* get file pointer and eof value */
47 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
48 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
49 eof
= (moreargs() ? xlgetarg() : NIL
);
50 if (moreargs() && !null(xlgetarg())) recursive_p
= TRUE
;
53 /* read an expression */
54 if (!xlread(fptr
, &val
, recursive_p
, FALSE
)) {
55 if (eof_error_p
) xlfail("end of file on read");
59 /* return the expression */
63 /* TAA MOD 9/97 -- added read-preserving-whitespace */
67 int eof_error_p
, recursive_p
= FALSE
;
69 /* get file pointer and eof value */
70 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
71 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
72 eof
= (moreargs() ? xlgetarg() : NIL
);
73 if (moreargs() && !null(xlgetarg())) recursive_p
= TRUE
;
76 /* read an expression */
77 if (!xlread(fptr
, &val
, recursive_p
, TRUE
)) {
78 if (eof_error_p
) xlfail("end of file on read");
82 /* return the expression */
86 /* xprint - built-in function 'print' */
89 return (printit(TRUE
,TRUE
));
92 /* xprin1 - built-in function 'prin1' */
95 return (printit(TRUE
,FALSE
));
98 /* xprinc - built-in function princ */
101 return (printit(FALSE
,FALSE
));
104 /* xfreshline - start a new line if not at begining of line */
109 /* get file pointer */
110 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
113 /* optionally terminate the print line and return action */
114 return (xlfreshline(fptr
)? s_true
: NIL
);
118 /* xterpri - terminate the current print line */
123 /* get file pointer */
124 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
127 /* terminate the print line and return nil */
132 /* printit - common print function */
133 LOCAL LVAL printit
P2C(int, pflag
, int, tflag
)
137 /* get expression to print and file pointer */
139 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
142 #ifndef OLDPRINT /* fixed to make PRINT correspond the CL specs - L. Tierney */
143 /* terminate the previous line if necessary */
144 if (tflag
) xlterpri(fptr
);
145 #endif /* OLDPRINT */
147 /* print the value */
148 xlprint(fptr
,val
,pflag
);
151 /* print space if needed */
152 if (tflag
) xlputc(fptr
, ' ');
153 #endif /* OLDPRINT */
156 /* terminate the print line if necessary */
159 #endif /* OLDPRINT */
160 /* return the result */
164 /* xflatsize - compute the size of a printed representation using prin1 */
167 /* TAA MOD -- rewritten to use a USTREAM 1/21/97 */
170 /* get the expression */
174 return (cvfixnum(flatsize(val
, TRUE
)));
177 /* xflatc - compute the size of a printed representation using princ */
180 /* TAA MOD -- rewritten to use a USTREAM 1/21/97 */
183 /* get the expression */
187 return (cvfixnum(flatsize(val
, FALSE
)));
190 /* flatsize - compute the size of a printed expression */
191 LOCAL FIXTYPE flatsize
P2C(LVAL
, val
, int, pflag
)
193 /* TAA MOD -- rewritten to use a USTREAM 1/21/97 */
197 /* create and protect the stream */
198 ustream
= newustream();
201 /* print the value to compute its size */
202 xlprint(ustream
,val
,pflag
);
205 for (size
= 0, ustream
= gethead(ustream
);
207 size
++, ustream
= cdr(ustream
)) ;
212 /* return the length of the expression */
216 enum ACTIONS
{A_NIL
, A_ERR
, A_REN
, A_OVER
, A_APP
, A_SUPER
, A_CREATE
};
218 LOCAL FILEP opencmd
P3C(char *, name
, char *, mode
, int, binary
)
220 if (binary
) return OSBOPEN(name
, mode
);
221 else return OSAOPEN(name
, mode
);
224 /* xopen - open a file */
230 char *name
; /* file name strings */
231 FILEP fp
; /* opened file pointer */
232 LVAL fname
; /* file name string LVAL */
233 LVAL temp
; /* key arguments */
234 int iomode
; /* file mode, as stored in node */
235 enum ACTIONS exist
; /* exist action */
236 enum ACTIONS nexist
;/* non-exist action */
240 name
= getstring(fname
= xlgetfname());
243 if (xlgetkeyarg(k_direction
,&temp
) && temp
!= k_input
) {
244 if (temp
== k_output
) iomode
= S_FORWRITING
;
245 else if (temp
== k_io
) iomode
= S_FORREADING
|S_FORWRITING
;
246 else if (temp
== k_probe
) iomode
= 0;
249 else iomode
= S_FORREADING
;
253 if (xlgetkeyarg(k_elementtype
,&temp
) && temp
!= a_char
) {
255 int notsigned
= TRUE
;
256 nbits
= 8; /* default size */
257 if (temp
== a_sbyte
) notsigned
= FALSE
;
258 else if (consp(temp
) && car(temp
) == a_sbyte
&&
259 consp(cdr(temp
)) && fixp(car(cdr(temp
))) &&
260 null(cdr(cdr(temp
)))) {
261 nbits
= getfixnum(car(cdr(temp
)));
264 else if (consp(temp
) && car(temp
) == a_unbyte
&&
265 consp(cdr(temp
)) && fixp(car(cdr(temp
))) &&
266 null(cdr(cdr(temp
)))) {
267 nbits
= getfixnum(car(cdr(temp
)));
269 else if (temp
!= a_unbyte
&& temp
!= a_fixnum
)
271 if (nbits
< 0 || (nbits
& 7) != 0 || nbits
> /*32L* */MAXVECLEN
)
272 goto argerror
; /* invalid value for number of bits */
273 if (iomode
) iomode
|= (notsigned
? S_BINARY
|S_UNSIGNED
: S_BINARY
);
276 if (temp
== a_fixnum
) {
277 if (iomode
) iomode
|= S_BINARY
; /* mark as binary file type */
286 /* get exists action */
287 if (xlgetkeyarg(k_exist
, &temp
) &&
288 (iomode
& S_FORWRITING
) && /* ignore value if :input or :probe */
289 temp
!= k_rename
&& temp
!= k_newversion
) {
290 if (null(temp
)) exist
= A_NIL
;
291 else if (temp
== k_error
) exist
= A_ERR
;
292 else if (temp
== k_overwrite
) exist
= A_OVER
;
293 else if (temp
== k_append
) exist
= A_APP
;
294 else if (temp
== k_supersede
|| temp
== k_rendel
)
300 /* get non-exist action */
302 if (xlgetkeyarg(k_nexist
, &temp
)) {
303 if (null(temp
)) nexist
= A_NIL
;
304 else if (temp
== k_error
) nexist
= A_ERR
;
305 else if (temp
== k_create
) nexist
= A_CREATE
;
308 else { /* handle confusing mess of defaults */
309 if (iomode
== S_FORREADING
|| exist
== A_OVER
|| exist
== A_APP
)
311 else if (iomode
& S_FORWRITING
) nexist
= A_CREATE
;
317 /* attempt to open the file */
319 if ((fp
= opencmd(name
,
320 (iomode
& S_FORWRITING
) ? OPEN_UPDATE
: OPEN_RO
,
323 if (iomode
& S_FORWRITING
) switch (exist
) { /* do exist action */
324 case A_ERR
: /* give error */
326 xlerror("file exists", fname
);
328 case A_REN
: /* create new version */
331 if (!renamebackup(name
))
332 xlerror("couldn't create backup file", fname
);
334 case A_APP
: /* position to end of file */
337 case A_SUPER
: /* supersede file */
341 case A_NIL
: /* return NIL */
344 /*case A_OVER:*/ /* overwrite -- does nothing special */
348 else { /* file does not exist */
350 case A_ERR
: /* give error */
351 xlerror("file does not exist", fname
);
353 case A_NIL
: /* return NIL */
355 /*case A_CREATE:*/ /* create a new file */
360 /* we now create the file if it is not already open */
362 if ((fp
= opencmd(name
,
363 (iomode
&S_FORREADING
)? CREATE_UPDATE
: CREATE_WR
,
365 xlerror("couldn't create file", fname
);
367 /* take concluding actions */
368 if (iomode
== 0) { /* probe */
374 temp
= cvfile(fp
, iomode
);
375 temp
->n_bsiz
= (short)(unsigned short)(nbits
/8);
378 return cvfile(fp
,iomode
);
380 argerror
: xlerror("invalid argument", temp
);
385 /* xfileposition - get position of file stream */
386 LVAL
xfileposition(V
)
393 /* get file pointer */
394 fp
= getfile(fptr
= xlgastream());
396 /* make sure the file exists */
398 xlfail("file not open");
400 /* get current position, adjusting for posible "unget" */
401 j
= OSTELL(fp
) + (getsavech(fptr
) ? -1L : 0L);
403 if (moreargs()) { /* must be set position */
406 if (pos
== k_end
) t
=OSSEEKEND(fp
);
407 else if (pos
== k_start
) t
=OSSEEK(fp
,0L);
408 else if (fixp(pos
)) { /* check for in range, then position */
409 /* STDIO allows positioning beyond end of file, so we must check
410 the file size (boo his!) */
413 if (fptr
->n_sflags
& S_BINARY
) i
*= fptr
->n_bsiz
;
417 if (t
== 0 && fp
!= CONSOLE
&& (i
< 0 || i
> fsize
)) {
419 xlerror("position outside of file", pos
);
421 t
= OSSEEK(fp
, (long)i
);
425 setsavech(fptr
,'\0'); /* toss unget character, if any */
426 fptr
->n_sflags
&= ~(S_READING
|S_WRITING
);
427 /* neither reading or writing currently */
428 /* t is non-zero if couldn't do seek */
429 return (t
!= 0 || fp
== CONSOLE
? NIL
: s_true
);
433 return ((j
== -1L || fp
== CONSOLE
) ? NIL
:
434 cvfixnum(fptr
->n_sflags
& S_BINARY
? j
/fptr
->n_bsiz
: j
));
436 return ((j
== -1L || fp
== CONSOLE
) ? NIL
: cvfixnum(j
));
440 /* xfilelength - returns length of file */
449 /* get file pointer */
451 fp
= getfile(stream
= xlgastream());
453 fp
= getfile(xlgastream());
457 /* make sure the file exists */
459 xlfail("file not open");
461 /* not all stdio packages will catch the following gaffe */
462 if (fp
== CONSOLE
) return NIL
;
464 if ((i
=OSTELL(fp
)) == -1L ||
466 (j
= OSTELL(fp
)) == -1L ||
472 return cvfixnum(stream
->n_sflags
& S_BINARY
? j
/stream
->n_bsiz
: j
);
479 /* xfilemtime - returns modification time of file */
486 str
= getstring(fname
= xlgetfname());
489 if (osmtime(str
, &mtime
))
490 xlerror("can't get modification time", fname
);
492 if ((double) mtime
> (double) MAXFIX
)
493 return cvflonum((FLOTYPE
) mtime
);
495 return cvfixnum((FIXTYPE
) mtime
);
498 /* xrenamefile - renames file */
501 LVAL oldname
, newname
;
502 char *oldstr
, *newstr
;
504 oldstr
= getstring(oldname
= xlgetfname());
505 newstr
= getstring(newname
= xlgastring());
508 /* in applec and THINK_C rename fails if the new file exists, */
509 /* so remove it first */
510 if ((remove(newstr
) != 0 && errno
== EACCES
) ||
511 rename(oldstr
, newstr
) != 0)
512 xlerror("can't rename file", oldname
);
513 /**** need to fix the truename of open file streams */
514 /**** need to add multiple return values */
518 #endif /* FILETABLE */
524 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
527 if (streamp(fptr
)) osforce(getfile(fptr
));
536 LVAL f
= xlgetfname();
537 char namebuf
[FNAMEMAX
+1];
542 STRCPY(buf
, getstring(f
));
544 if (!truename(buf
, namebuf
)) xlerror("strange file name", f
);
546 return cvstring(namebuf
);
554 /* get the argument */
559 if (streamp(arg
) && getfile(arg
) > CONSOLE
) {
560 /* close file first */
562 STRCPY(buf
, filetab
[fp
].tname
);
564 setsavech(arg
, '\0');
568 if (symbolp(arg
)) arg
= getpname(arg
);
569 else if (!stringp(arg
)) xlbadtype(arg
);
571 if (getslength(arg
) >= FNAMEMAX
)
572 xlerror("file name too long", arg
);
574 STRCPY(buf
,getstring(arg
));
576 if (remove(buf
) != 0 && errno
== EACCES
)
577 xlerror("cannot delete file", arg
);
589 return dirlist(getstring(name
));
595 char *name
= getstring(xlgastring());
597 if (stat(name
, &s
) != 0)
599 else if (S_ISDIR(s
.st_mode
))
600 return xlenter(":DIRECTORY");
601 else if (S_ISCHR(s
.st_mode
))
602 return xlenter(":CHARACTER-SPECIAL");
603 else if (S_ISBLK(s
.st_mode
))
604 return xlenter(":BLOCK-SPECIAL");
605 else if (S_ISREG(s
.st_mode
))
606 return xlenter(":REGULAR");
607 else if (S_ISFIFO(s
.st_mode
))
608 return xlenter(":FIFO");
610 return xlenter(":UNKNOWN");
614 /* xclose - close a file */
618 FILEP fp
; /* TAA MOD to allow closing closed files,
619 prohibit closing the console, return the correct
620 values (true on success), and close string streams */
623 /* get file pointer */
627 /* handle string stream case by converting to a closed file! */
628 if (ustreamp(fptr
)) {
629 fptr
->n_type
= STREAM
;
630 setfile(fptr
, CLOSED
);
631 setsavech(fptr
, '\0');
635 /* give error of not file stream */
636 if (!streamp(fptr
)) xlbadtype(fptr
);
639 /* make sure the file exists */
641 if ((fp
= getfile(fptr
)) == CLOSED
|| fp
== CONSOLE
)
646 setsavech(fptr
, '\0');
647 setfile(fptr
,CLOSED
);
653 /* xrdchar - read a character from a file */
654 /* eof, eof-error-p added - L. Tierney */
660 /* get file pointer */
661 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
662 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
663 eof
= (moreargs() ? xlgetarg() : NIL
);
664 if (moreargs()) xlgetarg(); /* remove and ignore recursive-p argument */
667 /* get character and check for eof */
669 if (ch
== EOF
&& eof_error_p
) xlfail("end of file on read");
670 return (ch
== EOF
? eof
: cvchar(ch
));
674 #define bs(n) (n) /* byte select in short */
676 #define bs(n) ((n)^1)
679 /* xrdbyte - read a byte from a file */
680 /* eof, eof-error-p added - L. Tierney */
687 int ch
, eof_error_p
, i
, size
, ofs
;
690 /* get file pointer */
692 if ((fptr
->n_sflags
& S_BINARY
) == 0)
693 xlfail("not a binary file");
694 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
695 eof
= (moreargs() ? xlgetarg() : NIL
);
698 if (fptr
->n_bsiz
== 1) { /* file of bytes */
700 if (ch
== EOF
&& eof_error_p
) xlfail("end of file on read");
701 return(ch
== EOF
? eof
:
702 ((fptr
->n_sflags
&S_UNSIGNED
) ? cvfixnum((FIXTYPE
)ch
)
703 : cvfixnum((FIXTYPE
)(/*signed*/ char)ch
)));
705 else { /* file of more than that */
706 size
= (fptr
->n_bsiz
+sizeof(BIGNUMDATA
)-1)/sizeof(BIGNUMDATA
);
707 /* size of bignum needed */
708 if (size
< 2) size
= 2;
709 ofs
= size
*sizeof(BIGNUMDATA
) - fptr
->n_bsiz
; /* unused bytes */
710 val
= newbignum(size
);
711 vx
= getbignumarray(val
)+1; /* point to data array start */
712 v
= (unsigned char *)vx
;
714 for (i
= ofs
; i
< size
*sizeof(BIGNUMDATA
); i
++)
716 for (i
= size
*sizeof(BIGNUMDATA
)-1; i
>= ofs
; i
--)
721 if (eof_error_p
) xlfail("end of file on read");
724 v
[bs(i
)] = (unsigned char)ch
;
726 if ((/*signed*/ char)(v
[bs(ofs
)]) < 0 && (fptr
->n_sflags
&S_UNSIGNED
)==0)
728 /* we need to handle negative number */
732 for (i
= ofs
-1; i
>=0; i
--) v
[bs(i
)] = 0xff;
733 for (i
= size
-1; i
>= 0; i
--) {
734 sum
= (unsigned long)(BIGNUMDATA
)(~vx
[i
]) + carry
;
735 carry
= (int)(sum
>> 16);
736 vx
[i
] = (BIGNUMDATA
)sum
;
739 val
= normalBignum(val
); /* normalize in case of leading zeroes */
740 return (cvtbigfixnum(val
, &temp
) ? cvfixnum(temp
) : val
);
749 /* get file pointer */
750 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
751 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
752 eof
= (moreargs() ? xlgetarg() : NIL
);
755 /* get character and check for eof */
757 if (ch
== EOF
&& eof_error_p
) xlfail("end of file on read");
758 return(ch
== EOF
? eof
: cvfixnum((FIXTYPE
)ch
));
762 /* xpkchar - peek at a character from a file */
763 /* eof, eof-error-p added */
769 /* peek flag and get file pointer */
770 flag
= (moreargs() ? xlgetarg() : NIL
);
771 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
772 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
773 eof
= (moreargs() ? xlgetarg() : NIL
);
774 if (moreargs()) xlgetarg(); /* remove and ignore recursive-p argument */
777 /* skip leading white space and get a character */
779 while ((ch
= xlpeek(fptr
)) != EOF
&& isspace(ch
))
784 /* return the character */
785 if (ch
== EOF
&& eof_error_p
) xlfail("end of file on read");
786 return (ch
== EOF
? eof
: cvchar(ch
));
789 /* xwrchar - write a character to a file */
794 /* get the character and file pointer */
796 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
799 /* put character to the file */
800 xlputc(fptr
,getchcode(chr
));
802 /* return the character */
806 /* xwrbyte - write a byte to a file */
808 /* we will continue XLISP's tradition of not checking for value
809 to write being out of range. At any rate, this will save time. */
817 /* get the byte and file pointer */
819 if (!(fixp(chr
) || bignump(chr
))) xlbadtype(chr
);
821 if ((fptr
->n_sflags
& S_BINARY
) == 0)
822 xlfail("not a binary file");
825 /* can't really do an unsigned write of a negative number */
826 if ((fptr
->n_sflags
&S_UNSIGNED
) &&
827 ((fixp(chr
)&&getfixnum(chr
)<0) || (bignump(chr
)&&getbignumsign(chr
))))
828 xlerror("Can't do unsigned write-byte of", chr
);
831 if (fptr
->n_bsiz
== 1 && fixp(chr
)) { /* handle easy case */
832 /* put byte to the file */
833 xlputc(fptr
,(int)getfixnum(chr
));
836 /* work only with bignums from now on */
837 if (fixp(chr
)) chr2
= cvtfixbignum(getfixnum(chr
));
839 vx
= getbignumarray(chr2
);
840 size
= getbignumsize(chr2
) * sizeof(BIGNUMDATA
); /* number size in bytes */
841 ofs
= fptr
->n_bsiz
- size
; /* number of excess bytes to write */
842 if (*vx
++) { /* negative value */
845 v
= (unsigned char *)vx
;
846 for (i
= ofs
; i
> 0; i
--) xlputc(fptr
, 0xff); /* filler */
847 for (i
= size
-1; i
>= -ofs
&& i
>= 0; i
--) { /* find end of carries */
848 if (v
[bs(i
)] != 0) { /* only zeroes will generate carries */
849 for (j
= (ofs
>= 0 ? 0 : -ofs
); j
< i
; j
++) {
850 xlputc(fptr
, (unsigned char) (~v
[bs(j
)]));
855 for (; i
< size
; i
++) xlputc(fptr
, 1 + (unsigned char)(~v
[bs(i
)]));
859 v
= (unsigned char *)vx
;
860 for (i
= size
-1; i
>= -ofs
&& i
>= 0; i
--) {
861 sum
= (unsigned)(unsigned char)~v
[bs(i
)] + carry
;
863 xlputc(fptr
, (unsigned char) sum
);
865 for (i
= ofs
; i
> 0; i
--) xlputc(fptr
, 0xff); /* filler */
868 else { /* postive value */
869 v
= (unsigned char *)vx
;
871 for (i
= ofs
; i
> 0; i
--) xlputc(fptr
, 0); /* filler */
872 for (i
= (ofs
>= 0 ? 0 : -ofs
); i
< size
; i
++) xlputc(fptr
, v
[bs(i
)]);
874 for (i
= size
-1; i
>= -ofs
&& i
>= 0; i
--) xlputc(fptr
, v
[bs(i
)]);
875 for (i
= ofs
; i
> 0; i
--) xlputc(fptr
, 0); /* filler */
879 /* return the byte */
887 /* get the byte and file pointer */
889 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
892 /* put byte to the file */
893 xlputc(fptr
,(int)getfixnum(chr
));
895 /* return the character */
900 /* xreadline - read a line from a file */
901 /* eof, eof-error-p added - L. Tierney */
905 LVAL fptr
,str
,newstr
,eof
;
906 int len
,blen
,ch
,eof_error_p
;
908 /* protect some pointers */
911 /* get file pointer */
912 fptr
= (moreargs() ? xlgetfile(FALSE
) : getvalue(s_stdin
));
913 eof_error_p
= moreargs() ? ((xlgetarg() != NIL
) ? TRUE
: FALSE
) : TRUE
;
914 eof
= (moreargs() ? xlgetarg() : NIL
);
915 if (moreargs()) xlgetarg(); /* remove and ignore recursive-p argument */
918 /* get character and check for eof */
919 len
= blen
= 0; p
= buf
;
920 while ((ch
= xlgetc(fptr
)) != EOF
&& ch
!= '\n') {
922 /* check for buffer overflow TAA MOD to use MEMCPY instead of strcat*/
923 if (blen
>= STRMAX
) {
924 newstr
= newstring(len
+ STRMAX
);
925 sptr
= getstring(newstr
);
926 if (str
!= NIL
) MEMCPY(sptr
, getstring(str
), len
);
927 MEMCPY(sptr
+len
, buf
, blen
);
933 /* store the character */
937 /* check for end of file */
938 if (len
== 0 && p
== buf
&& ch
== EOF
) {
940 if (eof_error_p
) xlfail("end of file on read");
944 /* append the last substring */
945 /* conditional removed because code always executes! */
946 newstr
= newstring(len
+ blen
);
947 sptr
= getstring(newstr
);
948 if (str
!= NIL
) MEMCPY(sptr
, getstring(str
), len
);
949 MEMCPY(sptr
+len
, buf
, blen
);
950 sptr
[len
+blen
] = '\0';
953 /* restore the stack */
956 /* return the string */
960 /* xunrdchar - unread a character from a file */
965 /* get the character and file pointer */
967 fptr
= (moreargs() ? xlgetfile(TRUE
) : getvalue(s_stdout
));
970 /* unread character from the file */
971 xlungetc(fptr
,getchcode(chr
));
973 /* return the character */
977 /* xmkstrinput - make a string input stream */
978 /* TAA MOD - reworked for unsigned lengths */
981 unsigned start
,end
=0,len
,i
;
986 /* protect the return value */
989 /* get the string and length */
990 string
= xlgastring();
991 str
= getstring(string
);
992 len
= getslength(string
);
994 /* get the starting offset */
997 temp
= getfixnum(val
);
998 if (temp
< 0 || temp
> len
)
999 xlerror("string index out of bounds",val
);
1000 start
= (unsigned) temp
;
1004 /* get the ending offset */
1005 if (moreargs()) { /* TAA mod to allow NIL for end offset */
1007 if (null(val
)) end
= len
;
1008 else if (fixp(val
)) {
1009 temp
= getfixnum(val
);
1010 if (temp
< start
|| temp
> len
)
1011 xlerror("string index out of bounds",val
);
1012 end
= (unsigned) temp
;
1014 else xlbadtype(val
);
1020 /* make the stream */
1023 /* copy the substring into the stream */
1024 for (i
= start
; i
< end
; ++i
)
1027 /* restore the stack */
1030 /* return the new stream */
1034 /* xmkstroutput - make a string output stream */
1035 LVAL
xmkstroutput(V
)
1037 return (newustream());
1040 /* xgetstroutput - get output stream string */
1041 LVAL
xgetstroutput(V
)
1044 stream
= xlgaustream();
1046 return (getstroutput(stream
));
1049 /* xgetlstoutput - get output stream list */
1050 LVAL
xgetlstoutput(V
)
1054 /* get the stream */
1055 stream
= xlgaustream();
1058 /* get the output character list */
1059 val
= gethead(stream
);
1061 /* empty the character list */
1062 sethead(stream
,NIL
);
1063 settail(stream
,NIL
);
1065 /* return the list */
1070 LOCAL VOID toomanyopt
P1C(LVAL
, fmt
)
1072 xlerror("too many prefix parameters in format",fmt
);
1075 /* decode prefix parameters and modifiers for a format directive */
1076 /* TAA MOD Entirely rewritten -- return value -1 for unassigned since
1077 negative numbers are inappropriate for all arguments we are concerned
1078 with. Also clips args to reasonable values, allows both : and @ modifiers
1080 LOCAL
char *decode_pp
P7C(char *, fmt
,
1081 FIXTYPE
*, pp
, /* prefix parameters */
1082 int, maxnpp
, /* maximum number of them */
1083 int *, npp
, /* actual number of them */
1084 int *, colon
, /* colon modifier given? */
1085 int *, atsign
, /* atsign modifier given? */
1086 LVAL
, lfmt
) /* format string for failure */
1092 for (i
= 0; i
< maxnpp
; i
++) pp
[i
] = -1; /* initially all undefined */
1097 if (*fmt
== '\'') { /* character code */
1098 pp
[*npp
] = *(++fmt
);
1102 else if (*fmt
== '#') { /* xlargc is value */
1104 if (accum
>FMTMAX
) accum
= FMTMAX
;
1109 else if (*fmt
== 'v' || *fmt
== 'V') { /* lisp arg is value */
1110 LVAL arg
= xlgetarg();
1112 accum
= getfixnum(arg
);
1113 if (accum
< 0) accum
= 0; /* clip at reasonable values */
1114 else if (accum
>FMTMAX
) accum
= FMTMAX
;
1116 else if (charp(arg
))
1117 accum
= getchcode(arg
);
1127 else if (isdigit(*fmt
)) { /* integer literal */
1130 accum
= accum
*10 + (int)(*fmt
++ - '0');
1132 accum
= FMTMAX
; /* Clip at reasonable value */
1133 } while (isdigit(*fmt
));
1137 else if (*fmt
== '#') { /* use number of remaining arguments */
1142 else if (*fmt
== ',') { /* empty field */
1145 else break; /* nothing to process */
1147 if (*fmt
!= ',') break; /* no comma -- done */
1148 *npp
+= 1; /* got an argument */
1149 fmt
++; /* toss comma */
1150 if( *npp
>= maxnpp
) toomanyopt(lfmt
);
1154 do { /* pick up any colon or atsign modifier */
1155 if (*fmt
== ':') *colon
= 1;
1156 else if (*fmt
== '@') *atsign
= 1;
1163 #define mincol pp[0]
1164 #define colinc pp[1]
1165 #define minpad pp[2]
1166 #define padchar pp[3]
1168 /* opt_print - print a value using prefix parameter options */
1169 LOCAL VOID opt_print
P6C(LVAL
, stream
,
1171 int, pflag
, /* quoting or not */
1172 FIXTYPE
*, pp
, /* prefix parameters */
1173 int, colon
, /* colon modifier given? */
1174 int, atsign
) /* at-sign modifier given? */
1179 if (mincol
< 0) mincol
= 0; /* handle default values */
1180 if (colinc
< 1) colinc
= 1; /* also arg of 0 for colinc */
1181 if (minpad
< 0) minpad
= 0;
1182 if (padchar
< 0) padchar
= ' ';
1184 if( mincol
< minpad
)
1188 /* we will need to pad, so must calculate flat size */
1189 if (colon
&& null(val
)) /* flat size is 2 */
1192 flatsiz
= (int)flatsize(val
, pflag
);
1193 if (atsign
) { /* padding may be required on left */
1194 for( i
= 0; i
< minpad
; flatsiz
++, i
++ )
1195 xlputc(stream
,(int)padchar
);
1196 while( flatsiz
< mincol
) {
1197 for( i
= 0; i
< colinc
; i
++ )
1198 xlputc(stream
,(int)padchar
);
1199 flatsiz
+= (int)colinc
;
1204 /* print the value */
1205 if( colon
&& null(val
))
1206 xlputstr(stream
,"()");
1208 xlprint(stream
,val
,pflag
);
1210 if( mincol
> 0 && !atsign
) { /* padding required on right */
1211 for( i
= 0; i
< minpad
; flatsiz
++, i
++ )
1212 xlputc(stream
,(int)padchar
);
1213 while( flatsiz
< mincol
) {
1214 for( i
= 0; i
< colinc
; i
++ )
1215 xlputc(stream
,(int)padchar
);
1216 flatsiz
+= (int)colinc
;
1222 LOCAL VOID integer_print
P5C(LVAL
, stream
,
1224 int, pflag
, /* Style */
1225 FIXTYPE
*, pp
, /* prefix parameters */
1226 int, atsign
) /* at-sign modifier given? */
1237 if (radix
< 2 || radix
> 36)
1238 xlerror("bad radix specified", cvfixnum(radix
));
1243 fillchar
= (int)pp
[1];
1245 if (fillchar
< 0) fillchar
= ' ';
1248 /* can't print in binary or arbitrary radix with printf */
1249 if (fixp(val
) && (pflag
== 'B' || pflag
== 'R')) {
1250 if (getfixnum(val
) == 0) pflag
= 'D'; /* print zero in "decimal" */
1251 else val
= cvtfixbignum(getfixnum(val
));
1255 if (fixp(val
)) { /* D O or X and fixnum */
1256 FIXTYPE v
= getfixnum(val
); /* TAA mod 3/95 to handle @X and @O
1257 and negative values with X and O */
1260 sprintf(buf
, (atsign
?"%+ld":"%ld"), v
);
1263 if (v
< 0) sprintf(buf
, "-%lo", -v
);
1264 else sprintf(buf
, (atsign
? "+%lo" : "%lo"), v
);
1267 if (v
< 0) sprintf(buf
, "-%lx", -v
);
1268 else sprintf(buf
, (atsign
? "+%lx" : "%lx"), v
);
1271 if (mincol
> 0) { /* need to fill */
1272 for (i
= (int)mincol
-strlen(buf
); i
-- > 0;)
1273 xlputc(stream
,fillchar
);
1275 xlputstr(stream
,buf
);
1279 else if (bignump(val
)) { /* D O or X and bignum */
1281 case 'D': radix
= 10; break;
1282 case 'X': radix
= 16; break;
1283 case 'B': radix
= 2; break;
1284 case 'O': radix
= 8; break;
1286 bufr
= cvtbignumstr(val
, (int)radix
);
1287 if (atsign
&& getbignumsign(val
)) atsign
= 0; /* add leading "+"? */
1288 if (mincol
> 0) { /* need to fill */
1289 for (i
= (int)mincol
- atsign
- STRLEN(bufr
); i
-- > 0;)
1290 xlputc(stream
,fillchar
);
1292 if (atsign
) xlputc(stream
, '+');
1293 xlputstr(stream
,bufr
);
1298 else { /* not a number */
1299 padchar
= colinc
= minpad
= -1; /* zap arg if provided */
1300 opt_print(stream
,val
,FALSE
,pp
,0,0);
1306 Floating point formatting has been modified (L. Tierney) to correspond
1307 more closely to CL. All prefix parameters for ~F, ~E and ~G except the
1308 scale parameter k are supported. (I don't have much use for k, and it
1309 would be hard to add since it can be negative.) The routines operate
1310 by letting sprintf do the formatting work and parsing the results it
1311 produces. IEEE NaN's and Infinities are recognized by checking for an
1312 alpha character as the first character in the printed representation
1313 of fabs(num). Also, I have tried to write all inequalities in such a
1314 way as to insure that Infinities and NaN's should only be handled in
1315 the ~E directive. Most reasonable cases seem to be handled correctly,
1316 but I may have gotten some of the extreme cases wrong (w = 1, d = 0 and
1317 that sort of stuff). There seems to be some disagreement among CL
1318 implementations on these.
1321 /* trim trailing zeros in fractional part; return length of fraction left */
1322 LOCAL
int trimzeros
P2C(char *, s
, int, skip_one
)
1326 /* locate the decimal point */
1327 for (i
= 0, d
= -1; s
[i
] != 0; i
++) {
1334 /* drop trailing zeros if decimal point is found */
1336 dd
= (skip_one
) ? d
+ 1 : d
;
1337 for (i
= d
+ 1; s
[i
] != 0 && isdigit(s
[i
]); i
++);
1339 for (i
--; i
> dd
&& s
[i
] == '0'; i
--)
1341 return(strlen(s
+d
+1));
1346 LOCAL
int allzeros
P1C(char *, s
)
1348 for (; *s
!= 0; s
++)
1349 if (*s
!= '.' && *s
!= '0')
1354 LOCAL VOID write_double_ffmt
P4C(char *, s
, double, y
, int, e
, int, d
)
1361 sprintf(cmd
, "%%.%de", f
> 0 ? f
: 0);
1364 /* re-read exponent in case changed by rounding */
1365 if (read_exponent(strchr(s
, 'e') + 1) > e
) {
1366 s
[f
> 0 ? f
+ 2 : 2] = '0'; /* extend fractional part with a zero */
1367 f
++; /* increment length of fractional part */
1368 e
++; /* increment exponent */
1371 s
[1] = '.'; /* make sure decimal point is there */
1372 s
[f
> 0 ? f
+ 2 : 2] = 0; /* terminate the string */
1375 m
= e
> f
? f
: e
; /* shift the decimal point */
1376 MEMMOVE(s
+ 1, s
+ 2, m
);
1379 for (i
= m
+ 1; i
< e
+ 1; i
++) /* insert zeros */
1381 if (f
< d
) { /* add trailing zeros if needed */
1382 for (i
= e
+ f
+ 2; i
< e
+ d
+ 2; i
++)
1388 MEMMOVE(s
+ 2 - e
, s
+ 2, f
); /* shift fractional part */
1389 s
[1 - e
] = s
[0]; /* move leading digit */
1390 s
[0] = '0'; /* set leading digit to zero */
1391 for (i
= 2; i
< 1 - e
; i
++) /* insert zeros if needed */
1393 s
[2 + f
- e
] = 0; /* terminate string */
1396 int ld
= s
[0]; /* round up leading digit if needed */
1397 s
[0] = (d
== 0 && e
== -1 && ld
>= '5') ? '1' : '0';
1399 for (i
= 2; i
< d
+ 1; i
++) /* insert zeros if needed */
1401 if (d
> 0) /* round up final digit if needed */
1402 s
[d
+ 1] = (f
== -1 && ld
>= '5') ? '1' : '0';
1403 s
[d
+ 2] = 0; /* terminate string */
1407 VOID write_double_efmt
P3C(char *, s
, double, y
, int, d
)
1412 /* tries to use d - 1 digits if the result reads in as equal to y */
1413 sprintf(cmd
, "%%.%de", d
> 0 ? d
- 1 : 0);
1417 sprintf(s
, is_nan(y
) ? "NaN" : "Inf");
1419 Finite
= isdigit(s
[0]);
1420 if (d
> 0 && Finite
) {
1422 sscanf(s
, "%lf", &n
);
1424 sprintf(cmd
, "%%.%de", d
);
1430 LOCAL VOID flonum_fprint
P4C(LVAL
, stream
,
1432 FIXTYPE
*, pp
, /* prefix parameters */
1433 int, atsign
) /* at-sign modifier given? */
1435 if (! realp(val
)) { /* not a real number */
1436 padchar
= colinc
= minpad
= -1; /* zap arg if provided */
1437 opt_print(stream
,val
,FALSE
,pp
,0,0);
1441 FLOTYPE num
= makefloat(val
);
1442 FLOTYPE y
= fabs(num
);
1443 int needsign
= (atsign
|| num
< 0.0) ? TRUE
: FALSE
;
1444 int w
= pp
[0], d
= pp
[1];
1445 int overflowchar
= pp
[3], fillchar
= pp
[4];
1446 int i
, rw
, intsize
, fracsize
, exponent
, len
, haved
;
1450 /* IBM 370 floating pt format; the largest number isn't */
1451 /* quite so large... - Dave Rivers (rivers@ponds.uucp) */
1452 if (y
== 0.0 || (y
> 1e-100 && y
< 1e75
))
1454 if (y
== 0.0 || (y
> 1e-100 && y
< 1e100
))
1457 /* don't generate extra big number */
1458 /* test should be false for Infinity, NaN */
1460 /* control width and decimals */
1461 if (w
> 100) w
= 100;
1462 if (d
> 100) d
= 100;
1464 /* compute the sizes of the integer and fractional parts */
1471 write_double_efmt(buf
, y
, 16);
1472 p
= strchr(buf
, 'e');
1474 exponent
= read_exponent(p
+ 1);
1475 intsize
= (exponent
>= 0) ? 1 + exponent
: 0;
1476 i
= trimzeros(buf
, FALSE
);
1477 fracsize
= (exponent
< i
) ? i
- exponent
: 1;
1479 else { /* should not happen */
1480 exponent
= intsize
= fracsize
= 0;
1483 if (d
== 0 && intsize
== 0) intsize
= 1;
1485 /* if d is given, check for overflow; otherwise, compute d */
1489 rw
= (needsign
) ? d
+ 2 : d
+ 1;
1492 if (overflowchar
>= 0) goto overflow
;
1500 d
= w
- 1 - intsize
;
1502 if ((intsize
== 0 && d
< 1) || d
< 0) {
1503 if (overflowchar
>= 0) goto overflow
;
1505 d
= (intsize
== 0) ? 1 : 0;
1506 w
= (needsign
) ? intsize
+ 2 + d
: intsize
+ 1 + d
;
1513 write_double_ffmt(buf
, y
, exponent
, d
);
1514 if (y
== 0.0 || ! allzeros(buf
))
1515 d
= trimzeros(buf
, TRUE
);
1518 /* write number using computed d */
1519 write_double_ffmt(buf
, y
, exponent
, d
);
1521 /* fiddle it if no leading zero or rounded to be too long */
1524 if (w
>= 0 && len
> ((needsign
) ? w
- 1 : w
)) {
1527 else if (p
[len
- 1] == '0' && ! haved
)
1529 else if (overflowchar
>= 0)
1533 /* if w is supplied, output pad characters */
1535 if (fillchar
< 0) fillchar
= ' ';
1539 xlputc(stream
,fillchar
);
1542 /* print the sign if needed */
1543 if (num
< 0) xlputc(stream
, '-');
1544 else if (atsign
) xlputc(stream
, '+');
1550 else if (w
>= 0 && overflowchar
>= 0) goto overflow
;
1553 for (i
= 0; i
< 7; i
++) pp
[i
] = -1; /* zap any arguments */
1554 flonum_eprint(stream
, val
, pp
, atsign
);
1558 /* handle overflows */
1560 for (i
= 0; i
< w
; i
++) xlputc(stream
, overflowchar
);
1564 LOCAL VOID flonum_eprint
P4C(LVAL
, stream
,
1566 FIXTYPE
*, pp
, /* prefix parameters */
1567 int, atsign
) /* at-sign modifier given? */
1569 if (! realp(val
)) { /* not a real number */
1570 padchar
= colinc
= minpad
= -1; /* zap arg if provided */
1571 opt_print(stream
,val
,FALSE
,pp
,0,0);
1574 FLOTYPE num
= makefloat(val
);
1575 FLOTYPE y
= fabs(num
);
1576 int needsign
= (atsign
|| num
< 0.0) ? TRUE
: FALSE
;
1577 int w
= pp
[0], d
= pp
[1], dd
= pp
[1], e
= pp
[2], ee
= pp
[2];
1578 int overflowchar
= pp
[4], fillchar
= pp
[5], expchar
= pp
[6];
1579 int i
, rw
, fracsize
, expsize
, exponent
, finite
;
1582 /* control width and decimals */
1583 if (w
> 100) w
= 100;
1584 if (d
> 100) d
= 100;
1586 /* compute the sizes of the parts */
1594 write_double_efmt(buf
, y
, d
>= 0 ? d
: 16);
1595 finite
= isdigit(buf
[0]);
1596 for (p
= buf
; *p
== '.' || isdigit(*p
); p
++);
1597 if (finite
&& isalpha(*p
)) {
1598 exponent
= read_exponent(p
+ 1);
1599 fracsize
= trimzeros(buf
, TRUE
);
1600 sprintf(buf
, "%+d", exponent
);
1601 expsize
= strlen(buf
) - 1;
1604 fracsize
= strlen(buf
);
1605 e
= exponent
= expsize
= 0;
1609 /* set the fill character */
1610 if (fillchar
< 0) fillchar
= ' ';
1612 /* handle non-finite numbers */
1617 if (w
< i
&& overflowchar
>= 0) goto overflow
;
1619 for (i
= w
- i
; i
-- > 0;)
1620 xlputc(stream
, fillchar
);
1622 if (num
< 0.0) xlputc(stream
, '-');
1623 else if (atsign
) xlputc(stream
, (num
> 0.0) ? '+' : fillchar
);
1624 xlputstr(stream
,buf
);
1628 /* check for exponent overflow and adjust e */
1631 if (w
>= 0 && overflowchar
>= 0) goto overflow
;
1637 /* if d is given, check for overflow; otherwise, compute d */
1640 rw
= (needsign
) ? d
+ e
+ 5 : d
+ e
+ 4;
1642 if (overflowchar
>= 0) goto overflow
;
1652 if (overflowchar
>= 0) goto overflow
;
1655 w
= (needsign
) ? e
+ 5 : e
+ 4;
1662 sprintf(cmd
, "%%.%de", d
);
1663 sprintf(buf
, cmd
, y
);
1665 /* adjust and recheck the exponent */
1666 for (p
= buf
; *p
== '.' || isdigit(*p
); p
++);
1668 exponent
= read_exponent(p
+ 1);
1669 if (dd
< 0) d
= trimzeros(buf
, TRUE
);
1670 sprintf(buf
, "%+d", exponent
);
1671 expsize
= strlen(buf
) - 1;
1673 if (ee
>= 0 && expsize
> ee
&& w
>= 0 && overflowchar
>= 0)
1680 /* write number using computed and modified d */
1681 sprintf(cmd
, "%%.%de", d
);
1682 sprintf(buf
, cmd
, y
);
1684 /* remove the exponent and fiddle it if nothing after the decimal */
1689 else buf
[2 + d
] = 0;
1691 /* if w is supplied, output pad characters */
1693 i
= w
- e
- 2 - strlen(buf
);
1696 xlputc(stream
,fillchar
);
1699 /* print the sign if needed */
1700 if (num
< 0) xlputc(stream
, '-');
1701 else if (atsign
) xlputc(stream
, '+');
1704 xlputstr(stream
,buf
);
1706 /* print the exponent */
1707 xlputc(stream
, (expchar
>= 0) ? expchar
: 'E');
1708 xlputc(stream
, (exponent
>= 0) ? '+' : '-');
1709 for (i
= e
- expsize
; i
> 0; i
--) xlputc(stream
, '0');
1710 sprintf(buf
, "%d", (exponent
>= 0) ? exponent
: -exponent
);
1711 xlputstr(stream
, buf
);
1714 /* handle overflows */
1716 for (i
= 0; i
< w
; i
++) xlputc(stream
, overflowchar
);
1720 LOCAL VOID flonum_gprint
P4C(LVAL
, stream
,
1722 FIXTYPE
*, pp
, /* prefix parameters */
1723 int, atsign
) /* at-sign modifier given? */
1727 fillchar
= (int)pp
[2];
1729 if (fillchar
< 0) fillchar
= ' ';
1731 if (! realp(val
)) { /* not a real number */
1732 padchar
= colinc
= minpad
= -1; /* zap arg if provided */
1733 opt_print(stream
,val
,FALSE
,pp
,0,0);
1736 FLOTYPE num
= makefloat(val
);
1737 FLOTYPE y
= fabs(num
);
1738 int w
= pp
[0], d
= pp
[1], e
= pp
[2];
1739 int overflowchar
= pp
[4], fillchar
= pp
[5];
1740 int i
, fracsize
, expsize
, exponent
, finite
;
1741 int ww
, dd
, ee
, q
, n
;
1744 /* control width and decimals */
1745 if (w
> 100) w
= 100;
1746 if (d
> 100) d
= 100;
1748 /* compute the sizes of the parts */
1756 write_double_efmt(buf
, y
, 16);
1757 finite
= isdigit(buf
[0]);
1758 for (p
= buf
; *p
== '.' || isdigit(*p
); p
++);
1759 if (finite
&& isalpha(*p
)) {
1760 exponent
= read_exponent(p
+ 1);
1761 fracsize
= trimzeros(buf
, FALSE
);
1762 sprintf(buf
, "%+d", exponent
);
1763 expsize
= strlen(buf
) - 1;
1766 fracsize
= strlen(buf
);
1767 exponent
= expsize
= 0;
1771 /* compute n such that 10^(n-1) <= y < 10^n, with n = 0 for y = 0 */
1772 if (y
== 0.0) n
= 0;
1773 else n
= exponent
+ 1;
1776 ee
= (e
>= 0) ? e
+ 2 : 4;
1779 ww
= (w
>= 0) ? w
- ee
: -1;
1781 /* compute d, if not supplied, and dd */
1784 i
= (n
> 7) ? 7 : n
;
1785 d
= (q
> i
) ? q
: i
;
1789 /* print the number using F or E format */
1790 if (finite
&& 0 <= dd
&& dd
<= d
) {
1793 pp
[1] = (dd
== 0 || pp
[1] >= 0) ? dd
: -1; /* to get zeros trimmed */
1796 pp
[3] = overflowchar
;
1798 flonum_fprint(stream
, val
, pp
, atsign
);
1800 for (i
= 0; i
< ee
; i
++)
1801 xlputc(stream
, ' ');
1805 pp
[1] = (pp
[1] >= 0) ? d
: -1; /* to get zeros trimmed */
1807 flonum_eprint(stream
, val
, pp
, atsign
);
1814 LOCAL VOID tab_print
P3C(LVAL
, stream
, FIXTYPE
*, pp
, int, atsign
)
1816 int pos
= xlgetcolumn(stream
); /* where are we now??? */
1817 int count
; /* number of spaces to insert */
1818 int column
= (int)pp
[0]; /* desired column */
1819 int colinc
= (int)pp
[1]; /* desired column increment */
1821 if (column
< 0) column
= 1; /* handle defaults */
1822 if (colinc
< 0) colinc
= 1;
1824 if (atsign
) { /* relative */
1825 if (colinc
== 0) colinc
= 1;
1826 count
= column
+ (colinc
- (pos
+ column
) % colinc
) % colinc
;
1828 else { /* absolute */
1829 if (pos
>= column
) {
1831 int k
= (pos
+ (colinc
-1) - column
)/colinc
;
1832 count
= column
-pos
+ k
*colinc
;
1833 if (count
==0) count
= colinc
;
1837 else count
= column
- pos
;
1840 xlputc(stream
, ' ');
1843 LOCAL VOID indirect_print
P2C(LVAL
, stream
, int, atsign
)
1845 LVAL
*oldargv
, lfmt
, args
;
1848 lfmt
= xlgastring();
1850 if (atsign
) xlformat(lfmt
, stream
);
1856 for (xlargc
= 0; consp(args
); args
= cdr(args
), xlargc
++)
1858 xlformat(lfmt
, stream
);
1864 /* adapted from changecase in xlstr.c */
1865 LOCAL VOID case_convert_print
P4C(char *, fmt
, LVAL
, stream
, int, colon
, int, atsign
)
1870 int lastspace
= TRUE
;
1876 lfmt
= cvstring(fmt
);
1879 xlformat(lfmt
, tmp
);
1881 if (colon
&& atsign
) fcn
= 'U';
1882 else if (colon
) fcn
= 'C';
1883 else if (atsign
) fcn
= 'S';
1886 while ((ch
= xlgetc(tmp
)) != EOF
) {
1888 case 'U': if (ISLOWER(ch
)) ch
= TOUPPER(ch
); break;
1889 case 'D': if (ISUPPER(ch
)) ch
= TOLOWER(ch
); break;
1890 case 'C': if (lastspace
&& ISLOWER(ch
)) ch
= TOUPPER(ch
);
1891 if (!lastspace
&& ISUPPER(ch
)) ch
= TOLOWER(ch
);
1892 lastspace
= !ISLOWERA(ch
) && !ISUPPER(ch
);
1894 case 'S': if (lastspace
&& ISLOWER(ch
)) ch
= TOUPPER(ch
);
1895 if (!lastspace
&& ISUPPER(ch
)) ch
= TOLOWER(ch
);
1896 if (ISUPPER(ch
)) lastspace
= FALSE
;
1905 LOCAL VOID conditional_print
P5C(char *, fmt
, LVAL
, stream
,
1906 FIXTYPE
, count
, int, colon
, int, atsign
)
1913 lfmt
= cvstring(fmt
);
1916 if (! null(xlgetarg())) {
1919 xlformat(lfmt
, stream
);
1923 if (! null(xlgetarg())) {
1924 fmt
= skip_past_directive(fmt
, ';', FALSE
);
1925 if (fmt
== NULL
) xlerror("missing 'true' clause", lfmt
);
1926 lfmt
= cvstring(fmt
);
1928 xlformat(lfmt
, stream
);
1931 if (count
< 0) count
= getfixnum(xlgafixnum());
1933 while (count
-- > 0) {
1934 fmt
= skip_past_directive(fmt
, ';', FALSE
);
1935 if (fmt
== NULL
) break;
1938 fmt
= skip_past_directive(oldfmt
, ';', TRUE
);
1940 lfmt
= cvstring(fmt
);
1941 xlformat(lfmt
, stream
);
1950 /* this does not support the termination directive ~^ */
1951 LOCAL VOID iterative_print
P5C(char *, fmt
,
1957 LVAL lfmt
, args
= NIL
, alist
;
1958 LVAL
*oldargv
= NULL
, *oldsp
= NULL
;
1959 int oldargc
= 0, once
;
1960 int npp
; /* number of prefix parameters */
1961 FIXTYPE pp
[MAXNPP
]; /* list of prefix parameters */
1962 int tcolon
, tatsign
;
1966 lfmt
= cvstring(fmt
);
1967 once
= (skip_past_directive(fmt
, '}', TRUE
) == NULL
) ? FALSE
: TRUE
;
1969 *decode_pp(fmt
+ 1, pp
, MAXNPP
, &npp
, &tcolon
, &tatsign
, lfmt
) == '}')
1970 lfmt
= xlgastring();
1971 if (! atsign
) args
= xlgetarg();
1973 if (! atsign
|| colon
) {
1983 for (; (oldargc
> 0 || once
) && count
!= 0; oldargc
--, count
--) {
1989 for (; consp(alist
); alist
= cdr(alist
)) {
1990 pusharg(car(alist
));
1993 xlformat(lfmt
, stream
);
1997 for (; (consp(args
) || once
) && count
!= 0; args
= cdr(args
), count
--) {
2003 for (; consp(alist
); alist
= cdr(alist
)) {
2004 pusharg(car(alist
));
2007 xlformat(lfmt
, stream
);
2013 for (; consp(args
); args
= cdr(args
)) {
2018 while ((xlargc
> 0 || once
) && count
-- != 0) {
2020 if (--xlsample
<= 0) {
2024 xlformat(lfmt
, stream
);
2028 if (! atsign
|| colon
) {
2036 /* skip prefix parameters and modifiers for a format directive */
2037 LOCAL
char *skip_pp
P3C(char *, fmt
,
2038 int *, colon
, /* colon modifier given? */
2039 int *, atsign
) /* atsign modifier given? */
2044 if (*fmt
== '\'') fmt
+= 2; /* character code */
2045 else if (*fmt
== '#') fmt
++; /* xlargc is value */
2046 else if (*fmt
== 'v' || *fmt
== 'V') fmt
++; /* lisp arg is value */
2047 else if (isdigit(*fmt
)) /* integer literal */
2048 do { fmt
++; } while (isdigit(*fmt
));
2049 else if (*fmt
== ',') { /* empty field */
2051 else break; /* nothing to process */
2053 if (*fmt
!= ',') break; /* no comma -- done */
2054 fmt
++; /* toss comma */
2057 do { /* pick up any colon or atsign modifier */
2058 if (*fmt
== ':') *colon
= 1;
2059 else if (*fmt
== '@') *atsign
= 1;
2066 LOCAL
char *skip_past_directive
P3C(char *, fmt
,
2071 int colon
, atsign
; /* : and @ modifiers given? */
2074 /* process the format string */
2075 while ((ch
= *fmt
++) != 0)
2077 fmt
= skip_pp(fmt
, &colon
, &atsign
);
2079 if (! nesting
&& (! want_colon
|| colon
) && ch
== tch
)
2093 if (nesting
< 0) break;
2098 /* xlformat - formatted output function */
2099 /* TAA MOD 6/22/93 -- split out from xformat so routine can
2100 be called internally by xerror() and xcerror() */
2101 VOID xlformat
P2C(LVAL
, lfmt
, LVAL
, stream
)
2104 int npp
; /* number of prefix parameters */
2105 FIXTYPE pp
[MAXNPP
]; /* list of prefix parameters */
2106 int colon
, atsign
; /* : and @ modifiers given? */
2107 char *fmt
= getstring(lfmt
);
2114 /* process the format string */
2115 while ((ch
= *fmt
++) != 0)
2117 fmt
= decode_pp( fmt
, pp
, MAXNPP
, &npp
, &colon
, &atsign
, lfmt
);
2119 if (ISLOWER7(ch
)) ch
= toupper(ch
);
2122 xlerror("expecting a format directive",cvstring(fmt
-1));
2124 opt_print(stream
,xlgetarg(),FALSE
,pp
,colon
,atsign
);
2127 opt_print(stream
,xlgetarg(),TRUE
,pp
,colon
,atsign
);
2131 if (npp
> 3) toomanyopt(lfmt
);
2132 integer_print(stream
,xlgetarg(),ch
,pp
,atsign
);
2139 if (npp
> 4) toomanyopt(lfmt
);
2140 integer_print(stream
,xlgetarg(),ch
,pp
,atsign
);
2143 if (npp
> 7) toomanyopt(lfmt
);
2144 flonum_eprint(stream
,xlgetarg(),pp
,atsign
);
2147 if (npp
> 5) toomanyopt(lfmt
);
2148 flonum_fprint(stream
,xlgetarg(),pp
,atsign
);
2151 if (npp
> 7) toomanyopt(lfmt
);
2152 flonum_gprint(stream
,xlgetarg(),pp
,atsign
);
2155 if ( pp
[0] < 0 ) pp
[0] = 1;
2157 xlfreshline(stream
);
2158 while( (pp
[0])-- > 0 )
2162 if (npp
> 1) toomanyopt(lfmt
);
2164 if (pp
[0] < 0) pp
[0] = 0;
2165 if (pp
[0] > oldargc
) xltoofew();
2166 xlargc
= oldargc
- (int)pp
[0];
2167 xlargv
= oldargv
+ (int)pp
[0];
2170 if (pp
[0] < 0) pp
[0] = 1;
2171 if (pp
[0] > oldargc
- xlargc
) xltoofew();
2172 xlargc
+= (int)pp
[0];
2173 xlargv
-= (int)pp
[0];
2176 if (pp
[0] < 0) pp
[0] = 1;
2177 if (pp
[0] > xlargc
) xltoofew();
2178 xlargc
-= (int)pp
[0];
2179 xlargv
+= (int)pp
[0];
2183 tab_print(stream
,pp
,atsign
);
2186 if( pp
[0] < 0 ) pp
[0] = 1;
2187 while( (pp
[0])-- > 0 )
2191 if( pp
[0] <= 0 ) pp
[0] = 1;
2192 while( (pp
[0])-- > 0 )
2200 while (*fmt
&& *fmt
!= '\n' && isspace(*fmt
))
2204 indirect_print(stream
, atsign
);
2207 if (pp
[0] < 0) pp
[0] = 1;
2208 while ((pp
[0])-- > 0)
2209 xlputc(stream
, '\f');
2212 case_convert_print(fmt
, stream
, colon
, atsign
);
2213 fmt
= skip_past_directive(fmt
, ')', FALSE
);
2214 if (fmt
== NULL
) xlerror("incomplete ( directive", lfmt
);
2217 conditional_print(fmt
, stream
, pp
[0], colon
, atsign
);
2218 fmt
= skip_past_directive(fmt
, ']', FALSE
);
2219 if (fmt
== NULL
) xlerror("incomplete [ directive", lfmt
);
2222 iterative_print(fmt
, stream
, pp
[0], colon
, atsign
);
2223 fmt
= skip_past_directive(fmt
, '}', FALSE
);
2224 if (fmt
== NULL
) xlerror("incomplete { directive", lfmt
);
2232 xlerror("unknown format directive",cvstring(fmt
-1));
2239 /* xformat - formatted output function */
2245 xlsave1(val
); /* TAA fix */
2247 /* get the stream and format string */
2248 stream
= xlgetarg();
2250 val
= stream
= newustream();
2253 if (stream
== s_true
)
2254 stream
= getvalue(s_stdout
);
2255 /* fix from xlispbug.417 */
2256 else if (streamp(stream
)) { /* copied from xlgetfile() */
2257 if (getfile(stream
) == CLOSED
)
2258 xlfail("file not open");
2260 else if (!ustreamp(stream
))
2268 xlformat(lfmt
, stream
);
2270 /* get string if output to string */
2271 if (!null(val
)) val
= getstroutput(val
);
2276 /* return the value */
2281 /* getstroutput - get the output stream string (internal) */
2282 LVAL getstroutput
P1C(LVAL
, stream
)
2286 unsigned len
; /* TAA MOD */
2289 /* compute the length of the stream */
2290 for (len
= 0, next
= gethead(stream
); consp(next
); next
= cdr(next
)) {
2292 /****if (len > MAXSLEN)
2293 xltoolong();*/ /* TAA MOD addition for overflow detect */
2296 /* create a new string */
2298 val
= newstring(len
);
2301 /* copy the characters into the new string */
2302 str
= getstring(val
);
2303 while ((ch
= xlgetc(stream
)) != EOF
)
2307 /* return the string */