write.c revision 5dfecf96
15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/write.c,v 1.31tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "lisp/write.h"
335dfecf96Smrg#include "lisp/hash.h"
345dfecf96Smrg#include <math.h>
355dfecf96Smrg#include <ctype.h>
365dfecf96Smrg
375dfecf96Smrg#define	FLOAT_PREC	17
385dfecf96Smrg
395dfecf96Smrg#define UPCASE		0
405dfecf96Smrg#define DOWNCASE	1
415dfecf96Smrg#define CAPITALIZE	2
425dfecf96Smrg
435dfecf96Smrg#define INCDEPTH()							\
445dfecf96Smrg    if (++info->depth > MAX_STACK_DEPTH / 2)				\
455dfecf96Smrg	LispDestroy("stack overflow")
465dfecf96Smrg#define DECDEPTH()	--info->depth
475dfecf96Smrg
485dfecf96Smrg/*
495dfecf96Smrg * Types
505dfecf96Smrg */
515dfecf96Smrgtypedef struct _circle_info {
525dfecf96Smrg    long circle_nth;		/* nth circular list */
535dfecf96Smrg    LispObj *object;		/* the circular object */
545dfecf96Smrg} circle_info;
555dfecf96Smrg
565dfecf96Smrgtypedef struct _write_info {
575dfecf96Smrg    long depth;
585dfecf96Smrg    long level;			/* current level */
595dfecf96Smrg    long length;		/* current length */
605dfecf96Smrg    long print_level;		/* *print-level* when started printing */
615dfecf96Smrg    long print_length;		/* *print-length* when started printing */
625dfecf96Smrg
635dfecf96Smrg    int print_escape;
645dfecf96Smrg    int print_case;
655dfecf96Smrg
665dfecf96Smrg    long circle_count;
675dfecf96Smrg    /* used while building circle info */
685dfecf96Smrg    LispObj **objects;
695dfecf96Smrg    long num_objects;
705dfecf96Smrg    /* the circular lists */
715dfecf96Smrg    circle_info *circles;
725dfecf96Smrg    long num_circles;
735dfecf96Smrg} write_info;
745dfecf96Smrg
755dfecf96Smrg/*
765dfecf96Smrg * Prototypes
775dfecf96Smrg */
785dfecf96Smrgstatic void check_stream(LispObj*, LispFile**, LispString**, int);
795dfecf96Smrgstatic void parse_double(char*, int*, double, int);
805dfecf96Smrgstatic int float_string_inc(char*, int);
815dfecf96Smrgstatic void format_integer(char*, long, int);
825dfecf96Smrgstatic int LispWriteCPointer(LispObj*, void*);
835dfecf96Smrgstatic int LispWriteCString(LispObj*, char*, long, write_info*);
845dfecf96Smrgstatic int LispDoFormatExponentialFloat(LispObj*, LispObj*,
855dfecf96Smrg					int, int, int*, int, int,
865dfecf96Smrg					int, int, int, int);
875dfecf96Smrg
885dfecf96Smrgstatic int LispWriteInteger(LispObj*, LispObj*);
895dfecf96Smrgstatic int LispWriteCharacter(LispObj*, LispObj*, write_info*);
905dfecf96Smrgstatic int LispWriteString(LispObj*, LispObj*, write_info*);
915dfecf96Smrgstatic int LispWriteFloat(LispObj*, LispObj*);
925dfecf96Smrgstatic int LispWriteAtom(LispObj*, LispObj*, write_info*);
935dfecf96Smrgstatic int LispDoWriteAtom(LispObj*, char*, int, int);
945dfecf96Smrgstatic int LispWriteList(LispObj*, LispObj*, write_info*, int);
955dfecf96Smrgstatic int LispWriteArray(LispObj*, LispObj*, write_info*);
965dfecf96Smrgstatic int LispWriteStruct(LispObj*, LispObj*, write_info*);
975dfecf96Smrgstatic int LispDoWriteObject(LispObj*, LispObj*, write_info*, int);
985dfecf96Smrgstatic void LispBuildCircle(LispObj*, write_info*);
995dfecf96Smrgstatic void LispDoBuildCircle(LispObj*, write_info*);
1005dfecf96Smrgstatic long LispCheckCircle(LispObj*, write_info*);
1015dfecf96Smrgstatic int LispPrintCircle(LispObj*, LispObj*, long, int*, write_info*);
1025dfecf96Smrgstatic int LispWriteAlist(LispObj*, LispArgList*, write_info*);
1035dfecf96Smrg
1045dfecf96Smrg/*
1055dfecf96Smrg * Initialization
1065dfecf96Smrg */
1075dfecf96SmrgLispObj *Oprint_level, *Oprint_length, *Oprint_circle,
1085dfecf96Smrg	*Oprint_escape, *Oprint_case;
1095dfecf96SmrgLispObj *Kupcase, *Kdowncase, *Kcapitalize;
1105dfecf96Smrg
1115dfecf96Smrg/*
1125dfecf96Smrg * Implementation
1135dfecf96Smrg */
1145dfecf96Smrgvoid
1155dfecf96SmrgLispWriteInit(void)
1165dfecf96Smrg{
1175dfecf96Smrg    Oprint_level	= STATIC_ATOM("*PRINT-LEVEL*");
1185dfecf96Smrg    LispProclaimSpecial(Oprint_level, NIL, NIL);
1195dfecf96Smrg    LispExportSymbol(Oprint_level);
1205dfecf96Smrg
1215dfecf96Smrg    Oprint_length	= STATIC_ATOM("*PRINT-LENGTH*");
1225dfecf96Smrg    LispProclaimSpecial(Oprint_length, NIL, NIL);
1235dfecf96Smrg    LispExportSymbol(Oprint_length);
1245dfecf96Smrg
1255dfecf96Smrg    Oprint_circle	= STATIC_ATOM("*PRINT-CIRCLE*");
1265dfecf96Smrg    LispProclaimSpecial(Oprint_circle, T, NIL);
1275dfecf96Smrg    LispExportSymbol(Oprint_circle);
1285dfecf96Smrg
1295dfecf96Smrg    Oprint_escape	= STATIC_ATOM("*PRINT-ESCAPE*");
1305dfecf96Smrg    LispProclaimSpecial(Oprint_escape, T, NIL);
1315dfecf96Smrg    LispExportSymbol(Oprint_escape);
1325dfecf96Smrg
1335dfecf96Smrg    Kupcase		= KEYWORD("UPCASE");
1345dfecf96Smrg    Kdowncase		= KEYWORD("DOWNCASE");
1355dfecf96Smrg    Kcapitalize		= KEYWORD("CAPITALIZE");
1365dfecf96Smrg    Oprint_case		= STATIC_ATOM("*PRINT-CASE*");
1375dfecf96Smrg    LispProclaimSpecial(Oprint_case, Kupcase, NIL);
1385dfecf96Smrg    LispExportSymbol(Oprint_case);
1395dfecf96Smrg}
1405dfecf96Smrg
1415dfecf96SmrgLispObj *
1425dfecf96SmrgLisp_FreshLine(LispBuiltin *builtin)
1435dfecf96Smrg/*
1445dfecf96Smrg fresh-line &optional output-stream
1455dfecf96Smrg */
1465dfecf96Smrg{
1475dfecf96Smrg    LispObj *output_stream;
1485dfecf96Smrg
1495dfecf96Smrg    output_stream = ARGUMENT(0);
1505dfecf96Smrg
1515dfecf96Smrg    if (output_stream == UNSPEC)
1525dfecf96Smrg	output_stream = NIL;
1535dfecf96Smrg    else if (output_stream != NIL) {
1545dfecf96Smrg	CHECK_STREAM(output_stream);
1555dfecf96Smrg    }
1565dfecf96Smrg    if (LispGetColumn(output_stream)) {
1575dfecf96Smrg	LispWriteChar(output_stream, '\n');
1585dfecf96Smrg	if (output_stream == NIL ||
1595dfecf96Smrg	    (output_stream->data.stream.type == LispStreamStandard &&
1605dfecf96Smrg	     output_stream->data.stream.source.file == Stdout))
1615dfecf96Smrg	    LispFflush(Stdout);
1625dfecf96Smrg	return (T);
1635dfecf96Smrg    }
1645dfecf96Smrg
1655dfecf96Smrg    return (NIL);
1665dfecf96Smrg}
1675dfecf96Smrg
1685dfecf96SmrgLispObj *
1695dfecf96SmrgLisp_Prin1(LispBuiltin *builtin)
1705dfecf96Smrg/*
1715dfecf96Smrg prin1 object &optional output-stream
1725dfecf96Smrg */
1735dfecf96Smrg{
1745dfecf96Smrg    LispObj *object, *output_stream;
1755dfecf96Smrg
1765dfecf96Smrg    output_stream = ARGUMENT(1);
1775dfecf96Smrg    object = ARGUMENT(0);
1785dfecf96Smrg
1795dfecf96Smrg    if (output_stream == UNSPEC)
1805dfecf96Smrg	output_stream = NIL;
1815dfecf96Smrg    LispPrint(object, output_stream, 0);
1825dfecf96Smrg
1835dfecf96Smrg    return (object);
1845dfecf96Smrg}
1855dfecf96Smrg
1865dfecf96SmrgLispObj *
1875dfecf96SmrgLisp_Princ(LispBuiltin *builtin)
1885dfecf96Smrg/*
1895dfecf96Smrg princ object &optional output-stream
1905dfecf96Smrg */
1915dfecf96Smrg{
1925dfecf96Smrg    int head;
1935dfecf96Smrg    LispObj *object, *output_stream;
1945dfecf96Smrg
1955dfecf96Smrg    output_stream = ARGUMENT(1);
1965dfecf96Smrg    object = ARGUMENT(0);
1975dfecf96Smrg
1985dfecf96Smrg    if (output_stream == UNSPEC)
1995dfecf96Smrg	output_stream = NIL;
2005dfecf96Smrg    head = lisp__data.env.length;
2015dfecf96Smrg    LispAddVar(Oprint_escape, NIL);
2025dfecf96Smrg    ++lisp__data.env.head;
2035dfecf96Smrg    LispPrint(object, output_stream, 0);
2045dfecf96Smrg    lisp__data.env.head = lisp__data.env.length = head;
2055dfecf96Smrg
2065dfecf96Smrg    return (object);
2075dfecf96Smrg}
2085dfecf96Smrg
2095dfecf96SmrgLispObj *
2105dfecf96SmrgLisp_Print(LispBuiltin *builtin)
2115dfecf96Smrg/*
2125dfecf96Smrg print object &optional output-stream
2135dfecf96Smrg */
2145dfecf96Smrg{
2155dfecf96Smrg    LispObj *object, *output_stream;
2165dfecf96Smrg
2175dfecf96Smrg    output_stream = ARGUMENT(1);
2185dfecf96Smrg    object = ARGUMENT(0);
2195dfecf96Smrg
2205dfecf96Smrg    if (output_stream == UNSPEC)
2215dfecf96Smrg	output_stream = NIL;
2225dfecf96Smrg    LispWriteChar(output_stream, '\n');
2235dfecf96Smrg    LispPrint(object, output_stream, 0);
2245dfecf96Smrg    LispWriteChar(output_stream, ' ');
2255dfecf96Smrg
2265dfecf96Smrg    return (object);
2275dfecf96Smrg}
2285dfecf96Smrg
2295dfecf96SmrgLispObj *
2305dfecf96SmrgLisp_Terpri(LispBuiltin *builtin)
2315dfecf96Smrg/*
2325dfecf96Smrg terpri &optional output-stream
2335dfecf96Smrg */
2345dfecf96Smrg{
2355dfecf96Smrg    LispObj *output_stream;
2365dfecf96Smrg
2375dfecf96Smrg    output_stream = ARGUMENT(0);
2385dfecf96Smrg
2395dfecf96Smrg    if (output_stream == UNSPEC)
2405dfecf96Smrg	output_stream = NIL;
2415dfecf96Smrg    else if (output_stream != NIL) {
2425dfecf96Smrg	CHECK_STREAM(output_stream);
2435dfecf96Smrg    }
2445dfecf96Smrg    LispWriteChar(output_stream, '\n');
2455dfecf96Smrg    if (output_stream == NIL ||
2465dfecf96Smrg	(output_stream->data.stream.type == LispStreamStandard &&
2475dfecf96Smrg	 output_stream->data.stream.source.file == Stdout))
2485dfecf96Smrg	LispFflush(Stdout);
2495dfecf96Smrg
2505dfecf96Smrg    return (NIL);
2515dfecf96Smrg}
2525dfecf96Smrg
2535dfecf96SmrgLispObj *
2545dfecf96SmrgLisp_Write(LispBuiltin *builtin)
2555dfecf96Smrg/*
2565dfecf96Smrg write object &key case circle escape length level lines pretty readably right-margin stream
2575dfecf96Smrg */
2585dfecf96Smrg{
2595dfecf96Smrg    int head = lisp__data.env.length;
2605dfecf96Smrg
2615dfecf96Smrg    LispObj *object, *ocase, *circle, *escape, *length, *level, *stream;
2625dfecf96Smrg
2635dfecf96Smrg    stream = ARGUMENT(10);
2645dfecf96Smrg    level = ARGUMENT(5);
2655dfecf96Smrg    length = ARGUMENT(4);
2665dfecf96Smrg    escape = ARGUMENT(3);
2675dfecf96Smrg    circle = ARGUMENT(2);
2685dfecf96Smrg    ocase = ARGUMENT(1);
2695dfecf96Smrg    object = ARGUMENT(0);
2705dfecf96Smrg
2715dfecf96Smrg    if (stream == UNSPEC)
2725dfecf96Smrg	stream = NIL;
2735dfecf96Smrg    else if (stream != NIL) {
2745dfecf96Smrg	CHECK_STREAM(stream);
2755dfecf96Smrg    }
2765dfecf96Smrg
2775dfecf96Smrg    /* prepare the printer environment */
2785dfecf96Smrg    if (circle != UNSPEC)
2795dfecf96Smrg	LispAddVar(Oprint_circle, circle);
2805dfecf96Smrg    if (length != UNSPEC)
2815dfecf96Smrg	LispAddVar(Oprint_length, length);
2825dfecf96Smrg    if (level != UNSPEC)
2835dfecf96Smrg	LispAddVar(Oprint_level, level);
2845dfecf96Smrg    if (ocase != UNSPEC)
2855dfecf96Smrg	LispAddVar(Oprint_case, ocase);
2865dfecf96Smrg    if (escape != UNSPEC)
2875dfecf96Smrg	LispAddVar(Oprint_escape, escape);
2885dfecf96Smrg
2895dfecf96Smrg    lisp__data.env.head = lisp__data.env.length;
2905dfecf96Smrg
2915dfecf96Smrg    (void)LispWriteObject(stream, object);
2925dfecf96Smrg
2935dfecf96Smrg    lisp__data.env.head = lisp__data.env.length = head;
2945dfecf96Smrg
2955dfecf96Smrg    return (object);
2965dfecf96Smrg}
2975dfecf96Smrg
2985dfecf96SmrgLispObj *
2995dfecf96SmrgLisp_WriteChar(LispBuiltin *builtin)
3005dfecf96Smrg/*
3015dfecf96Smrg write-char character &optional output-stream
3025dfecf96Smrg */
3035dfecf96Smrg{
3045dfecf96Smrg    int ch;
3055dfecf96Smrg
3065dfecf96Smrg    LispObj *character, *output_stream;
3075dfecf96Smrg
3085dfecf96Smrg    output_stream = ARGUMENT(1);
3095dfecf96Smrg    character = ARGUMENT(0);
3105dfecf96Smrg
3115dfecf96Smrg    if (output_stream == UNSPEC)
3125dfecf96Smrg	output_stream = NIL;
3135dfecf96Smrg    CHECK_SCHAR(character);
3145dfecf96Smrg    ch = SCHAR_VALUE(character);
3155dfecf96Smrg
3165dfecf96Smrg    LispWriteChar(output_stream, ch);
3175dfecf96Smrg
3185dfecf96Smrg    return (character);
3195dfecf96Smrg}
3205dfecf96Smrg
3215dfecf96SmrgLispObj *
3225dfecf96SmrgLisp_WriteLine(LispBuiltin *builtin)
3235dfecf96Smrg/*
3245dfecf96Smrg write-line string &optional output-stream &key start end
3255dfecf96Smrg */
3265dfecf96Smrg{
3275dfecf96Smrg    return (LispWriteString_(builtin, 1));
3285dfecf96Smrg}
3295dfecf96Smrg
3305dfecf96SmrgLispObj *
3315dfecf96SmrgLisp_WriteString(LispBuiltin *builtin)
3325dfecf96Smrg/*
3335dfecf96Smrg write-string string &optional output-stream &key start end
3345dfecf96Smrg */
3355dfecf96Smrg{
3365dfecf96Smrg    return (LispWriteString_(builtin, 0));
3375dfecf96Smrg}
3385dfecf96Smrg
3395dfecf96Smrg
3405dfecf96Smrgint
3415dfecf96SmrgLispWriteObject(LispObj *stream, LispObj *object)
3425dfecf96Smrg{
3435dfecf96Smrg    write_info info;
3445dfecf96Smrg    int bytes;
3455dfecf96Smrg    LispObj *level, *length, *circle, *oescape, *ocase;
3465dfecf96Smrg
3475dfecf96Smrg    /* current state */
3485dfecf96Smrg    info.depth = info.level = info.length = 0;
3495dfecf96Smrg
3505dfecf96Smrg    /* maximum level to descend */
3515dfecf96Smrg    level = LispGetVar(Oprint_level);
3525dfecf96Smrg    if (level && INDEXP(level))
3535dfecf96Smrg	info.print_level = FIXNUM_VALUE(level);
3545dfecf96Smrg    else
3555dfecf96Smrg	info.print_level = -1;
3565dfecf96Smrg
3575dfecf96Smrg    /* maximum list length */
3585dfecf96Smrg    length = LispGetVar(Oprint_length);
3595dfecf96Smrg    if (length && INDEXP(length))
3605dfecf96Smrg	info.print_length = FIXNUM_VALUE(length);
3615dfecf96Smrg    else
3625dfecf96Smrg	info.print_length = -1;
3635dfecf96Smrg
3645dfecf96Smrg    /* detect circular/shared objects? */
3655dfecf96Smrg    circle = LispGetVar(Oprint_circle);
3665dfecf96Smrg    info.circle_count = 0;
3675dfecf96Smrg    info.objects = NULL;
3685dfecf96Smrg    info.num_objects = 0;
3695dfecf96Smrg    info.circles = NULL;
3705dfecf96Smrg    info.num_circles = 0;
3715dfecf96Smrg    if (circle && circle != NIL) {
3725dfecf96Smrg	LispBuildCircle(object, &info);
3735dfecf96Smrg	/* free this data now */
3745dfecf96Smrg	if (info.num_objects) {
3755dfecf96Smrg	    LispFree(info.objects);
3765dfecf96Smrg	    info.num_objects = 0;
3775dfecf96Smrg	}
3785dfecf96Smrg    }
3795dfecf96Smrg
3805dfecf96Smrg    /* escape characters and strings? */
3815dfecf96Smrg    oescape = LispGetVar(Oprint_escape);
3825dfecf96Smrg    if (oescape != NULL)
3835dfecf96Smrg	info.print_escape = oescape == NIL;
3845dfecf96Smrg    else
3855dfecf96Smrg	info.print_escape = -1;
3865dfecf96Smrg
3875dfecf96Smrg    /* don't use the default case printing? */
3885dfecf96Smrg    ocase = LispGetVar(Oprint_case);
3895dfecf96Smrg    if (ocase == Kdowncase)
3905dfecf96Smrg	info.print_case = DOWNCASE;
3915dfecf96Smrg    else if (ocase == Kcapitalize)
3925dfecf96Smrg	info.print_case = CAPITALIZE;
3935dfecf96Smrg    else
3945dfecf96Smrg	info.print_case = UPCASE;
3955dfecf96Smrg
3965dfecf96Smrg    bytes = LispDoWriteObject(stream, object, &info, 1);
3975dfecf96Smrg    if (circle && circle != NIL && info.num_circles)
3985dfecf96Smrg	LispFree(info.circles);
3995dfecf96Smrg
4005dfecf96Smrg    return (bytes);
4015dfecf96Smrg}
4025dfecf96Smrg
4035dfecf96Smrgstatic void
4045dfecf96SmrgLispBuildCircle(LispObj *object, write_info *info)
4055dfecf96Smrg{
4065dfecf96Smrg    LispObj *list;
4075dfecf96Smrg
4085dfecf96Smrg    switch (OBJECT_TYPE(object)) {
4095dfecf96Smrg	case LispCons_t:
4105dfecf96Smrg	    LispDoBuildCircle(object, info);
4115dfecf96Smrg	    break;
4125dfecf96Smrg	case LispArray_t:
4135dfecf96Smrg	    /* Currently arrays are implemented as lists, but only
4145dfecf96Smrg	     * the elements could/should be circular */
4155dfecf96Smrg	    if (LispCheckCircle(object, info) >= 0)
4165dfecf96Smrg		return;
4175dfecf96Smrg	    LispDoBuildCircle(object, info);
4185dfecf96Smrg	    for (list = object->data.array.list;
4195dfecf96Smrg		 CONSP(list); list = CDR(list))
4205dfecf96Smrg		LispBuildCircle(CAR(list), info);
4215dfecf96Smrg	    break;
4225dfecf96Smrg	case LispStruct_t:
4235dfecf96Smrg	    /* Like arrays, structs are currently implemented as lists,
4245dfecf96Smrg	     * but only the elements could/should be circular */
4255dfecf96Smrg	    if (LispCheckCircle(object, info) >= 0)
4265dfecf96Smrg		return;
4275dfecf96Smrg	    LispDoBuildCircle(object, info);
4285dfecf96Smrg	    for (list = object->data.struc.fields;
4295dfecf96Smrg		 CONSP(list); list = CDR(list))
4305dfecf96Smrg		LispBuildCircle(CAR(list), info);
4315dfecf96Smrg	    break;
4325dfecf96Smrg	case LispQuote_t:
4335dfecf96Smrg	case LispBackquote_t:
4345dfecf96Smrg	case LispFunctionQuote_t:
4355dfecf96Smrg	    LispDoBuildCircle(object, info);
4365dfecf96Smrg	    LispBuildCircle(object->data.quote, info);
4375dfecf96Smrg	    break;
4385dfecf96Smrg	case LispComma_t:
4395dfecf96Smrg	    LispDoBuildCircle(object, info);
4405dfecf96Smrg	    LispBuildCircle(object->data.comma.eval, info);
4415dfecf96Smrg	    break;
4425dfecf96Smrg	case LispLambda_t:
4435dfecf96Smrg	    /* Circularity in a function body should fail elsewhere... */
4445dfecf96Smrg	    if (LispCheckCircle(object, info) >= 0)
4455dfecf96Smrg		return;
4465dfecf96Smrg	    LispDoBuildCircle(object, info);
4475dfecf96Smrg	    LispBuildCircle(object->data.lambda.code, info);
4485dfecf96Smrg	    break;
4495dfecf96Smrg	default:
4505dfecf96Smrg	    break;
4515dfecf96Smrg    }
4525dfecf96Smrg}
4535dfecf96Smrg
4545dfecf96Smrgstatic void
4555dfecf96SmrgLispDoBuildCircle(LispObj *object, write_info *info)
4565dfecf96Smrg{
4575dfecf96Smrg    long i;
4585dfecf96Smrg
4595dfecf96Smrg    if (LispCheckCircle(object, info) >= 0)
4605dfecf96Smrg	return;
4615dfecf96Smrg
4625dfecf96Smrg    for (i = 0; i < info->num_objects; i++)
4635dfecf96Smrg	if (info->objects[i] == object) {
4645dfecf96Smrg	    /* circularity found */
4655dfecf96Smrg	    info->circles = LispRealloc(info->circles, sizeof(circle_info) *
4665dfecf96Smrg					(info->num_circles + 1));
4675dfecf96Smrg	    info->circles[info->num_circles].circle_nth = 0;
4685dfecf96Smrg	    info->circles[info->num_circles].object = object;
4695dfecf96Smrg	    ++info->num_circles;
4705dfecf96Smrg	    return;
4715dfecf96Smrg	}
4725dfecf96Smrg
4735dfecf96Smrg    /* object pointer not yet recorded */
4745dfecf96Smrg    if ((i % 16) == 0)
4755dfecf96Smrg	info->objects = LispRealloc(info->objects, sizeof(LispObj*) *
4765dfecf96Smrg				    (info->num_objects + 16));
4775dfecf96Smrg    info->objects[info->num_objects++] = object;
4785dfecf96Smrg
4795dfecf96Smrg    if (CONSP(object)) {
4805dfecf96Smrg	if (CONSP(CAR(object)))
4815dfecf96Smrg	    LispDoBuildCircle(CAR(object), info);
4825dfecf96Smrg	else
4835dfecf96Smrg	    LispBuildCircle(CAR(object), info);
4845dfecf96Smrg	if (CONSP(CDR(object)))
4855dfecf96Smrg	    LispDoBuildCircle(CDR(object), info);
4865dfecf96Smrg	else
4875dfecf96Smrg	    LispBuildCircle(CDR(object), info);
4885dfecf96Smrg    }
4895dfecf96Smrg}
4905dfecf96Smrg
4915dfecf96Smrgstatic long
4925dfecf96SmrgLispCheckCircle(LispObj *object, write_info *info)
4935dfecf96Smrg{
4945dfecf96Smrg    long i;
4955dfecf96Smrg
4965dfecf96Smrg    for (i = 0; i < info->num_circles; i++)
4975dfecf96Smrg	if (info->circles[i].object == object)
4985dfecf96Smrg	    return (i);
4995dfecf96Smrg
5005dfecf96Smrg    return (-1);
5015dfecf96Smrg}
5025dfecf96Smrg
5035dfecf96Smrgstatic int
5045dfecf96SmrgLispPrintCircle(LispObj *stream, LispObj *object, long circle,
5055dfecf96Smrg		int *length, write_info *info)
5065dfecf96Smrg{
5075dfecf96Smrg    char stk[32];
5085dfecf96Smrg
5095dfecf96Smrg    if (!info->circles[circle].circle_nth) {
5105dfecf96Smrg	sprintf(stk, "#%ld=", ++info->circle_count);
5115dfecf96Smrg	*length += LispWriteStr(stream, stk, strlen(stk));
5125dfecf96Smrg	info->circles[circle].circle_nth = info->circle_count;
5135dfecf96Smrg
5145dfecf96Smrg	return (1);
5155dfecf96Smrg    }
5165dfecf96Smrg    sprintf(stk, "#%ld#", info->circles[circle].circle_nth);
5175dfecf96Smrg    *length += LispWriteStr(stream, stk, strlen(stk));
5185dfecf96Smrg
5195dfecf96Smrg    return (0);
5205dfecf96Smrg}
5215dfecf96Smrg
5225dfecf96Smrgstatic int
5235dfecf96SmrgLispWriteAlist(LispObj *stream, LispArgList *alist, write_info *info)
5245dfecf96Smrg{
5255dfecf96Smrg    char *name;
5265dfecf96Smrg    int i, length = 0, need_space = 0;
5275dfecf96Smrg
5285dfecf96Smrg#define WRITE_ATOM(object)						\
5295dfecf96Smrg    name = ATOMID(object);						\
5305dfecf96Smrg    length += LispDoWriteAtom(stream, name, strlen(name),		\
5315dfecf96Smrg			      info->print_case)
5325dfecf96Smrg#define WRITE_STRING(string)						\
5335dfecf96Smrg    length += LispDoWriteAtom(stream, string, strlen(string),		\
5345dfecf96Smrg			      info->print_case)
5355dfecf96Smrg#define WRITE_OBJECT(object)						\
5365dfecf96Smrg    length += LispDoWriteObject(stream, object, info, 1)
5375dfecf96Smrg#define WRITE_OPAREN()							\
5385dfecf96Smrg    length += LispWriteChar(stream, '(')
5395dfecf96Smrg#define WRITE_SPACE()							\
5405dfecf96Smrg    length += LispWriteChar(stream, ' ')
5415dfecf96Smrg#define WRITE_CPAREN()							\
5425dfecf96Smrg    length += LispWriteChar(stream, ')')
5435dfecf96Smrg
5445dfecf96Smrg    WRITE_OPAREN();
5455dfecf96Smrg    for (i = 0; i < alist->normals.num_symbols; i++) {
5465dfecf96Smrg	WRITE_ATOM(alist->normals.symbols[i]);
5475dfecf96Smrg	if (i + 1 < alist->normals.num_symbols)
5485dfecf96Smrg	    WRITE_SPACE();
5495dfecf96Smrg	else
5505dfecf96Smrg	    need_space = 1;
5515dfecf96Smrg    }
5525dfecf96Smrg    if (alist->optionals.num_symbols) {
5535dfecf96Smrg	if (need_space)
5545dfecf96Smrg	    WRITE_SPACE();
5555dfecf96Smrg	WRITE_STRING(Soptional);
5565dfecf96Smrg	WRITE_SPACE();
5575dfecf96Smrg	for (i = 0; i < alist->optionals.num_symbols; i++) {
5585dfecf96Smrg	    WRITE_OPAREN();
5595dfecf96Smrg	    WRITE_ATOM(alist->optionals.symbols[i]);
5605dfecf96Smrg	    WRITE_SPACE();
5615dfecf96Smrg	    WRITE_OBJECT(alist->optionals.defaults[i]);
5625dfecf96Smrg	    if (alist->optionals.sforms[i]) {
5635dfecf96Smrg		WRITE_SPACE();
5645dfecf96Smrg		WRITE_ATOM(alist->optionals.sforms[i]);
5655dfecf96Smrg	    }
5665dfecf96Smrg	    WRITE_CPAREN();
5675dfecf96Smrg	    if (i + 1 < alist->optionals.num_symbols)
5685dfecf96Smrg		WRITE_SPACE();
5695dfecf96Smrg	}
5705dfecf96Smrg	need_space = 1;
5715dfecf96Smrg    }
5725dfecf96Smrg    if (alist->keys.num_symbols) {
5735dfecf96Smrg	if (need_space)
5745dfecf96Smrg	    WRITE_SPACE();
5755dfecf96Smrg	length += LispDoWriteAtom(stream, Skey, 4, info->print_case);
5765dfecf96Smrg	WRITE_SPACE();
5775dfecf96Smrg	for (i = 0; i < alist->keys.num_symbols; i++) {
5785dfecf96Smrg	    WRITE_OPAREN();
5795dfecf96Smrg	    if (alist->keys.keys[i]) {
5805dfecf96Smrg		WRITE_OPAREN();
5815dfecf96Smrg		WRITE_ATOM(alist->keys.keys[i]);
5825dfecf96Smrg		WRITE_SPACE();
5835dfecf96Smrg	    }
5845dfecf96Smrg	    WRITE_ATOM(alist->keys.symbols[i]);
5855dfecf96Smrg	    if (alist->keys.keys[i])
5865dfecf96Smrg		WRITE_CPAREN();
5875dfecf96Smrg	    WRITE_SPACE();
5885dfecf96Smrg	    WRITE_OBJECT(alist->keys.defaults[i]);
5895dfecf96Smrg	    if (alist->keys.sforms[i]) {
5905dfecf96Smrg		WRITE_SPACE();
5915dfecf96Smrg		WRITE_ATOM(alist->keys.sforms[i]);
5925dfecf96Smrg	    }
5935dfecf96Smrg	    WRITE_CPAREN();
5945dfecf96Smrg	    if (i + 1 < alist->keys.num_symbols)
5955dfecf96Smrg		WRITE_SPACE();
5965dfecf96Smrg	}
5975dfecf96Smrg	need_space = 1;
5985dfecf96Smrg    }
5995dfecf96Smrg    if (alist->rest) {
6005dfecf96Smrg	if (need_space)
6015dfecf96Smrg	    WRITE_SPACE();
6025dfecf96Smrg	WRITE_STRING(Srest);
6035dfecf96Smrg	WRITE_SPACE();
6045dfecf96Smrg	WRITE_ATOM(alist->rest);
6055dfecf96Smrg	need_space = 1;
6065dfecf96Smrg    }
6075dfecf96Smrg    if (alist->auxs.num_symbols) {
6085dfecf96Smrg	if (need_space)
6095dfecf96Smrg	    WRITE_SPACE();
6105dfecf96Smrg	WRITE_STRING(Saux);
6115dfecf96Smrg	WRITE_SPACE();
6125dfecf96Smrg	for (i = 0; i < alist->auxs.num_symbols; i++) {
6135dfecf96Smrg	    WRITE_OPAREN();
6145dfecf96Smrg	    WRITE_ATOM(alist->auxs.symbols[i]);
6155dfecf96Smrg	    WRITE_SPACE();
6165dfecf96Smrg	    WRITE_OBJECT(alist->auxs.initials[i]);
6175dfecf96Smrg	    WRITE_CPAREN();
6185dfecf96Smrg	    if (i + 1 < alist->auxs.num_symbols)
6195dfecf96Smrg		WRITE_SPACE();
6205dfecf96Smrg	}
6215dfecf96Smrg    }
6225dfecf96Smrg    WRITE_CPAREN();
6235dfecf96Smrg
6245dfecf96Smrg#undef WRITE_ATOM
6255dfecf96Smrg#undef WRITE_STRING
6265dfecf96Smrg#undef WRITE_OBJECT
6275dfecf96Smrg#undef WRITE_OPAREN
6285dfecf96Smrg#undef WRITE_SPACE
6295dfecf96Smrg#undef WRITE_CPAREN
6305dfecf96Smrg
6315dfecf96Smrg    return (length);
6325dfecf96Smrg}
6335dfecf96Smrg
6345dfecf96Smrgstatic void
6355dfecf96Smrgcheck_stream(LispObj *stream,
6365dfecf96Smrg	     LispFile **file, LispString **string, int check_writable)
6375dfecf96Smrg{
6385dfecf96Smrg    /* NIL is UNIX stdout, *STANDARD-OUTPUT* may not be UNIX stdout */
6395dfecf96Smrg    if (stream == NIL) {
6405dfecf96Smrg	*file = Stdout;
6415dfecf96Smrg	*string = NULL;
6425dfecf96Smrg    }
6435dfecf96Smrg    else {
6445dfecf96Smrg	if (!STREAMP(stream))
6455dfecf96Smrg	    LispDestroy("%s is not a stream", STROBJ(stream));
6465dfecf96Smrg	if (check_writable && !stream->data.stream.writable)
6475dfecf96Smrg	    LispDestroy("%s is not writable", STROBJ(stream));
6485dfecf96Smrg	else if (stream->data.stream.type == LispStreamString) {
6495dfecf96Smrg	    *string = SSTREAMP(stream);
6505dfecf96Smrg	    *file = NULL;
6515dfecf96Smrg	}
6525dfecf96Smrg	else {
6535dfecf96Smrg	    if (stream->data.stream.type == LispStreamPipe)
6545dfecf96Smrg		*file = OPSTREAMP(stream);
6555dfecf96Smrg	    else
6565dfecf96Smrg		*file = stream->data.stream.source.file;
6575dfecf96Smrg	    *string = NULL;
6585dfecf96Smrg	}
6595dfecf96Smrg    }
6605dfecf96Smrg}
6615dfecf96Smrg
6625dfecf96Smrg/* Assumes buffer has enough storage, 64 bytes should be more than enough */
6635dfecf96Smrgstatic void
6645dfecf96Smrgparse_double(char *buffer, int *exponent, double value, int d)
6655dfecf96Smrg{
6665dfecf96Smrg    char stk[64], fmt[32], *ptr, *fract = NULL;
6675dfecf96Smrg    int positive = value >= 0.0;
6685dfecf96Smrg
6695dfecf96Smrgparse_double_again:
6705dfecf96Smrg    if (d >= 8) {
6715dfecf96Smrg	double dcheck;
6725dfecf96Smrg	int icheck, count;
6735dfecf96Smrg
6745dfecf96Smrg	/* this should to do the correct rounding */
6755dfecf96Smrg	for (count = 2;  count >= 0; count--) {
6765dfecf96Smrg	    icheck = d <= 0 ? 0 : d > FLOAT_PREC ? FLOAT_PREC - count : d - count;
6775dfecf96Smrg	    sprintf(fmt, "%%.%de", icheck);
6785dfecf96Smrg	    sprintf(stk, fmt, value);
6795dfecf96Smrg	    if (count) {
6805dfecf96Smrg		/* if the value read back is the same formatted */
6815dfecf96Smrg		sscanf(stk, "%lf", &dcheck);
6825dfecf96Smrg		if (dcheck == value)
6835dfecf96Smrg		    break;
6845dfecf96Smrg	    }
6855dfecf96Smrg	}
6865dfecf96Smrg    }
6875dfecf96Smrg    else {
6885dfecf96Smrg	sprintf(fmt, "%%.%de", d <= 0 ? 0 : d > FLOAT_PREC ? FLOAT_PREC : d);
6895dfecf96Smrg	sprintf(stk, fmt, value);
6905dfecf96Smrg    }
6915dfecf96Smrg
6925dfecf96Smrg    /* this "should" never fail */
6935dfecf96Smrg    ptr = strchr(stk, 'e');
6945dfecf96Smrg    if (ptr) {
6955dfecf96Smrg	*ptr++ = '\0';
6965dfecf96Smrg	*exponent = atoi(ptr);
6975dfecf96Smrg    }
6985dfecf96Smrg    else
6995dfecf96Smrg	*exponent = 0;
7005dfecf96Smrg
7015dfecf96Smrg    /* find start of number representation */
7025dfecf96Smrg    for (ptr = stk; *ptr && !isdigit(*ptr); ptr++)
7035dfecf96Smrg	;
7045dfecf96Smrg
7055dfecf96Smrg    /* check if did not trim any significant digit,
7065dfecf96Smrg     * this may happen because '%.e' puts only one digit before the '.' */
7075dfecf96Smrg    if (d > 0 && d < FLOAT_PREC && fabs(value) >= 10.0 &&
7085dfecf96Smrg	strlen(ptr) - 1 - !positive <= *exponent) {
7095dfecf96Smrg	d += *exponent - (strlen(ptr) - 1 - !positive) + 1;
7105dfecf96Smrg	goto parse_double_again;
7115dfecf96Smrg    }
7125dfecf96Smrg
7135dfecf96Smrg    /* this "should" never fail */
7145dfecf96Smrg    fract = strchr(ptr, '.');
7155dfecf96Smrg    if (fract)
7165dfecf96Smrg	*fract++ = '\0';
7175dfecf96Smrg
7185dfecf96Smrg    /* store number representation in buffer */
7195dfecf96Smrg    *buffer = positive ? '+' : '-';
7205dfecf96Smrg    strcpy(buffer + 1, ptr);
7215dfecf96Smrg    if (fract)
7225dfecf96Smrg	strcpy(buffer + strlen(buffer), fract);
7235dfecf96Smrg}
7245dfecf96Smrg
7255dfecf96Smrgstatic void
7265dfecf96Smrgformat_integer(char *buffer, long value, int radix)
7275dfecf96Smrg{
7285dfecf96Smrg    if (radix == 10)
7295dfecf96Smrg	sprintf(buffer, "%ld", value);
7305dfecf96Smrg    else if (radix == 16)
7315dfecf96Smrg	sprintf(buffer, "%lx", value);
7325dfecf96Smrg    else if (radix == 8)
7335dfecf96Smrg	sprintf(buffer, "%lo", value);
7345dfecf96Smrg    else {
7355dfecf96Smrg	/* use bignum routine to convert number to string */
7365dfecf96Smrg	mpi integer;
7375dfecf96Smrg
7385dfecf96Smrg	mpi_init(&integer);
7395dfecf96Smrg	mpi_seti(&integer, value);
7405dfecf96Smrg	mpi_getstr(buffer, &integer, radix);
7415dfecf96Smrg	mpi_clear(&integer);
7425dfecf96Smrg    }
7435dfecf96Smrg}
7445dfecf96Smrg
7455dfecf96Smrgstatic int
7465dfecf96SmrgLispWriteCPointer(LispObj *stream, void *data)
7475dfecf96Smrg{
7485dfecf96Smrg    char stk[32];
7495dfecf96Smrg
7505dfecf96Smrg#ifdef LONG64
7515dfecf96Smrg    sprintf(stk, "0x%016lx", (long)data);
7525dfecf96Smrg#else
7535dfecf96Smrg    sprintf(stk, "0x%08lx", (long)data);
7545dfecf96Smrg#endif
7555dfecf96Smrg
7565dfecf96Smrg    return (LispWriteStr(stream, stk, strlen(stk)));
7575dfecf96Smrg}
7585dfecf96Smrg
7595dfecf96Smrgstatic int
7605dfecf96SmrgLispWriteCString(LispObj *stream, char *string, long length, write_info *info)
7615dfecf96Smrg{
7625dfecf96Smrg    int result;
7635dfecf96Smrg
7645dfecf96Smrg    if (!info->print_escape) {
7655dfecf96Smrg	char *base, *ptr, *end;
7665dfecf96Smrg
7675dfecf96Smrg	result = LispWriteChar(stream, '"');
7685dfecf96Smrg	for (base = ptr = string, end = string + length; ptr < end; ptr++) {
7695dfecf96Smrg	    if (*ptr == '\\' || *ptr == '"') {
7705dfecf96Smrg		result += LispWriteStr(stream, base, ptr - base);
7715dfecf96Smrg		result += LispWriteChar(stream, '\\');
7725dfecf96Smrg		result += LispWriteChar(stream, *ptr);
7735dfecf96Smrg		base = ptr + 1;
7745dfecf96Smrg	    }
7755dfecf96Smrg	}
7765dfecf96Smrg	result += LispWriteStr(stream, base, end - base);
7775dfecf96Smrg	result += LispWriteChar(stream, '"');
7785dfecf96Smrg    }
7795dfecf96Smrg    else
7805dfecf96Smrg	result = LispWriteStr(stream, string, length);
7815dfecf96Smrg
7825dfecf96Smrg    return (result);
7835dfecf96Smrg}
7845dfecf96Smrg
7855dfecf96Smrgstatic int
7865dfecf96SmrgLispWriteList(LispObj *stream, LispObj *object, write_info *info, int paren)
7875dfecf96Smrg{
7885dfecf96Smrg    int length = 0;
7895dfecf96Smrg    long circle = 0;
7905dfecf96Smrg
7915dfecf96Smrg    INCDEPTH();
7925dfecf96Smrg    if (info->print_level < 0 || info->level <= info->print_level) {
7935dfecf96Smrg	LispObj *car, *cdr;
7945dfecf96Smrg	long print_length = info->length;
7955dfecf96Smrg
7965dfecf96Smrg	if (info->circles && (circle = LispCheckCircle(object, info)) >= 0) {
7975dfecf96Smrg	    if (!paren) {
7985dfecf96Smrg		length += LispWriteStr(stream, ". ", 2);
7995dfecf96Smrg		paren = 1;
8005dfecf96Smrg	    }
8015dfecf96Smrg	    if (LispPrintCircle(stream, object, circle, &length, info) == 0) {
8025dfecf96Smrg		DECDEPTH();
8035dfecf96Smrg
8045dfecf96Smrg		return (length);
8055dfecf96Smrg	    }
8065dfecf96Smrg	}
8075dfecf96Smrg
8085dfecf96Smrg	car = CAR(object);
8095dfecf96Smrg	cdr = CDR(object);
8105dfecf96Smrg
8115dfecf96Smrg	if (cdr == NIL) {
8125dfecf96Smrg	    if (paren)
8135dfecf96Smrg		length += LispWriteChar(stream, '(');
8145dfecf96Smrg	    if (info->print_length < 0 || info->length < info->print_length) {
8155dfecf96Smrg		info->length = 0;
8165dfecf96Smrg		length += LispDoWriteObject(stream, car, info, 1);
8175dfecf96Smrg		info->length = print_length + 1;
8185dfecf96Smrg	    }
8195dfecf96Smrg	    else
8205dfecf96Smrg		length += LispWriteStr(stream, "...", 3);
8215dfecf96Smrg	    if (paren)
8225dfecf96Smrg		length += LispWriteChar(stream, ')');
8235dfecf96Smrg	}
8245dfecf96Smrg	else {
8255dfecf96Smrg	    if (paren)
8265dfecf96Smrg		length += LispWriteChar(stream, '(');
8275dfecf96Smrg	    if (info->print_length < 0 || info->length < info->print_length) {
8285dfecf96Smrg		info->length = 0;
8295dfecf96Smrg		length += LispDoWriteObject(stream, car, info, 1);
8305dfecf96Smrg		info->length = print_length + 1;
8315dfecf96Smrg		if (!CONSP(cdr)) {
8325dfecf96Smrg		    length += LispWriteStr(stream, " . ", 3);
8335dfecf96Smrg		    info->length = 0;
8345dfecf96Smrg		    length += LispDoWriteObject(stream, cdr, info, 0);
8355dfecf96Smrg		}
8365dfecf96Smrg		else {
8375dfecf96Smrg		    length += LispWriteChar(stream, ' ');
8385dfecf96Smrg		    if (info->print_length < 0 ||
8395dfecf96Smrg			info->length < info->print_length)
8405dfecf96Smrg			length += LispWriteList(stream, cdr, info, 0);
8415dfecf96Smrg		    else
8425dfecf96Smrg			length += LispWriteStr(stream, "...", 3);
8435dfecf96Smrg		}
8445dfecf96Smrg	    }
8455dfecf96Smrg	    else
8465dfecf96Smrg		length += LispWriteStr(stream, "...", 3);
8475dfecf96Smrg	    if (paren)
8485dfecf96Smrg		length += LispWriteChar(stream, ')');
8495dfecf96Smrg	}
8505dfecf96Smrg	info->length = print_length;
8515dfecf96Smrg    }
8525dfecf96Smrg    else
8535dfecf96Smrg	length += LispWriteChar(stream, '#');
8545dfecf96Smrg    DECDEPTH();
8555dfecf96Smrg
8565dfecf96Smrg    return (length);
8575dfecf96Smrg}
8585dfecf96Smrg
8595dfecf96Smrgstatic int
8605dfecf96SmrgLispDoWriteObject(LispObj *stream, LispObj *object, write_info *info, int paren)
8615dfecf96Smrg{
8625dfecf96Smrg    long print_level;
8635dfecf96Smrg    int length = 0;
8645dfecf96Smrg    char stk[64], *string = NULL;
8655dfecf96Smrg
8665dfecf96Smrgwrite_again:
8675dfecf96Smrg    switch (OBJECT_TYPE(object)) {
8685dfecf96Smrg	case LispNil_t:
8695dfecf96Smrg	    if (object == NIL)
8705dfecf96Smrg		string = Snil;
8715dfecf96Smrg	    else if (object == T)
8725dfecf96Smrg		string = St;
8735dfecf96Smrg	    else if (object == DOT)
8745dfecf96Smrg		string = "#<DOT>";
8755dfecf96Smrg	    else if (object == UNSPEC)
8765dfecf96Smrg		string = "#<UNSPEC>";
8775dfecf96Smrg	    else if (object == UNBOUND)
8785dfecf96Smrg		string = "#<UNBOUND>";
8795dfecf96Smrg	    else
8805dfecf96Smrg		string = "#<ERROR>";
8815dfecf96Smrg	    length += LispDoWriteAtom(stream, string, strlen(string),
8825dfecf96Smrg				      info->print_case);
8835dfecf96Smrg	    break;
8845dfecf96Smrg	case LispOpaque_t: {
8855dfecf96Smrg	    char *desc = LispIntToOpaqueType(object->data.opaque.type);
8865dfecf96Smrg
8875dfecf96Smrg	    length += LispWriteChar(stream, '#');
8885dfecf96Smrg	    length += LispWriteCPointer(stream, object->data.opaque.data);
8895dfecf96Smrg	    length += LispWriteStr(stream, desc, strlen(desc));
8905dfecf96Smrg	}   break;
8915dfecf96Smrg	case LispAtom_t:
8925dfecf96Smrg	    length += LispWriteAtom(stream, object, info);
8935dfecf96Smrg	    break;
8945dfecf96Smrg	case LispFunction_t:
8955dfecf96Smrg	    if (object->data.atom->a_function) {
8965dfecf96Smrg		object = object->data.atom->property->fun.function;
8975dfecf96Smrg		goto write_lambda;
8985dfecf96Smrg	    }
8995dfecf96Smrg	    length += LispWriteStr(stream, "#<", 2);
9005dfecf96Smrg	    if (object->data.atom->a_compiled)
9015dfecf96Smrg		LispDoWriteAtom(stream, "COMPILED", 8, info->print_case);
9025dfecf96Smrg	    else if (object->data.atom->a_builtin)
9035dfecf96Smrg		LispDoWriteAtom(stream, "BUILTIN", 7, info->print_case);
9045dfecf96Smrg	    /* XXX the function does not exist anymore */
9055dfecf96Smrg	    /* FIXME not sure if I want this fixed... */
9065dfecf96Smrg	    else
9075dfecf96Smrg		LispDoWriteAtom(stream, "UNBOUND", 7, info->print_case);
9085dfecf96Smrg	    LispDoWriteAtom(stream, "-FUNCTION", 9, info->print_case);
9095dfecf96Smrg	    length += LispWriteChar(stream, ' ');
9105dfecf96Smrg	    length += LispWriteAtom(stream, object->data.atom->object, info);
9115dfecf96Smrg	    length += LispWriteChar(stream, '>');
9125dfecf96Smrg	    break;
9135dfecf96Smrg	case LispString_t:
9145dfecf96Smrg	    length += LispWriteString(stream, object, info);
9155dfecf96Smrg	    break;
9165dfecf96Smrg	case LispSChar_t:
9175dfecf96Smrg	    length += LispWriteCharacter(stream, object, info);
9185dfecf96Smrg	    break;
9195dfecf96Smrg	case LispDFloat_t:
9205dfecf96Smrg	    length += LispWriteFloat(stream, object);
9215dfecf96Smrg	    break;
9225dfecf96Smrg	case LispFixnum_t:
9235dfecf96Smrg	case LispInteger_t:
9245dfecf96Smrg	case LispBignum_t:
9255dfecf96Smrg	    length += LispWriteInteger(stream, object);
9265dfecf96Smrg	    break;
9275dfecf96Smrg	case LispRatio_t:
9285dfecf96Smrg	    format_integer(stk, object->data.ratio.numerator, 10);
9295dfecf96Smrg	    length += LispWriteStr(stream, stk, strlen(stk));
9305dfecf96Smrg	    length += LispWriteChar(stream, '/');
9315dfecf96Smrg	    format_integer(stk, object->data.ratio.denominator, 10);
9325dfecf96Smrg	    length += LispWriteStr(stream, stk, strlen(stk));
9335dfecf96Smrg	    break;
9345dfecf96Smrg	case LispBigratio_t: {
9355dfecf96Smrg	    int sz;
9365dfecf96Smrg	    char *ptr;
9375dfecf96Smrg
9385dfecf96Smrg	    sz = mpi_getsize(mpr_num(object->data.mp.ratio), 10) + 1 +
9395dfecf96Smrg		 mpi_getsize(mpr_den(object->data.mp.ratio), 10) + 1 +
9405dfecf96Smrg		 (mpi_sgn(mpr_num(object->data.mp.ratio)) < 0);
9415dfecf96Smrg	    if (sz > sizeof(stk))
9425dfecf96Smrg		ptr = LispMalloc(sz);
9435dfecf96Smrg	    else
9445dfecf96Smrg		ptr = stk;
9455dfecf96Smrg	    mpr_getstr(ptr, object->data.mp.ratio, 10);
9465dfecf96Smrg	    length += LispWriteStr(stream, ptr, sz - 1);
9475dfecf96Smrg	    if (ptr != stk)
9485dfecf96Smrg		LispFree(ptr);
9495dfecf96Smrg	}   break;
9505dfecf96Smrg	case LispComplex_t:
9515dfecf96Smrg	    length += LispWriteStr(stream, "#C(", 3);
9525dfecf96Smrg	    length += LispDoWriteObject(stream,
9535dfecf96Smrg					object->data.complex.real, info, 0);
9545dfecf96Smrg	    length += LispWriteChar(stream, ' ');
9555dfecf96Smrg	    length += LispDoWriteObject(stream,
9565dfecf96Smrg					object->data.complex.imag, info, 0);
9575dfecf96Smrg	    length += LispWriteChar(stream, ')');
9585dfecf96Smrg	    break;
9595dfecf96Smrg	case LispCons_t:
9605dfecf96Smrg	    print_level = info->level;
9615dfecf96Smrg	    ++info->level;
9625dfecf96Smrg	    length += LispWriteList(stream, object, info, paren);
9635dfecf96Smrg	    info->level = print_level;
9645dfecf96Smrg	    break;
9655dfecf96Smrg	case LispQuote_t:
9665dfecf96Smrg	    length += LispWriteChar(stream, '\'');
9675dfecf96Smrg	    paren = 1;
9685dfecf96Smrg	    object = object->data.quote;
9695dfecf96Smrg	    goto write_again;
9705dfecf96Smrg	case LispBackquote_t:
9715dfecf96Smrg	    length += LispWriteChar(stream, '`');
9725dfecf96Smrg	    paren = 1;
9735dfecf96Smrg	    object = object->data.quote;
9745dfecf96Smrg	    goto write_again;
9755dfecf96Smrg	case LispComma_t:
9765dfecf96Smrg	    if (object->data.comma.atlist)
9775dfecf96Smrg		length += LispWriteStr(stream, ",@", 2);
9785dfecf96Smrg	    else
9795dfecf96Smrg		length += LispWriteChar(stream, ',');
9805dfecf96Smrg	    paren = 1;
9815dfecf96Smrg	    object = object->data.comma.eval;
9825dfecf96Smrg	    goto write_again;
9835dfecf96Smrg	    break;
9845dfecf96Smrg	case LispFunctionQuote_t:
9855dfecf96Smrg	    length += LispWriteStr(stream, "#'", 2);
9865dfecf96Smrg	    paren = 1;
9875dfecf96Smrg	    object = object->data.quote;
9885dfecf96Smrg	    goto write_again;
9895dfecf96Smrg	case LispArray_t:
9905dfecf96Smrg	    length += LispWriteArray(stream, object, info);
9915dfecf96Smrg	    break;
9925dfecf96Smrg	case LispStruct_t:
9935dfecf96Smrg	    length += LispWriteStruct(stream, object, info);
9945dfecf96Smrg	    break;
9955dfecf96Smrg	case LispLambda_t:
9965dfecf96Smrg	write_lambda:
9975dfecf96Smrg	    switch (object->funtype) {
9985dfecf96Smrg		case LispLambda:
9995dfecf96Smrg		    string = "#<LAMBDA ";
10005dfecf96Smrg		    break;
10015dfecf96Smrg		case LispFunction:
10025dfecf96Smrg		    string = "#<FUNCTION ";
10035dfecf96Smrg		    break;
10045dfecf96Smrg		case LispMacro:
10055dfecf96Smrg		    string = "#<MACRO ";
10065dfecf96Smrg		    break;
10075dfecf96Smrg		case LispSetf:
10085dfecf96Smrg		    string = "#<SETF ";
10095dfecf96Smrg		    break;
10105dfecf96Smrg	    }
10115dfecf96Smrg	    length += LispDoWriteAtom(stream, string, strlen(string),
10125dfecf96Smrg				      info->print_case);
10135dfecf96Smrg	    if (object->funtype != LispLambda) {
10145dfecf96Smrg		length += LispWriteAtom(stream, object->data.lambda.name, info);
10155dfecf96Smrg		length += LispWriteChar(stream, ' ');
10165dfecf96Smrg		length += LispWriteAlist(stream, object->data.lambda.name
10175dfecf96Smrg					 ->data.atom->property->alist, info);
10185dfecf96Smrg	    }
10195dfecf96Smrg	    else {
10205dfecf96Smrg		length += LispDoWriteAtom(stream, Snil, 3, info->print_case);
10215dfecf96Smrg		length += LispWriteChar(stream, ' ');
10225dfecf96Smrg		length += LispWriteAlist(stream, (LispArgList*)object->
10235dfecf96Smrg					 data.lambda.name->data.opaque.data,
10245dfecf96Smrg					 info);
10255dfecf96Smrg	    }
10265dfecf96Smrg	    length += LispWriteChar(stream, ' ');
10275dfecf96Smrg	    length += LispDoWriteObject(stream,
10285dfecf96Smrg					object->data.lambda.code, info, 0);
10295dfecf96Smrg	    length += LispWriteChar(stream, '>');
10305dfecf96Smrg	    break;
10315dfecf96Smrg	case LispStream_t:
10325dfecf96Smrg	    length += LispWriteStr(stream, "#<", 2);
10335dfecf96Smrg	    if (object->data.stream.type == LispStreamFile)
10345dfecf96Smrg		string = "FILE-STREAM ";
10355dfecf96Smrg	    else if (object->data.stream.type == LispStreamString)
10365dfecf96Smrg		string = "STRING-STREAM ";
10375dfecf96Smrg	    else if (object->data.stream.type == LispStreamStandard)
10385dfecf96Smrg		string = "STANDARD-STREAM ";
10395dfecf96Smrg	    else if (object->data.stream.type == LispStreamPipe)
10405dfecf96Smrg		string = "PIPE-STREAM ";
10415dfecf96Smrg	    length += LispDoWriteAtom(stream, string, strlen(string),
10425dfecf96Smrg				      info->print_case);
10435dfecf96Smrg
10445dfecf96Smrg	    if (!object->data.stream.readable && !object->data.stream.writable)
10455dfecf96Smrg		length += LispDoWriteAtom(stream, "CLOSED",
10465dfecf96Smrg					  6, info->print_case);
10475dfecf96Smrg	    else {
10485dfecf96Smrg		if (object->data.stream.readable)
10495dfecf96Smrg		    length += LispDoWriteAtom(stream, "READ",
10505dfecf96Smrg					      4, info->print_case);
10515dfecf96Smrg		if (object->data.stream.writable) {
10525dfecf96Smrg		    if (object->data.stream.readable)
10535dfecf96Smrg			length += LispWriteChar(stream, '-');
10545dfecf96Smrg		    length += LispDoWriteAtom(stream, "WRITE",
10555dfecf96Smrg					      5, info->print_case);
10565dfecf96Smrg		}
10575dfecf96Smrg	    }
10585dfecf96Smrg	    if (object->data.stream.type != LispStreamString) {
10595dfecf96Smrg		length += LispWriteChar(stream, ' ');
10605dfecf96Smrg		length += LispDoWriteObject(stream,
10615dfecf96Smrg					    object->data.stream.pathname,
10625dfecf96Smrg					    info, 1);
10635dfecf96Smrg		/* same address/size for pipes */
10645dfecf96Smrg		length += LispWriteChar(stream, ' ');
10655dfecf96Smrg		length += LispWriteCPointer(stream,
10665dfecf96Smrg					    object->data.stream.source.file);
10675dfecf96Smrg		if (object->data.stream.readable &&
10685dfecf96Smrg		    object->data.stream.type == LispStreamFile &&
10695dfecf96Smrg		    !object->data.stream.source.file->binary) {
10705dfecf96Smrg		    length += LispWriteStr(stream, " @", 2);
10715dfecf96Smrg		    format_integer(stk, object->data.stream.source.file->line, 10);
10725dfecf96Smrg		    length += LispWriteStr(stream, stk, strlen(stk));
10735dfecf96Smrg		}
10745dfecf96Smrg	    }
10755dfecf96Smrg	    length += LispWriteChar(stream, '>');
10765dfecf96Smrg	    break;
10775dfecf96Smrg	case LispPathname_t:
10785dfecf96Smrg	    length += LispWriteStr(stream, "#P", 2);
10795dfecf96Smrg	    paren = 1;
10805dfecf96Smrg	    object = CAR(object->data.quote);
10815dfecf96Smrg	    goto write_again;
10825dfecf96Smrg	case LispPackage_t:
10835dfecf96Smrg	    length += LispDoWriteAtom(stream, "#<PACKAGE ",
10845dfecf96Smrg				      10, info->print_case);
10855dfecf96Smrg	    length += LispWriteStr(stream,
10865dfecf96Smrg				   THESTR(object->data.package.name),
10875dfecf96Smrg				   STRLEN(object->data.package.name));
10885dfecf96Smrg	    length += LispWriteChar(stream, '>');
10895dfecf96Smrg	    break;
10905dfecf96Smrg	case LispRegex_t:
10915dfecf96Smrg	    length += LispDoWriteAtom(stream, "#<REGEX ",
10925dfecf96Smrg				      8, info->print_case);
10935dfecf96Smrg	    length += LispDoWriteObject(stream,
10945dfecf96Smrg					object->data.regex.pattern, info, 1);
10955dfecf96Smrg	    if (object->data.regex.options & RE_NOSPEC)
10965dfecf96Smrg		length += LispDoWriteAtom(stream, " :NOSPEC",
10975dfecf96Smrg					  8, info->print_case);
10985dfecf96Smrg	    if (object->data.regex.options & RE_ICASE)
10995dfecf96Smrg		length += LispDoWriteAtom(stream, " :ICASE",
11005dfecf96Smrg					  7, info->print_case);
11015dfecf96Smrg	    if (object->data.regex.options & RE_NOSUB)
11025dfecf96Smrg		length += LispDoWriteAtom(stream, " :NOSUB",
11035dfecf96Smrg					  7, info->print_case);
11045dfecf96Smrg	    if (object->data.regex.options & RE_NEWLINE)
11055dfecf96Smrg		length += LispDoWriteAtom(stream, " :NEWLINE",
11065dfecf96Smrg					  9, info->print_case);
11075dfecf96Smrg	    length += LispWriteChar(stream, '>');
11085dfecf96Smrg	    break;
11095dfecf96Smrg	case LispBytecode_t:
11105dfecf96Smrg	    length += LispDoWriteAtom(stream, "#<BYTECODE ",
11115dfecf96Smrg				      11, info->print_case);
11125dfecf96Smrg	    length += LispWriteCPointer(stream,
11135dfecf96Smrg					object->data.bytecode.bytecode);
11145dfecf96Smrg	    length += LispWriteChar(stream, '>');
11155dfecf96Smrg	    break;
11165dfecf96Smrg	case LispHashTable_t:
11175dfecf96Smrg	    length += LispDoWriteAtom(stream, "#<HASH-TABLE ",
11185dfecf96Smrg				      13, info->print_case);
11195dfecf96Smrg	    length += LispWriteAtom(stream, object->data.hash.test, info);
11205dfecf96Smrg	    snprintf(stk, sizeof(stk), " %g %g",
11215dfecf96Smrg		     object->data.hash.table->rehash_size,
11225dfecf96Smrg		     object->data.hash.table->rehash_threshold);
11235dfecf96Smrg	    length += LispWriteStr(stream, stk, strlen(stk));
11245dfecf96Smrg	    snprintf(stk, sizeof(stk), " %ld/%ld>",
11255dfecf96Smrg		     object->data.hash.table->count,
11265dfecf96Smrg		     object->data.hash.table->num_entries);
11275dfecf96Smrg	    length += LispWriteStr(stream, stk, strlen(stk));
11285dfecf96Smrg	    break;
11295dfecf96Smrg    }
11305dfecf96Smrg
11315dfecf96Smrg    return (length);
11325dfecf96Smrg}
11335dfecf96Smrg
11345dfecf96Smrg/* return current column number in stream */
11355dfecf96Smrgint
11365dfecf96SmrgLispGetColumn(LispObj *stream)
11375dfecf96Smrg{
11385dfecf96Smrg    LispFile *file;
11395dfecf96Smrg    LispString *string;
11405dfecf96Smrg
11415dfecf96Smrg    check_stream(stream, &file, &string, 0);
11425dfecf96Smrg    if (file != NULL)
11435dfecf96Smrg	return (file->column);
11445dfecf96Smrg    return (string->column);
11455dfecf96Smrg}
11465dfecf96Smrg
11475dfecf96Smrg/* write a character to stream */
11485dfecf96Smrgint
11495dfecf96SmrgLispWriteChar(LispObj *stream, int character)
11505dfecf96Smrg{
11515dfecf96Smrg    LispFile *file;
11525dfecf96Smrg    LispString *string;
11535dfecf96Smrg
11545dfecf96Smrg    check_stream(stream, &file, &string, 1);
11555dfecf96Smrg    if (file != NULL)
11565dfecf96Smrg	return (LispFputc(file, character));
11575dfecf96Smrg
11585dfecf96Smrg    return (LispSputc(string, character));
11595dfecf96Smrg}
11605dfecf96Smrg
11615dfecf96Smrg/* write a character count times to stream */
11625dfecf96Smrgint
11635dfecf96SmrgLispWriteChars(LispObj *stream, int character, int count)
11645dfecf96Smrg{
11655dfecf96Smrg    int length = 0;
11665dfecf96Smrg
11675dfecf96Smrg    if (count > 0) {
11685dfecf96Smrg	char stk[64];
11695dfecf96Smrg	LispFile *file;
11705dfecf96Smrg	LispString *string;
11715dfecf96Smrg
11725dfecf96Smrg	check_stream(stream, &file, &string, 1);
11735dfecf96Smrg	if (count >= sizeof(stk)) {
11745dfecf96Smrg	    memset(stk, character, sizeof(stk));
11755dfecf96Smrg	    for (; count >= sizeof(stk); count -= sizeof(stk)) {
11765dfecf96Smrg		if (file != NULL)
11775dfecf96Smrg		    length += LispFwrite(file, stk, sizeof(stk));
11785dfecf96Smrg		else
11795dfecf96Smrg		    length += LispSwrite(string, stk, sizeof(stk));
11805dfecf96Smrg	    }
11815dfecf96Smrg	}
11825dfecf96Smrg	else
11835dfecf96Smrg	    memset(stk, character, count);
11845dfecf96Smrg
11855dfecf96Smrg	if (count) {
11865dfecf96Smrg	    if (file != NULL)
11875dfecf96Smrg		length += LispFwrite(file, stk, count);
11885dfecf96Smrg	    else
11895dfecf96Smrg		length += LispSwrite(string, stk, count);
11905dfecf96Smrg	}
11915dfecf96Smrg    }
11925dfecf96Smrg
11935dfecf96Smrg    return (length);
11945dfecf96Smrg}
11955dfecf96Smrg
11965dfecf96Smrg/* write a string to stream */
11975dfecf96Smrgint
11985dfecf96SmrgLispWriteStr(LispObj *stream, char *buffer, long length)
11995dfecf96Smrg{
12005dfecf96Smrg    LispFile *file;
12015dfecf96Smrg    LispString *string;
12025dfecf96Smrg
12035dfecf96Smrg    check_stream(stream, &file, &string, 1);
12045dfecf96Smrg    if (file != NULL)
12055dfecf96Smrg	return (LispFwrite(file, buffer, length));
12065dfecf96Smrg    return (LispSwrite(string, buffer, length));
12075dfecf96Smrg}
12085dfecf96Smrg
12095dfecf96Smrgstatic int
12105dfecf96SmrgLispDoWriteAtom(LispObj *stream, char *string, int length, int print_case)
12115dfecf96Smrg{
12125dfecf96Smrg    int bytes = 0, cap = 0;
12135dfecf96Smrg    char buffer[128], *ptr;
12145dfecf96Smrg
12155dfecf96Smrg    switch (print_case) {
12165dfecf96Smrg	case DOWNCASE:
12175dfecf96Smrg	    for (ptr = buffer; length > 0; length--, string++) {
12185dfecf96Smrg		if (isupper(*string))
12195dfecf96Smrg		    *ptr = tolower(*string);
12205dfecf96Smrg		else
12215dfecf96Smrg		    *ptr = *string;
12225dfecf96Smrg		++ptr;
12235dfecf96Smrg		if (ptr - buffer >= sizeof(buffer)) {
12245dfecf96Smrg		    bytes += LispWriteStr(stream, buffer, ptr - buffer);
12255dfecf96Smrg		    ptr = buffer;
12265dfecf96Smrg		}
12275dfecf96Smrg	    }
12285dfecf96Smrg	    if (ptr > buffer)
12295dfecf96Smrg		bytes += LispWriteStr(stream, buffer, ptr - buffer);
12305dfecf96Smrg	    break;
12315dfecf96Smrg	case CAPITALIZE:
12325dfecf96Smrg	    for (ptr = buffer; length > 0; length--, string++) {
12335dfecf96Smrg		if (isalnum(*string)) {
12345dfecf96Smrg		    if (cap && isupper(*string))
12355dfecf96Smrg			*ptr = tolower(*string);
12365dfecf96Smrg		    else
12375dfecf96Smrg			*ptr = *string;
12385dfecf96Smrg		    cap = 1;
12395dfecf96Smrg		}
12405dfecf96Smrg		else {
12415dfecf96Smrg		    *ptr = *string;
12425dfecf96Smrg		    cap = 0;
12435dfecf96Smrg		}
12445dfecf96Smrg		++ptr;
12455dfecf96Smrg		if (ptr - buffer >= sizeof(buffer)) {
12465dfecf96Smrg		    bytes += LispWriteStr(stream, buffer, ptr - buffer);
12475dfecf96Smrg		    ptr = buffer;
12485dfecf96Smrg		}
12495dfecf96Smrg	    }
12505dfecf96Smrg	    if (ptr > buffer)
12515dfecf96Smrg		bytes += LispWriteStr(stream, buffer, ptr - buffer);
12525dfecf96Smrg	    break;
12535dfecf96Smrg	default:
12545dfecf96Smrg	    /* Strings are already stored upcase/quoted */
12555dfecf96Smrg	    bytes += LispWriteStr(stream, string, length);
12565dfecf96Smrg	    break;
12575dfecf96Smrg    }
12585dfecf96Smrg
12595dfecf96Smrg    return (bytes);
12605dfecf96Smrg}
12615dfecf96Smrg
12625dfecf96Smrgstatic int
12635dfecf96SmrgLispWriteAtom(LispObj *stream, LispObj *object, write_info *info)
12645dfecf96Smrg{
12655dfecf96Smrg    int length = 0;
12665dfecf96Smrg    LispAtom *atom = object->data.atom;
12675dfecf96Smrg    Atom_id id = atom->string;
12685dfecf96Smrg
12695dfecf96Smrg    if (atom->package != PACKAGE) {
12705dfecf96Smrg	if (atom->package == lisp__data.keyword)
12715dfecf96Smrg	    length += LispWriteChar(stream, ':');
12725dfecf96Smrg	else if (atom->package == NULL)
12735dfecf96Smrg	    length += LispWriteStr(stream, "#:", 2);
12745dfecf96Smrg	else {
12755dfecf96Smrg	    /* Check if the symbol is visible */
12765dfecf96Smrg	    int i, visible = 0;
12775dfecf96Smrg
12785dfecf96Smrg	    if (atom->ext) {
12795dfecf96Smrg		for (i = lisp__data.pack->use.length - 1; i >= 0; i--) {
12805dfecf96Smrg		    if (lisp__data.pack->use.pairs[i] == atom->package) {
12815dfecf96Smrg			visible = 1;
12825dfecf96Smrg			break;
12835dfecf96Smrg		    }
12845dfecf96Smrg		}
12855dfecf96Smrg	    }
12865dfecf96Smrg
12875dfecf96Smrg	    if (!visible) {
12885dfecf96Smrg		/* XXX this assumes that package names are always "readable" */
12895dfecf96Smrg		length +=
12905dfecf96Smrg		    LispDoWriteAtom(stream,
12915dfecf96Smrg				    THESTR(atom->package->data.package.name),
12925dfecf96Smrg				    STRLEN(atom->package->data.package.name),
12935dfecf96Smrg				    info->print_case);
12945dfecf96Smrg		length += LispWriteChar(stream, ':');
12955dfecf96Smrg		if (!atom->ext)
12965dfecf96Smrg		    length += LispWriteChar(stream, ':');
12975dfecf96Smrg	    }
12985dfecf96Smrg	}
12995dfecf96Smrg    }
13005dfecf96Smrg    if (atom->unreadable)
13015dfecf96Smrg	length += LispWriteChar(stream, '|');
13025dfecf96Smrg    length += LispDoWriteAtom(stream, id, strlen(id),
13035dfecf96Smrg			      atom->unreadable ? UPCASE : info->print_case);
13045dfecf96Smrg    if (atom->unreadable)
13055dfecf96Smrg	length += LispWriteChar(stream, '|');
13065dfecf96Smrg
13075dfecf96Smrg    return (length);
13085dfecf96Smrg}
13095dfecf96Smrg
13105dfecf96Smrgstatic int
13115dfecf96SmrgLispWriteInteger(LispObj *stream, LispObj *object)
13125dfecf96Smrg{
13135dfecf96Smrg    return (LispFormatInteger(stream, object, 10, 0, 0, 0, 0, 0, 0));
13145dfecf96Smrg}
13155dfecf96Smrg
13165dfecf96Smrgstatic int
13175dfecf96SmrgLispWriteCharacter(LispObj *stream, LispObj *object, write_info *info)
13185dfecf96Smrg{
13195dfecf96Smrg    return (LispFormatCharacter(stream, object, !info->print_escape, 0));
13205dfecf96Smrg}
13215dfecf96Smrg
13225dfecf96Smrgstatic int
13235dfecf96SmrgLispWriteString(LispObj *stream, LispObj *object, write_info *info)
13245dfecf96Smrg{
13255dfecf96Smrg    return (LispWriteCString(stream, THESTR(object), STRLEN(object), info));
13265dfecf96Smrg}
13275dfecf96Smrg
13285dfecf96Smrgstatic int
13295dfecf96SmrgLispWriteFloat(LispObj *stream, LispObj *object)
13305dfecf96Smrg{
13315dfecf96Smrg    double value = DFLOAT_VALUE(object);
13325dfecf96Smrg
13335dfecf96Smrg    if (value == 0.0 || (fabs(value) < 1.0E7 && fabs(value) > 1.0E-4))
13345dfecf96Smrg	return (LispFormatFixedFloat(stream, object, 0, 0, NULL, 0, 0, 0));
13355dfecf96Smrg
13365dfecf96Smrg    return (LispDoFormatExponentialFloat(stream, object, 0, 0, NULL,
13375dfecf96Smrg					 0, 1, 0, ' ', 'E', 0));
13385dfecf96Smrg}
13395dfecf96Smrg
13405dfecf96Smrgstatic int
13415dfecf96SmrgLispWriteArray(LispObj *stream, LispObj *object, write_info *info)
13425dfecf96Smrg{
13435dfecf96Smrg    int length = 0;
13445dfecf96Smrg    long print_level = info->level, circle;
13455dfecf96Smrg
13465dfecf96Smrg    if (info->circles && (circle = LispCheckCircle(object, info)) >= 0 &&
13475dfecf96Smrg	LispPrintCircle(stream, object, circle, &length, info) == 0)
13485dfecf96Smrg	return (length);
13495dfecf96Smrg
13505dfecf96Smrg    if (object->data.array.rank == 0) {
13515dfecf96Smrg	length += LispWriteStr(stream, "#0A", 3);
13525dfecf96Smrg	length += LispDoWriteObject(stream, object->data.array.list, info, 1);
13535dfecf96Smrg	return (length);
13545dfecf96Smrg    }
13555dfecf96Smrg
13565dfecf96Smrg    INCDEPTH();
13575dfecf96Smrg    ++info->level;
13585dfecf96Smrg    if (info->print_level < 0 || info->level <= info->print_level) {
13595dfecf96Smrg	if (object->data.array.rank == 1)
13605dfecf96Smrg	    length += LispWriteStr(stream, "#(", 2);
13615dfecf96Smrg	else {
13625dfecf96Smrg	    char stk[32];
13635dfecf96Smrg
13645dfecf96Smrg	    format_integer(stk, object->data.array.rank, 10);
13655dfecf96Smrg	    length += LispWriteChar(stream, '#');
13665dfecf96Smrg	    length += LispWriteStr(stream, stk, strlen(stk));
13675dfecf96Smrg	    length += LispWriteStr(stream, "A(", 2);
13685dfecf96Smrg	}
13695dfecf96Smrg
13705dfecf96Smrg	if (!object->data.array.zero) {
13715dfecf96Smrg	    long print_length = info->length, local_length = 0;
13725dfecf96Smrg
13735dfecf96Smrg	    if (object->data.array.rank == 1) {
13745dfecf96Smrg		LispObj *ary;
13755dfecf96Smrg		long count;
13765dfecf96Smrg
13775dfecf96Smrg		for (ary = object->data.array.dim, count = 1;
13785dfecf96Smrg		     ary != NIL; ary = CDR(ary))
13795dfecf96Smrg		    count *= FIXNUM_VALUE(CAR(ary));
13805dfecf96Smrg		for (ary = object->data.array.list; count > 0;
13815dfecf96Smrg		     ary = CDR(ary), count--) {
13825dfecf96Smrg		    if (info->print_length < 0 ||
13835dfecf96Smrg			++local_length <= info->print_length) {
13845dfecf96Smrg			info->length = 0;
13855dfecf96Smrg			length += LispDoWriteObject(stream, CAR(ary), info, 1);
13865dfecf96Smrg		    }
13875dfecf96Smrg		    else {
13885dfecf96Smrg			length += LispWriteStr(stream, "...", 3);
13895dfecf96Smrg			break;
13905dfecf96Smrg		    }
13915dfecf96Smrg		    if (count - 1 > 0)
13925dfecf96Smrg			length += LispWriteChar(stream, ' ');
13935dfecf96Smrg		}
13945dfecf96Smrg	    }
13955dfecf96Smrg	    else {
13965dfecf96Smrg		LispObj *ary;
13975dfecf96Smrg		int i, k, rank, *dims, *loop;
13985dfecf96Smrg
13995dfecf96Smrg		rank = object->data.array.rank;
14005dfecf96Smrg		dims = LispMalloc(sizeof(int) * rank);
14015dfecf96Smrg		loop = LispCalloc(1, sizeof(int) * (rank - 1));
14025dfecf96Smrg
14035dfecf96Smrg		/* fill dim */
14045dfecf96Smrg		for (i = 0, ary = object->data.array.dim; ary != NIL;
14055dfecf96Smrg		     i++, ary = CDR(ary))
14065dfecf96Smrg		    dims[i] = FIXNUM_VALUE(CAR(ary));
14075dfecf96Smrg
14085dfecf96Smrg		i = 0;
14095dfecf96Smrg		ary = object->data.array.list;
14105dfecf96Smrg		while (loop[0] < dims[0]) {
14115dfecf96Smrg		    if (info->print_length < 0 ||
14125dfecf96Smrg			local_length < info->print_length) {
14135dfecf96Smrg			for (; i < rank - 1; i++)
14145dfecf96Smrg			    length += LispWriteChar(stream, '(');
14155dfecf96Smrg			--i;
14165dfecf96Smrg			for (;;) {
14175dfecf96Smrg			    ++loop[i];
14185dfecf96Smrg			    if (i && loop[i] >= dims[i])
14195dfecf96Smrg				loop[i] = 0;
14205dfecf96Smrg			    else
14215dfecf96Smrg				break;
14225dfecf96Smrg			    --i;
14235dfecf96Smrg			}
14245dfecf96Smrg			for (k = 0; k < dims[rank - 1] - 1;
14255dfecf96Smrg			     k++, ary = CDR(ary)) {
14265dfecf96Smrg			    if (info->print_length < 0 ||
14275dfecf96Smrg				k < info->print_length) {
14285dfecf96Smrg				++local_length;
14295dfecf96Smrg				info->length = 0;
14305dfecf96Smrg				length += LispDoWriteObject(stream,
14315dfecf96Smrg							    CAR(ary), info, 1);
14325dfecf96Smrg				length += LispWriteChar(stream, ' ');
14335dfecf96Smrg			    }
14345dfecf96Smrg			}
14355dfecf96Smrg			if (info->print_length < 0 || k < info->print_length) {
14365dfecf96Smrg			    ++local_length;
14375dfecf96Smrg			    info->length = 0;
14385dfecf96Smrg			    length += LispDoWriteObject(stream,
14395dfecf96Smrg							CAR(ary), info, 0);
14405dfecf96Smrg			}
14415dfecf96Smrg			else
14425dfecf96Smrg			    length += LispWriteStr(stream,  "...", 3);
14435dfecf96Smrg			for (k = rank - 1; k > i; k--)
14445dfecf96Smrg			    length += LispWriteChar(stream, ')');
14455dfecf96Smrg			if (loop[0] < dims[0])
14465dfecf96Smrg			    length += LispWriteChar(stream,  ' ');
14475dfecf96Smrg			ary = CDR(ary);
14485dfecf96Smrg		    }
14495dfecf96Smrg		    else {
14505dfecf96Smrg			++local_length;
14515dfecf96Smrg			length += LispWriteStr(stream,	"...)", 4);
14525dfecf96Smrg			for (; local_length < dims[0] - 1; local_length++)
14535dfecf96Smrg			    length += LispWriteStr(stream,  " ...)", 5);
14545dfecf96Smrg			if (local_length <= dims[0])
14555dfecf96Smrg			    length += LispWriteStr(stream,  " ...", 4);
14565dfecf96Smrg			break;
14575dfecf96Smrg		    }
14585dfecf96Smrg		}
14595dfecf96Smrg		LispFree(dims);
14605dfecf96Smrg		LispFree(loop);
14615dfecf96Smrg	    }
14625dfecf96Smrg	    info->length = print_length;
14635dfecf96Smrg	}
14645dfecf96Smrg	length += LispWriteChar(stream, ')');
14655dfecf96Smrg    }
14665dfecf96Smrg    else
14675dfecf96Smrg	length += LispWriteChar(stream, '#');
14685dfecf96Smrg    info->level = print_level;
14695dfecf96Smrg    DECDEPTH();
14705dfecf96Smrg
14715dfecf96Smrg    return (length);
14725dfecf96Smrg}
14735dfecf96Smrg
14745dfecf96Smrgstatic int
14755dfecf96SmrgLispWriteStruct(LispObj *stream, LispObj *object, write_info *info)
14765dfecf96Smrg{
14775dfecf96Smrg    int length;
14785dfecf96Smrg    long circle;
14795dfecf96Smrg    LispObj *symbol;
14805dfecf96Smrg    LispObj *def = object->data.struc.def;
14815dfecf96Smrg    LispObj *field = object->data.struc.fields;
14825dfecf96Smrg
14835dfecf96Smrg    if (info->circles && (circle = LispCheckCircle(object, info)) >= 0 &&
14845dfecf96Smrg	LispPrintCircle(stream, object, circle, &length, info) == 0)
14855dfecf96Smrg	return (length);
14865dfecf96Smrg
14875dfecf96Smrg    INCDEPTH();
14885dfecf96Smrg    length = LispWriteStr(stream, "#S(", 3);
14895dfecf96Smrg    symbol = SYMBOLP(CAR(def)) ? CAR(def) : CAAR(def);
14905dfecf96Smrg    length += LispWriteAtom(stream, symbol, info);
14915dfecf96Smrg    def = CDR(def);
14925dfecf96Smrg    for (; def != NIL; def = CDR(def), field = CDR(field)) {
14935dfecf96Smrg	length += LispWriteChar(stream, ' ');
14945dfecf96Smrg	symbol = SYMBOLP(CAR(def)) ? CAR(def) : CAAR(def);
14955dfecf96Smrg	length += LispWriteAtom(stream, symbol, info);
14965dfecf96Smrg	length += LispWriteChar(stream, ' ');
14975dfecf96Smrg	length += LispDoWriteObject(stream, CAR(field), info, 1);
14985dfecf96Smrg    }
14995dfecf96Smrg    length += LispWriteChar(stream, ')');
15005dfecf96Smrg    DECDEPTH();
15015dfecf96Smrg
15025dfecf96Smrg    return (length);
15035dfecf96Smrg}
15045dfecf96Smrg
15055dfecf96Smrgint
15065dfecf96SmrgLispFormatInteger(LispObj *stream, LispObj *object, int radix,
15075dfecf96Smrg		  int atsign, int collon, int mincol,
15085dfecf96Smrg		  int padchar, int commachar, int commainterval)
15095dfecf96Smrg{
15105dfecf96Smrg    char stk[128], *str = stk;
15115dfecf96Smrg    int i, length, sign, intervals;
15125dfecf96Smrg
15135dfecf96Smrg    if (LONGINTP(object))
15145dfecf96Smrg	format_integer(stk, LONGINT_VALUE(object), radix);
15155dfecf96Smrg    else {
15165dfecf96Smrg	if (mpi_getsize(object->data.mp.integer, radix) >= sizeof(stk))
15175dfecf96Smrg	    str = mpi_getstr(NULL, object->data.mp.integer, radix);
15185dfecf96Smrg	else
15195dfecf96Smrg	    mpi_getstr(str, object->data.mp.integer, radix);
15205dfecf96Smrg    }
15215dfecf96Smrg
15225dfecf96Smrg    sign = *str == '-';
15235dfecf96Smrg    length = strlen(str);
15245dfecf96Smrg
15255dfecf96Smrg    /* if collon, update length for the number of commachars to be printed */
15265dfecf96Smrg    if (collon && commainterval > 0 && commachar) {
15275dfecf96Smrg	intervals = length / commainterval;
15285dfecf96Smrg	length += intervals;
15295dfecf96Smrg    }
15305dfecf96Smrg    else
15315dfecf96Smrg	intervals = 0;
15325dfecf96Smrg
15335dfecf96Smrg    /* if sign must be printed, and number is positive */
15345dfecf96Smrg    if (atsign && !sign)
15355dfecf96Smrg	++length;
15365dfecf96Smrg
15375dfecf96Smrg    /* if need padding */
15385dfecf96Smrg    if (padchar && mincol > length)
15395dfecf96Smrg	LispWriteChars(stream, padchar, mincol - length);
15405dfecf96Smrg
15415dfecf96Smrg    /* if need to print number sign */
15425dfecf96Smrg    if (sign || atsign)
15435dfecf96Smrg	LispWriteChar(stream, sign ? '-' : '+');
15445dfecf96Smrg
15455dfecf96Smrg    /* if need to print commas to separate groups of numbers */
15465dfecf96Smrg    if (intervals) {
15475dfecf96Smrg	int j;
15485dfecf96Smrg	char *ptr;
15495dfecf96Smrg
15505dfecf96Smrg	i = (length - atsign) - intervals;
15515dfecf96Smrg	j = i % commainterval;
15525dfecf96Smrg	/* make the loop below easier */
15535dfecf96Smrg	if (j == 0)
15545dfecf96Smrg	    j = commainterval;
15555dfecf96Smrg	i -= j;
15565dfecf96Smrg	ptr = str + sign;
15575dfecf96Smrg	for (; j > 0; j--, ptr++)
15585dfecf96Smrg	    LispWriteChar(stream, *ptr);
15595dfecf96Smrg	for (; i > 0; i -= commainterval) {
15605dfecf96Smrg	    LispWriteChar(stream, commachar);
15615dfecf96Smrg	    for (j = 0; j < commainterval; j++, ptr++)
15625dfecf96Smrg		LispWriteChar(stream, *ptr);
15635dfecf96Smrg	}
15645dfecf96Smrg    }
15655dfecf96Smrg    /* else, just print the string */
15665dfecf96Smrg    else
15675dfecf96Smrg	LispWriteStr(stream, str + sign, length - sign);
15685dfecf96Smrg
15695dfecf96Smrg    /* if number required more than sizeof(stk) bytes */
15705dfecf96Smrg    if (str != stk)
15715dfecf96Smrg	LispFree(str);
15725dfecf96Smrg
15735dfecf96Smrg    return (length);
15745dfecf96Smrg}
15755dfecf96Smrg
15765dfecf96Smrgint
15775dfecf96SmrgLispFormatRomanInteger(LispObj *stream, long value, int new_roman)
15785dfecf96Smrg{
15795dfecf96Smrg    char stk[32];
15805dfecf96Smrg    int length;
15815dfecf96Smrg
15825dfecf96Smrg    length = 0;
15835dfecf96Smrg    while (value > 1000) {
15845dfecf96Smrg	stk[length++] = 'M';
15855dfecf96Smrg	value -= 1000;
15865dfecf96Smrg    }
15875dfecf96Smrg    if (new_roman) {
15885dfecf96Smrg	if (value >= 900) {
15895dfecf96Smrg	    strcpy(stk + length, "CM");
15905dfecf96Smrg	    length += 2,
15915dfecf96Smrg	    value -= 900;
15925dfecf96Smrg	}
15935dfecf96Smrg	else if (value < 500 && value >= 400) {
15945dfecf96Smrg	    strcpy(stk + length, "CD");
15955dfecf96Smrg	    length += 2;
15965dfecf96Smrg	    value -= 400;
15975dfecf96Smrg	}
15985dfecf96Smrg    }
15995dfecf96Smrg    if (value >= 500) {
16005dfecf96Smrg	stk[length++] = 'D';
16015dfecf96Smrg	value -= 500;
16025dfecf96Smrg    }
16035dfecf96Smrg    while (value >= 100) {
16045dfecf96Smrg	stk[length++] = 'C';
16055dfecf96Smrg	value -= 100;
16065dfecf96Smrg    }
16075dfecf96Smrg    if (new_roman) {
16085dfecf96Smrg	if (value >= 90) {
16095dfecf96Smrg	    strcpy(stk + length, "XC");
16105dfecf96Smrg	    length += 2,
16115dfecf96Smrg	    value -= 90;
16125dfecf96Smrg	}
16135dfecf96Smrg	else if (value < 50 && value >= 40) {
16145dfecf96Smrg	    strcpy(stk + length, "XL");
16155dfecf96Smrg	    length += 2;
16165dfecf96Smrg	    value -= 40;
16175dfecf96Smrg	}
16185dfecf96Smrg    }
16195dfecf96Smrg    if (value >= 50) {
16205dfecf96Smrg	stk[length++] = 'L';
16215dfecf96Smrg	value -= 50;
16225dfecf96Smrg    }
16235dfecf96Smrg    while (value >= 10) {
16245dfecf96Smrg	stk[length++] = 'X';
16255dfecf96Smrg	value -= 10;
16265dfecf96Smrg    }
16275dfecf96Smrg    if (new_roman) {
16285dfecf96Smrg	if (value == 9) {
16295dfecf96Smrg	    strcpy(stk + length, "IX");
16305dfecf96Smrg	    length += 2,
16315dfecf96Smrg	    value -= 9;
16325dfecf96Smrg	}
16335dfecf96Smrg	else if (value == 4) {
16345dfecf96Smrg	    strcpy(stk + length, "IV");
16355dfecf96Smrg	    length += 2;
16365dfecf96Smrg	    value -= 4;
16375dfecf96Smrg	}
16385dfecf96Smrg    }
16395dfecf96Smrg    if (value >= 5) {
16405dfecf96Smrg	stk[length++] = 'V';
16415dfecf96Smrg	value -= 5;
16425dfecf96Smrg    }
16435dfecf96Smrg    while (value) {
16445dfecf96Smrg	stk[length++] = 'I';
16455dfecf96Smrg	--value;
16465dfecf96Smrg    }
16475dfecf96Smrg
16485dfecf96Smrg    stk[length] = '\0';
16495dfecf96Smrg
16505dfecf96Smrg    return (LispWriteStr(stream, stk, length));
16515dfecf96Smrg}
16525dfecf96Smrg
16535dfecf96Smrgint
16545dfecf96SmrgLispFormatEnglishInteger(LispObj *stream, long number, int ordinal)
16555dfecf96Smrg{
16565dfecf96Smrg    static char *ds[] = {
16575dfecf96Smrg	"",	      "one",	   "two",	 "three",      "four",
16585dfecf96Smrg	"five",       "six",	   "seven",	 "eight",      "nine",
16595dfecf96Smrg	"ten",	      "eleven",    "twelve",	 "thirteen",   "fourteen",
16605dfecf96Smrg	"fifteen",    "sixteen",   "seventeen",  "eighteen",   "nineteen"
16615dfecf96Smrg    };
16625dfecf96Smrg    static char *dsth[] = {
16635dfecf96Smrg	"",	      "first",	   "second",	  "third",	"fourth",
16645dfecf96Smrg	"fifth",      "sixth",	   "seventh",	  "eighth",	"ninth",
16655dfecf96Smrg	"tenth",      "eleventh",  "twelfth",	  "thirteenth", "fourteenth",
16665dfecf96Smrg	 "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth"
16675dfecf96Smrg    };
16685dfecf96Smrg    static char *hs[] = {
16695dfecf96Smrg	"",	      "",	   "twenty",	  "thirty",	"forty",
16705dfecf96Smrg	"fifty",      "sixty",	   "seventy",	  "eighty",	"ninety"
16715dfecf96Smrg    };
16725dfecf96Smrg    static char *hsth[] = {
16735dfecf96Smrg	"",	      "",	   "twentieth",   "thirtieth",	"fortieth",
16745dfecf96Smrg       "fiftieth",    "sixtieth",  "seventieth",  "eightieth",	"ninetieth"
16755dfecf96Smrg    };
16765dfecf96Smrg    static char *ts[] = {
16775dfecf96Smrg	"",	      "thousand",   "million"
16785dfecf96Smrg    };
16795dfecf96Smrg    static char *tsth[] = {
16805dfecf96Smrg	"",	     "thousandth", "millionth"
16815dfecf96Smrg    };
16825dfecf96Smrg    char stk[256];
16835dfecf96Smrg    int length, sign;
16845dfecf96Smrg
16855dfecf96Smrg    sign = number < 0;
16865dfecf96Smrg    if (sign)
16875dfecf96Smrg	number = -number;
16885dfecf96Smrg    length = 0;
16895dfecf96Smrg
16905dfecf96Smrg#define SIGNLEN		6	/* strlen("minus ") */
16915dfecf96Smrg    if (sign) {
16925dfecf96Smrg	strcpy(stk, "minus ");
16935dfecf96Smrg	length += SIGNLEN;
16945dfecf96Smrg    }
16955dfecf96Smrg    else if (number == 0) {
16965dfecf96Smrg	if (ordinal) {
16975dfecf96Smrg	    strcpy(stk, "zeroth");
16985dfecf96Smrg	    length += 6;	/* strlen("zeroth") */
16995dfecf96Smrg	}
17005dfecf96Smrg	else {
17015dfecf96Smrg	    strcpy(stk, "zero");
17025dfecf96Smrg	    length += 4;	/* strlen("zero") */
17035dfecf96Smrg	}
17045dfecf96Smrg    }
17055dfecf96Smrg    for (;;) {
17065dfecf96Smrg	int count, temp;
17075dfecf96Smrg	char *t, *h, *d;
17085dfecf96Smrg	long value = number;
17095dfecf96Smrg
17105dfecf96Smrg	for (count = 0; value >= 1000; value /= 1000, count++)
17115dfecf96Smrg	    ;
17125dfecf96Smrg
17135dfecf96Smrg	t = ds[value / 100];
17145dfecf96Smrg	if (ordinal && !count && (value % 10) == 0)
17155dfecf96Smrg	    h = hsth[(value % 100) / 10];
17165dfecf96Smrg	else
17175dfecf96Smrg	    h = hs[(value % 100) / 10];
17185dfecf96Smrg
17195dfecf96Smrg	if (ordinal && !count)
17205dfecf96Smrg	    d = *h ? dsth[value % 10] : dsth[value % 20];
17215dfecf96Smrg	else
17225dfecf96Smrg	    d = *h ? ds[value % 10] : ds[value % 20];
17235dfecf96Smrg
17245dfecf96Smrg	if (((!sign && length) || length > SIGNLEN) && (*t || *h || *d)) {
17255dfecf96Smrg	    if (!ordinal || count || *h || *t) {
17265dfecf96Smrg		strcpy(stk + length, ", ");
17275dfecf96Smrg		length += 2;
17285dfecf96Smrg	    }
17295dfecf96Smrg	    else {
17305dfecf96Smrg		strcpy(stk + length, " ");
17315dfecf96Smrg		++length;
17325dfecf96Smrg	    }
17335dfecf96Smrg	}
17345dfecf96Smrg
17355dfecf96Smrg	if (*t) {
17365dfecf96Smrg	    if (ordinal && !count && (value % 100) == 0)
17375dfecf96Smrg		temp = sprintf(stk + length, "%s hundredth", t);
17385dfecf96Smrg	    else
17395dfecf96Smrg		temp = sprintf(stk + length, "%s hundred", t);
17405dfecf96Smrg	    length += temp;
17415dfecf96Smrg	}
17425dfecf96Smrg
17435dfecf96Smrg	if (*h) {
17445dfecf96Smrg	    if (*t) {
17455dfecf96Smrg		if (ordinal && !count) {
17465dfecf96Smrg		    strcpy(stk + length, " ");
17475dfecf96Smrg		    ++length;
17485dfecf96Smrg		}
17495dfecf96Smrg		else {
17505dfecf96Smrg		    strcpy(stk + length, " and ");
17515dfecf96Smrg		    length += 5;	/* strlen(" and ") */
17525dfecf96Smrg		}
17535dfecf96Smrg	    }
17545dfecf96Smrg	    strcpy(stk + length, h);
17555dfecf96Smrg	    length += strlen(h);
17565dfecf96Smrg	}
17575dfecf96Smrg
17585dfecf96Smrg	if (*d) {
17595dfecf96Smrg	    if (*h) {
17605dfecf96Smrg		strcpy(stk + length, "-");
17615dfecf96Smrg		++length;
17625dfecf96Smrg	    }
17635dfecf96Smrg	    else if (*t) {
17645dfecf96Smrg		if (ordinal && !count) {
17655dfecf96Smrg		    strcpy(stk + length, " ");
17665dfecf96Smrg		    ++length;
17675dfecf96Smrg		}
17685dfecf96Smrg		else {
17695dfecf96Smrg		    strcpy(stk + length, " and ");
17705dfecf96Smrg		    length += 5;	/* strlen(" and ") */
17715dfecf96Smrg		}
17725dfecf96Smrg	    }
17735dfecf96Smrg	    strcpy(stk + length, d);
17745dfecf96Smrg	    length += strlen(d);
17755dfecf96Smrg	}
17765dfecf96Smrg
17775dfecf96Smrg	if (!count)
17785dfecf96Smrg	    break;
17795dfecf96Smrg	else
17805dfecf96Smrg	    temp = count;
17815dfecf96Smrg
17825dfecf96Smrg	if (count > 1) {
17835dfecf96Smrg	    value *= 1000;
17845dfecf96Smrg	    while (--count)
17855dfecf96Smrg		value *= 1000;
17865dfecf96Smrg	    number -= value;
17875dfecf96Smrg	}
17885dfecf96Smrg	else
17895dfecf96Smrg	    number %= 1000;
17905dfecf96Smrg
17915dfecf96Smrg	if (ordinal && number == 0 && !*t && !*h)
17925dfecf96Smrg	    temp = sprintf(stk + length, " %s", tsth[temp]);
17935dfecf96Smrg	else
17945dfecf96Smrg	    temp = sprintf(stk + length, " %s", ts[temp]);
17955dfecf96Smrg	length += temp;
17965dfecf96Smrg
17975dfecf96Smrg	if (!number)
17985dfecf96Smrg	    break;
17995dfecf96Smrg    }
18005dfecf96Smrg
18015dfecf96Smrg    return (LispWriteStr(stream, stk, length));
18025dfecf96Smrg}
18035dfecf96Smrg
18045dfecf96Smrgint
18055dfecf96SmrgLispFormatCharacter(LispObj *stream, LispObj *object,
18065dfecf96Smrg		    int atsign, int collon)
18075dfecf96Smrg{
18085dfecf96Smrg    int length = 0;
18095dfecf96Smrg    int ch = SCHAR_VALUE(object);
18105dfecf96Smrg
18115dfecf96Smrg    if (atsign && !collon)
18125dfecf96Smrg	length += LispWriteStr(stream, "#\\", 2);
18135dfecf96Smrg    if ((atsign || collon) && (ch <= ' ' || ch == 0177)) {
18145dfecf96Smrg	char *name = LispChars[ch].names[0];
18155dfecf96Smrg
18165dfecf96Smrg	length += LispWriteStr(stream, name, strlen(name));
18175dfecf96Smrg    }
18185dfecf96Smrg    else
18195dfecf96Smrg	length += LispWriteChar(stream, ch);
18205dfecf96Smrg
18215dfecf96Smrg    return (length);
18225dfecf96Smrg}
18235dfecf96Smrg
18245dfecf96Smrg/* returns 1 if string size must grow, done inplace */
18255dfecf96Smrgstatic int
18265dfecf96Smrgfloat_string_inc(char *buffer, int offset)
18275dfecf96Smrg{
18285dfecf96Smrg    int i;
18295dfecf96Smrg
18305dfecf96Smrg    for (i = offset; i >= 0; i--) {
18315dfecf96Smrg	if (buffer[i] == '9')
18325dfecf96Smrg	    buffer[i] = '0';
18335dfecf96Smrg	else if (buffer[i] != '.') {
18345dfecf96Smrg	    ++buffer[i];
18355dfecf96Smrg	    break;
18365dfecf96Smrg	}
18375dfecf96Smrg    }
18385dfecf96Smrg    if (i < 0) {
18395dfecf96Smrg	int length = strlen(buffer);
18405dfecf96Smrg
18415dfecf96Smrg	/* string size must change */
18425dfecf96Smrg	memmove(buffer + 1, buffer, length + 1);
18435dfecf96Smrg	buffer[0] = '1';
18445dfecf96Smrg
18455dfecf96Smrg	return (1);
18465dfecf96Smrg    }
18475dfecf96Smrg
18485dfecf96Smrg    return (0);
18495dfecf96Smrg}
18505dfecf96Smrg
18515dfecf96Smrgint
18525dfecf96SmrgLispFormatFixedFloat(LispObj *stream, LispObj *object,
18535dfecf96Smrg		     int atsign, int w, int *pd, int k, int overflowchar,
18545dfecf96Smrg		     int padchar)
18555dfecf96Smrg{
18565dfecf96Smrg    char buffer[512], stk[64];
18575dfecf96Smrg    int sign, exponent, length, offset, d = pd ? *pd : FLOAT_PREC, again;
18585dfecf96Smrg    double value = DFLOAT_VALUE(object);
18595dfecf96Smrg
18605dfecf96Smrg    if (value == 0.0) {
18615dfecf96Smrg	exponent = k = 0;
18625dfecf96Smrg	strcpy(stk, "+0");
18635dfecf96Smrg    }
18645dfecf96Smrg    else
18655dfecf96Smrg	/* calculate format parameters, adjusting scale factor */
18665dfecf96Smrg	parse_double(stk, &exponent, value, d + 1 + k);
18675dfecf96Smrg
18685dfecf96Smrg    /* make sure k won't cause overflow */
18695dfecf96Smrg    if (k > 128)
18705dfecf96Smrg	k = 128;
18715dfecf96Smrg    else if (k < -128)
18725dfecf96Smrg	k = -128;
18735dfecf96Smrg
18745dfecf96Smrg    /* make sure d won't cause overflow */
18755dfecf96Smrg    if (d > 128)
18765dfecf96Smrg	d = 128;
18775dfecf96Smrg    else if (d < -128)
18785dfecf96Smrg	d = -128;
18795dfecf96Smrg
18805dfecf96Smrg    /* adjust scale factor, exponent is used as an index in stk */
18815dfecf96Smrg    exponent += k + 1;
18825dfecf96Smrg
18835dfecf96Smrg    /* how many bytes in float representation */
18845dfecf96Smrg    length = strlen(stk) - 1;
18855dfecf96Smrg
18865dfecf96Smrg    /* need to print a sign? */
18875dfecf96Smrg    sign = atsign || (stk[0] == '-');
18885dfecf96Smrg
18895dfecf96Smrg    /* format number, cannot overflow, as control variables were checked */
18905dfecf96Smrg    offset = 0;
18915dfecf96Smrg    if (sign)
18925dfecf96Smrg	buffer[offset++] = stk[0];
18935dfecf96Smrg    if (exponent > 0) {
18945dfecf96Smrg	if (exponent > length) {
18955dfecf96Smrg	    memcpy(buffer + offset, stk + 1, length);
18965dfecf96Smrg	    memset(buffer + offset + length, '0', exponent - length);
18975dfecf96Smrg	}
18985dfecf96Smrg	else
18995dfecf96Smrg	    memcpy(buffer + offset, stk + 1, exponent);
19005dfecf96Smrg	offset += exponent;
19015dfecf96Smrg	buffer[offset++] = '.';
19025dfecf96Smrg	if (length > exponent) {
19035dfecf96Smrg	    memcpy(buffer + offset, stk + 1 + exponent, length - exponent);
19045dfecf96Smrg	    offset += length - exponent;
19055dfecf96Smrg	}
19065dfecf96Smrg	else
19075dfecf96Smrg	    buffer[offset++] = '0';
19085dfecf96Smrg    }
19095dfecf96Smrg    else {
19105dfecf96Smrg	buffer[offset++] = '0';
19115dfecf96Smrg	buffer[offset++] = '.';
19125dfecf96Smrg	while (exponent < 0) {
19135dfecf96Smrg	    buffer[offset++] = '0';
19145dfecf96Smrg	    exponent++;
19155dfecf96Smrg	}
19165dfecf96Smrg	memcpy(buffer + offset, stk + 1, length);
19175dfecf96Smrg	offset += length;
19185dfecf96Smrg    }
19195dfecf96Smrg    buffer[offset] = '\0';
19205dfecf96Smrg
19215dfecf96Smrg    again = 0;
19225dfecf96Smrgfixed_float_check_again:
19235dfecf96Smrg    /* make sure only d digits are printed after decimal point */
19245dfecf96Smrg    if (d > 0) {
19255dfecf96Smrg	char *dptr = strchr(buffer, '.');
19265dfecf96Smrg
19275dfecf96Smrg	length = strlen(dptr) - 1;
19285dfecf96Smrg	/* check if need to remove excess digits */
19295dfecf96Smrg	if (length > d) {
19305dfecf96Smrg	    int digit;
19315dfecf96Smrg
19325dfecf96Smrg	    offset = (dptr - buffer) + 1 + d;
19335dfecf96Smrg	    digit = buffer[offset];
19345dfecf96Smrg
19355dfecf96Smrg	    /* remove extra digits */
19365dfecf96Smrg	    buffer[offset] = '\0';
19375dfecf96Smrg
19385dfecf96Smrg	    /* check if need to round */
19395dfecf96Smrg	    if (!again && offset > 1 && isdigit(digit) && digit >= '5' &&
19405dfecf96Smrg		isdigit(buffer[offset - 1]) &&
19415dfecf96Smrg		float_string_inc(buffer, offset - 1))
19425dfecf96Smrg		++offset;
19435dfecf96Smrg	}
19445dfecf96Smrg	/* check if need to add extra zero digits to fill space */
19455dfecf96Smrg	else if (length < d) {
19465dfecf96Smrg	    offset += d - length;
19475dfecf96Smrg	    for (++length; length <= d; length++)
19485dfecf96Smrg		dptr[length] = '0';
19495dfecf96Smrg	    dptr[length] = '\0';
19505dfecf96Smrg	}
19515dfecf96Smrg    }
19525dfecf96Smrg    else {
19535dfecf96Smrg	/* no digits after decimal point */
19545dfecf96Smrg	int digit, inc = 0;
19555dfecf96Smrg	char *dptr = strchr(buffer, '.') + 1;
19565dfecf96Smrg
19575dfecf96Smrg	digit = *dptr;
19585dfecf96Smrg	if (!again && digit >= '5' && dptr >= buffer + 2 && isdigit(dptr[-2]))
19595dfecf96Smrg	    inc = float_string_inc(buffer, dptr - buffer - 2);
19605dfecf96Smrg
19615dfecf96Smrg	offset = (dptr - buffer) + inc;
19625dfecf96Smrg	buffer[offset] = '\0';
19635dfecf96Smrg    }
19645dfecf96Smrg
19655dfecf96Smrg    /* if d was not specified, remove any extra zeros */
19665dfecf96Smrg    if (pd == NULL) {
19675dfecf96Smrg	while (offset > 2 && buffer[offset - 2] != '.' &&
19685dfecf96Smrg	       buffer[offset - 1] == '0')
19695dfecf96Smrg	    --offset;
19705dfecf96Smrg	buffer[offset] = '\0';
19715dfecf96Smrg    }
19725dfecf96Smrg
19735dfecf96Smrg    if (w > 0 && offset > w) {
19745dfecf96Smrg	/* first check if can remove extra fractional digits */
19755dfecf96Smrg	if (pd == NULL) {
19765dfecf96Smrg	    char *ptr = strchr(buffer, '.') + 1;
19775dfecf96Smrg
19785dfecf96Smrg	    if (ptr - buffer < w) {
19795dfecf96Smrg		d = w - (ptr - buffer);
19805dfecf96Smrg		goto fixed_float_check_again;
19815dfecf96Smrg	    }
19825dfecf96Smrg	}
19835dfecf96Smrg
19845dfecf96Smrg	/* remove leading "zero" to save space */
19855dfecf96Smrg 	if ((!sign && buffer[0] == '0') || (sign && buffer[1] == '0')) {
19865dfecf96Smrg	    /* ending nul also copied */
19875dfecf96Smrg	    memmove(buffer + sign, buffer + sign + 1, offset);
19885dfecf96Smrg	    --offset;
19895dfecf96Smrg	}
19905dfecf96Smrg	/* remove leading '+' to "save" space */
19915dfecf96Smrg	if (offset > w && buffer[0] == '+') {
19925dfecf96Smrg	    /* ending nul also copied */
19935dfecf96Smrg	    memmove(buffer, buffer + 1, offset);
19945dfecf96Smrg	    --offset;
19955dfecf96Smrg	}
19965dfecf96Smrg    }
19975dfecf96Smrg
19985dfecf96Smrg    /* if cannot represent number in given width */
19995dfecf96Smrg    if (overflowchar && offset > w) {
20005dfecf96Smrg	again = 1;
20015dfecf96Smrg	goto fixed_float_overflow;
20025dfecf96Smrg    }
20035dfecf96Smrg
20045dfecf96Smrg    length = 0;
20055dfecf96Smrg    /* print padding if required */
20065dfecf96Smrg    if (w > offset)
20075dfecf96Smrg	length += LispWriteChars(stream, padchar, w - offset);
20085dfecf96Smrg
20095dfecf96Smrg    /* print float number representation */
20105dfecf96Smrg    return (LispWriteStr(stream, buffer, offset) + length);
20115dfecf96Smrg
20125dfecf96Smrgfixed_float_overflow:
20135dfecf96Smrg    return (LispWriteChars(stream, overflowchar, w));
20145dfecf96Smrg}
20155dfecf96Smrg
20165dfecf96Smrgint
20175dfecf96SmrgLispFormatExponentialFloat(LispObj *stream, LispObj *object,
20185dfecf96Smrg			   int atsign, int w, int *pd, int e, int k,
20195dfecf96Smrg			   int overflowchar, int padchar, int exponentchar)
20205dfecf96Smrg{
20215dfecf96Smrg    return (LispDoFormatExponentialFloat(stream, object, atsign, w,
20225dfecf96Smrg					 pd, e, k, overflowchar, padchar,
20235dfecf96Smrg					 exponentchar, 1));
20245dfecf96Smrg}
20255dfecf96Smrg
20265dfecf96Smrgint
20275dfecf96SmrgLispDoFormatExponentialFloat(LispObj *stream, LispObj *object,
20285dfecf96Smrg			     int atsign, int w, int *pd, int e, int k,
20295dfecf96Smrg			     int overflowchar, int padchar, int exponentchar,
20305dfecf96Smrg			     int format)
20315dfecf96Smrg{
20325dfecf96Smrg    char buffer[512], stk[64];
20335dfecf96Smrg    int sign, exponent, length, offset, d = pd ? *pd : FLOAT_PREC;
20345dfecf96Smrg    double value = DFLOAT_VALUE(object);
20355dfecf96Smrg
20365dfecf96Smrg    if (value == 0.0) {
20375dfecf96Smrg	exponent = 0;
20385dfecf96Smrg	k = 1;
20395dfecf96Smrg	strcpy(stk, "+0");
20405dfecf96Smrg    }
20415dfecf96Smrg    else
20425dfecf96Smrg	/* calculate format parameters, adjusting scale factor */
20435dfecf96Smrg	parse_double(stk, &exponent, value, d + k - 1);
20445dfecf96Smrg
20455dfecf96Smrg    /* set e to a value that won't overflow */
20465dfecf96Smrg    if (e > 16)
20475dfecf96Smrg	e = 16;
20485dfecf96Smrg
20495dfecf96Smrg    /* set k to a value that won't overflow */
20505dfecf96Smrg    if (k > 128)
20515dfecf96Smrg	k = 128;
20525dfecf96Smrg    else if (k < -128)
20535dfecf96Smrg	k = -128;
20545dfecf96Smrg
20555dfecf96Smrg    /* set d to a value that won't overflow */
20565dfecf96Smrg    if (d > 128)
20575dfecf96Smrg	d = 128;
20585dfecf96Smrg    else if (d < -128)
20595dfecf96Smrg	d = -128;
20605dfecf96Smrg
20615dfecf96Smrg    /* how many bytes in float representation */
20625dfecf96Smrg    length = strlen(stk) - 1;
20635dfecf96Smrg
20645dfecf96Smrg    /* need to print a sign? */
20655dfecf96Smrg    sign = atsign || (stk[0] == '-');
20665dfecf96Smrg
20675dfecf96Smrg    /* adjust number of digits after decimal point */
20685dfecf96Smrg    if (k > 0)
20695dfecf96Smrg	d -= k - 1;
20705dfecf96Smrg
20715dfecf96Smrg    /* adjust exponent, based on scale factor */
20725dfecf96Smrg    exponent -= k - 1;
20735dfecf96Smrg
20745dfecf96Smrg    /* format number, cannot overflow, as control variables were checked */
20755dfecf96Smrg    offset = 0;
20765dfecf96Smrg    if (sign)
20775dfecf96Smrg	buffer[offset++] = stk[0];
20785dfecf96Smrg    if (k > 0) {
20795dfecf96Smrg	if (k > length) {
20805dfecf96Smrg	    memcpy(buffer + offset, stk + 1, length);
20815dfecf96Smrg	    offset += length;
20825dfecf96Smrg	}
20835dfecf96Smrg	else {
20845dfecf96Smrg	    memcpy(buffer + offset, stk + 1, k);
20855dfecf96Smrg	    offset += k;
20865dfecf96Smrg	}
20875dfecf96Smrg	buffer[offset++] = '.';
20885dfecf96Smrg	if (length > k) {
20895dfecf96Smrg	    memcpy(buffer + offset, stk + 1 + k, length - k);
20905dfecf96Smrg	    offset += length - k;
20915dfecf96Smrg	}
20925dfecf96Smrg 	else
20935dfecf96Smrg	    buffer[offset++] = '0';
20945dfecf96Smrg    }
20955dfecf96Smrg    else {
20965dfecf96Smrg	int tmp = k;
20975dfecf96Smrg
20985dfecf96Smrg	buffer[offset++] = '0';
20995dfecf96Smrg	buffer[offset++] = '.';
21005dfecf96Smrg	while (tmp < 0) {
21015dfecf96Smrg	    buffer[offset++] = '0';
21025dfecf96Smrg	    tmp++;
21035dfecf96Smrg	}
21045dfecf96Smrg	memcpy(buffer + offset, stk + 1, length);
21055dfecf96Smrg	offset += length;
21065dfecf96Smrg    }
21075dfecf96Smrg
21085dfecf96Smrg    /* if format, then always add a sign to exponent */
21095dfecf96Smrg    buffer[offset++] = exponentchar;
21105dfecf96Smrg    if (format || exponent < 0)
21115dfecf96Smrg	buffer[offset++] = exponent < 0 ? '-' : '+';
21125dfecf96Smrg
21135dfecf96Smrg    /* XXX destroy stk contents */
21145dfecf96Smrg    sprintf(stk, "%%0%dd", e);
21155dfecf96Smrg    /* format scale factor*/
21165dfecf96Smrg    length = sprintf(buffer + offset, stk,
21175dfecf96Smrg		     exponent < 0 ? -exponent : exponent);
21185dfecf96Smrg    /* check for overflow in exponent */
21195dfecf96Smrg    if (length > e && overflowchar)
21205dfecf96Smrg	goto exponential_float_overflow;
21215dfecf96Smrg    offset += length;
21225dfecf96Smrg
21235dfecf96Smrg    /* make sure only d digits are printed after decimal point */
21245dfecf96Smrg    if (d > 0) {
21255dfecf96Smrg	int currd;
21265dfecf96Smrg	char *dptr = strchr(buffer, '.'),
21275dfecf96Smrg	     *eptr = strchr(dptr, exponentchar);
21285dfecf96Smrg
21295dfecf96Smrg	currd = eptr - dptr - 1;
21305dfecf96Smrg	length = strlen(eptr);
21315dfecf96Smrg
21325dfecf96Smrg	/* check if need to remove excess digits */
21335dfecf96Smrg	if (currd > d) {
21345dfecf96Smrg	    int digit, dpos;
21355dfecf96Smrg
21365dfecf96Smrg	    dpos = offset = (dptr - buffer) + 1 + d;
21375dfecf96Smrg	    digit = buffer[offset];
21385dfecf96Smrg
21395dfecf96Smrg	    memmove(buffer + offset, eptr, length + 1);
21405dfecf96Smrg	    /* also copy ending nul character */
21415dfecf96Smrg
21425dfecf96Smrg	    /* adjust offset to length of total string */
21435dfecf96Smrg	    offset += length;
21445dfecf96Smrg
21455dfecf96Smrg	    /* check if need to round */
21465dfecf96Smrg	    if (dpos > 1 && isdigit(digit) && digit >= '5' &&
21475dfecf96Smrg		isdigit(buffer[dpos - 1]) &&
21485dfecf96Smrg		float_string_inc(buffer, dpos - 1))
21495dfecf96Smrg		++offset;
21505dfecf96Smrg	}
21515dfecf96Smrg	/* check if need to add extra zero digits to fill space */
21525dfecf96Smrg	else if (pd && currd < d) {
21535dfecf96Smrg	    memmove(eptr + d - currd, eptr, length + 1);
21545dfecf96Smrg	    /* also copy ending nul character */
21555dfecf96Smrg
21565dfecf96Smrg	    offset += d - currd;
21575dfecf96Smrg	    for (++currd; currd <= d; currd++)
21585dfecf96Smrg		dptr[currd] = '0';
21595dfecf96Smrg	}
21605dfecf96Smrg	/* check if need to remove zeros */
21615dfecf96Smrg	else if (pd == NULL) {
21625dfecf96Smrg	    int zeros = 1;
21635dfecf96Smrg
21645dfecf96Smrg	    while (eptr[-zeros] == '0')
21655dfecf96Smrg		++zeros;
21665dfecf96Smrg	    if (eptr[-zeros] == '.')
21675dfecf96Smrg		--zeros;
21685dfecf96Smrg	    if (zeros > 1) {
21695dfecf96Smrg		memmove(eptr - zeros + 1, eptr, length + 1);
21705dfecf96Smrg		offset -= zeros - 1;
21715dfecf96Smrg	    }
21725dfecf96Smrg	}
21735dfecf96Smrg    }
21745dfecf96Smrg    else {
21755dfecf96Smrg	/* no digits after decimal point */
21765dfecf96Smrg	int digit, inc = 0;
21775dfecf96Smrg	char *dptr = strchr(buffer, '.'),
21785dfecf96Smrg	     *eptr = strchr(dptr, exponentchar);
21795dfecf96Smrg
21805dfecf96Smrg	digit = dptr[1];
21815dfecf96Smrg
21825dfecf96Smrg	offset = (dptr - buffer) + 1;
21835dfecf96Smrg	length = strlen(eptr);
21845dfecf96Smrg	memmove(buffer + offset, eptr, length + 1);
21855dfecf96Smrg	/* also copy ending nul character */
21865dfecf96Smrg
21875dfecf96Smrg 	if (digit >= '5' && dptr >= buffer + 2 &&
21885dfecf96Smrg	    isdigit(dptr[-2]))
21895dfecf96Smrg	    inc = float_string_inc(buffer, dptr - buffer - 2);
21905dfecf96Smrg
21915dfecf96Smrg	/* adjust offset to length of total string */
21925dfecf96Smrg	offset += length + inc;
21935dfecf96Smrg    }
21945dfecf96Smrg
21955dfecf96Smrg    if (w > 0 && offset > w) {
21965dfecf96Smrg	/* remove leading "zero" to save space */
21975dfecf96Smrg	if ((!sign && buffer[0] == '0') || (sign && buffer[1] == '0')) {
21985dfecf96Smrg	    /* ending nul also copied */
21995dfecf96Smrg	    memmove(buffer + sign, buffer + sign + 1, offset);
22005dfecf96Smrg	    --offset;
22015dfecf96Smrg	}
22025dfecf96Smrg	/* remove leading '+' to "save" space */
22035dfecf96Smrg	if (offset > w && buffer[0] == '+') {
22045dfecf96Smrg	    /* ending nul also copied */
22055dfecf96Smrg	    memmove(buffer, buffer + 1, offset);
22065dfecf96Smrg	    --offset;
22075dfecf96Smrg	}
22085dfecf96Smrg    }
22095dfecf96Smrg
22105dfecf96Smrg    /* if cannot represent number in given width */
22115dfecf96Smrg    if (overflowchar && offset > w)
22125dfecf96Smrg	goto exponential_float_overflow;
22135dfecf96Smrg
22145dfecf96Smrg    length = 0;
22155dfecf96Smrg    /* print padding if required */
22165dfecf96Smrg    if (w > offset)
22175dfecf96Smrg	length += LispWriteChars(stream, padchar, w - offset);
22185dfecf96Smrg
22195dfecf96Smrg    /* print float number representation */
22205dfecf96Smrg    return (LispWriteStr(stream, buffer, offset) + length);
22215dfecf96Smrg
22225dfecf96Smrgexponential_float_overflow:
22235dfecf96Smrg    return (LispWriteChars(stream, overflowchar, w));
22245dfecf96Smrg}
22255dfecf96Smrg
22265dfecf96Smrgint
22275dfecf96SmrgLispFormatGeneralFloat(LispObj *stream, LispObj *object,
22285dfecf96Smrg		       int atsign, int w, int *pd, int e, int k,
22295dfecf96Smrg		       int overflowchar, int padchar, int exponentchar)
22305dfecf96Smrg{
22315dfecf96Smrg    char stk[64];
22325dfecf96Smrg    int length, exponent, n, dd, ee, ww, d = pd ? *pd : FLOAT_PREC;
22335dfecf96Smrg    double value = DFLOAT_VALUE(object);
22345dfecf96Smrg
22355dfecf96Smrg    if (value == 0.0) {
22365dfecf96Smrg	exponent = 0;
22375dfecf96Smrg	n = 0;
22385dfecf96Smrg	d = 1;
22395dfecf96Smrg	strcpy(stk, "+0");
22405dfecf96Smrg    }
22415dfecf96Smrg    else {
22425dfecf96Smrg	/* calculate format parameters, adjusting scale factor */
22435dfecf96Smrg	parse_double(stk, &exponent, value, d + k - 1);
22445dfecf96Smrg	n = exponent + 1;
22455dfecf96Smrg    }
22465dfecf96Smrg
22475dfecf96Smrg    /* Let ee equal e+2, or 4 if e is omitted. */
22485dfecf96Smrg    if (e)
22495dfecf96Smrg	ee = e + 2;
22505dfecf96Smrg    else
22515dfecf96Smrg	ee = 4;
22525dfecf96Smrg
22535dfecf96Smrg    /* Let ww equal w-ee, or nil if w is omitted. */
22545dfecf96Smrg    if (w)
22555dfecf96Smrg	ww = w - ee;
22565dfecf96Smrg    else
22575dfecf96Smrg	ww = 0;
22585dfecf96Smrg
22595dfecf96Smrg    dd = d - n;
22605dfecf96Smrg    if (d >= dd && dd >= 0) {
22615dfecf96Smrg	length = LispFormatFixedFloat(stream, object, atsign, ww,
22625dfecf96Smrg				      &dd, 0, overflowchar, padchar);
22635dfecf96Smrg
22645dfecf96Smrg	/* ~ee@T */
22655dfecf96Smrg	length += LispWriteChars(stream, padchar, ee);
22665dfecf96Smrg    }
22675dfecf96Smrg    else
22685dfecf96Smrg	length = LispFormatExponentialFloat(stream, object, atsign,
22695dfecf96Smrg					    w, pd, e, k, overflowchar,
22705dfecf96Smrg					    padchar, exponentchar);
22715dfecf96Smrg
22725dfecf96Smrg    return (length);
22735dfecf96Smrg}
22745dfecf96Smrg
22755dfecf96Smrgint
22765dfecf96SmrgLispFormatDollarFloat(LispObj *stream, LispObj *object,
22775dfecf96Smrg		      int atsign, int collon, int d, int n, int w, int padchar)
22785dfecf96Smrg{
22795dfecf96Smrg    char buffer[512], stk[64];
22805dfecf96Smrg    int sign, exponent, length, offset;
22815dfecf96Smrg    double value = DFLOAT_VALUE(object);
22825dfecf96Smrg
22835dfecf96Smrg    if (value == 0.0) {
22845dfecf96Smrg	exponent = 0;
22855dfecf96Smrg	strcpy(stk, "+0");
22865dfecf96Smrg    }
22875dfecf96Smrg    else
22885dfecf96Smrg	/* calculate format parameters, adjusting scale factor */
22895dfecf96Smrg	parse_double(stk, &exponent, value, d == 0 ? FLOAT_PREC : d + 1);
22905dfecf96Smrg
22915dfecf96Smrg    /* set d to a "sane" value */
22925dfecf96Smrg    if (d > 128)
22935dfecf96Smrg	d = 128;
22945dfecf96Smrg
22955dfecf96Smrg    /* set n to a "sane" value */
22965dfecf96Smrg    if (n > 128)
22975dfecf96Smrg	n = 128;
22985dfecf96Smrg
22995dfecf96Smrg    /* use exponent as index in stk */
23005dfecf96Smrg    ++exponent;
23015dfecf96Smrg
23025dfecf96Smrg    /* don't put sign in buffer,
23035dfecf96Smrg     * if collon specified, must go before padding */
23045dfecf96Smrg    sign = atsign || (stk[0] == '-');
23055dfecf96Smrg
23065dfecf96Smrg    offset = 0;
23075dfecf96Smrg
23085dfecf96Smrg    /* pad with zeros if required */
23095dfecf96Smrg    if (exponent > 0)
23105dfecf96Smrg	n -= exponent;
23115dfecf96Smrg    while (n > 0) {
23125dfecf96Smrg	buffer[offset++] = '0';
23135dfecf96Smrg	n--;
23145dfecf96Smrg    }
23155dfecf96Smrg
23165dfecf96Smrg    /* how many bytes in float representation */
23175dfecf96Smrg    length = strlen(stk) - 1;
23185dfecf96Smrg
23195dfecf96Smrg    if (exponent > 0) {
23205dfecf96Smrg	if (exponent > length) {
23215dfecf96Smrg	    memcpy(buffer + offset, stk + 1, length);
23225dfecf96Smrg	    memset(buffer + offset + length, '0', exponent - length);
23235dfecf96Smrg	}
23245dfecf96Smrg	else
23255dfecf96Smrg	    memcpy(buffer + offset, stk + 1, exponent);
23265dfecf96Smrg	offset += exponent;
23275dfecf96Smrg	buffer[offset++] = '.';
23285dfecf96Smrg	if (length > exponent) {
23295dfecf96Smrg	    memcpy(buffer + offset, stk + 1 + exponent, length - exponent);
23305dfecf96Smrg	    offset += length - exponent;
23315dfecf96Smrg	}
23325dfecf96Smrg	else
23335dfecf96Smrg	    buffer[offset++] = '0';
23345dfecf96Smrg    }
23355dfecf96Smrg    else {
23365dfecf96Smrg	if (n > 0)
23375dfecf96Smrg	    buffer[offset++] = '0';
23385dfecf96Smrg	buffer[offset++] = '.';
23395dfecf96Smrg	while (exponent < 0) {
23405dfecf96Smrg	    buffer[offset++] = '0';
23415dfecf96Smrg	    exponent++;
23425dfecf96Smrg	}
23435dfecf96Smrg	memcpy(buffer + offset, stk + 1, length);
23445dfecf96Smrg	offset += length;
23455dfecf96Smrg    }
23465dfecf96Smrg    buffer[offset] = '\0';
23475dfecf96Smrg
23485dfecf96Smrg    /* make sure only d digits are printed after decimal point */
23495dfecf96Smrg    if (d > 0) {
23505dfecf96Smrg	char *dptr = strchr(buffer, '.');
23515dfecf96Smrg
23525dfecf96Smrg	length = strlen(dptr) - 1;
23535dfecf96Smrg	/* check if need to remove excess digits */
23545dfecf96Smrg	if (length > d) {
23555dfecf96Smrg	    int digit;
23565dfecf96Smrg
23575dfecf96Smrg	    offset = (dptr - buffer) + 1 + d;
23585dfecf96Smrg	    digit = buffer[offset];
23595dfecf96Smrg
23605dfecf96Smrg	    /* remove extra digits */
23615dfecf96Smrg	    buffer[offset] = '\0';
23625dfecf96Smrg
23635dfecf96Smrg	    /* check if need to round */
23645dfecf96Smrg	    if (offset > 1 && isdigit(digit) && digit >= '5' &&
23655dfecf96Smrg		isdigit(buffer[offset - 1]) &&
23665dfecf96Smrg		float_string_inc(buffer, offset - 1))
23675dfecf96Smrg		++offset;
23685dfecf96Smrg	}
23695dfecf96Smrg	/* check if need to add extra zero digits to fill space */
23705dfecf96Smrg	else if (length < d) {
23715dfecf96Smrg	    offset += d - length;
23725dfecf96Smrg	    for (++length; length <= d; length++)
23735dfecf96Smrg		dptr[length] = '0';
23745dfecf96Smrg	    dptr[length] = '\0';
23755dfecf96Smrg	}
23765dfecf96Smrg    }
23775dfecf96Smrg    else {
23785dfecf96Smrg	/* no digits after decimal point */
23795dfecf96Smrg	int digit, inc = 0;
23805dfecf96Smrg	char *dptr = strchr(buffer, '.') + 1;
23815dfecf96Smrg
23825dfecf96Smrg	digit = *dptr;
23835dfecf96Smrg	if (digit >= '5' && dptr >= buffer + 2 && isdigit(dptr[-2]))
23845dfecf96Smrg	    inc = float_string_inc(buffer, dptr - buffer - 2);
23855dfecf96Smrg
23865dfecf96Smrg	offset = (dptr - buffer) + inc;
23875dfecf96Smrg	buffer[offset] = '\0';
23885dfecf96Smrg    }
23895dfecf96Smrg
23905dfecf96Smrg    length = 0;
23915dfecf96Smrg    if (sign) {
23925dfecf96Smrg	++offset;
23935dfecf96Smrg	if (atsign && collon)
23945dfecf96Smrg	    length += LispWriteChar(stream, value >= 0.0 ? '+' : '-');
23955dfecf96Smrg    }
23965dfecf96Smrg
23975dfecf96Smrg    /* print padding if required */
23985dfecf96Smrg    if (w > offset)
23995dfecf96Smrg	length += LispWriteChars(stream, padchar, w - offset);
24005dfecf96Smrg
24015dfecf96Smrg    if (atsign && !collon)
24025dfecf96Smrg	length += LispWriteChar(stream, value >= 0.0 ? '+' : '-');
24035dfecf96Smrg
24045dfecf96Smrg    /* print float number representation */
24055dfecf96Smrg    return (LispWriteStr(stream, buffer, offset) + length);
24065dfecf96Smrg}
2407