read.c revision f14f4646
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/read.c,v 1.36tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include <errno.h>
335dfecf96Smrg#include "lisp/read.h"
345dfecf96Smrg#include "lisp/package.h"
355dfecf96Smrg#include "lisp/write.h"
365dfecf96Smrg#include <fcntl.h>
375dfecf96Smrg#include <stdarg.h>
385dfecf96Smrg
395dfecf96Smrg/* This should be visible only in read.c, but if an error is generated,
405dfecf96Smrg * the current code in write.c will print it as #<ERROR> */
415dfecf96Smrg#define LABEL_BIT_COUNT		8
425dfecf96Smrg#define LABEL_BIT_MASK		0xff
435dfecf96Smrg#define MAX_LABEL_VALUE		((1L << (sizeof(long) * 8 - 9)) - 1)
445dfecf96Smrg#define READLABEL(label)						\
455dfecf96Smrg    (LispObj*)(((label) << LABEL_BIT_COUNT) | READLABEL_MASK)
465dfecf96Smrg#define READLABELP(object)						\
475dfecf96Smrg    (((unsigned long)(object) & LABEL_BIT_MASK) == READLABEL_MASK)
485dfecf96Smrg#define READLABEL_VALUE(object)						\
495dfecf96Smrg    ((long)(object) >> LABEL_BIT_COUNT)
505dfecf96Smrg
515dfecf96Smrg#define READ_ENTER()							\
525dfecf96Smrg    LispObj *read__stream = SINPUT;					\
535dfecf96Smrg    int read__line = LispGetLine(read__stream)
545dfecf96Smrg#define READ_ERROR0(format)						\
555dfecf96Smrg    LispReadError(read__stream, read__line, format)
565dfecf96Smrg#define READ_ERROR1(format, arg1)					\
575dfecf96Smrg    LispReadError(read__stream, read__line, format, arg1)
585dfecf96Smrg#define READ_ERROR2(format, arg1, arg2)					\
595dfecf96Smrg    LispReadError(read__stream, read__line, format, arg1, arg2)
605dfecf96Smrg
615dfecf96Smrg#define READ_ERROR_EOF()	READ_ERROR0("unexpected end of input")
625dfecf96Smrg#define READ_ERROR_FIXNUM()	READ_ERROR0("number is not a fixnum")
635dfecf96Smrg#define READ_ERROR_INVARG()	READ_ERROR0("invalid argument")
645dfecf96Smrg
655dfecf96Smrg#ifdef __UNIXOS2__
665dfecf96Smrg# define finite(x) isfinite(x)
675dfecf96Smrg#endif
685dfecf96Smrg
695dfecf96Smrg/*
705dfecf96Smrg * Types
715dfecf96Smrg */
725dfecf96Smrgtypedef struct _object_info {
735dfecf96Smrg    long label;		/* the read label of this object */
745dfecf96Smrg    LispObj *object;	/* the resulting object */
755dfecf96Smrg    long num_circles;	/* references to object before it was completely read */
765dfecf96Smrg} object_info;
775dfecf96Smrg
785dfecf96Smrgtypedef struct _read_info {
795dfecf96Smrg    int level;		/* level of open parentheses */
805dfecf96Smrg
815dfecf96Smrg    int nodot;		/* flag set when reading a "special" list */
825dfecf96Smrg
835dfecf96Smrg    int discard;	/* flag used when reading an unavailable feature */
845dfecf96Smrg
855dfecf96Smrg    long circle_count;	/* if non zero, must resolve some labels */
865dfecf96Smrg
875dfecf96Smrg    /* information for #<number>= and #<number># */
885dfecf96Smrg    object_info *objects;
895dfecf96Smrg    long num_objects;
905dfecf96Smrg
915dfecf96Smrg    /* could use only the objects field as all circular data is known,
925dfecf96Smrg     * but check every object so that circular/shared references generated
935dfecf96Smrg     * by evaluations would not cause an infinite loop at read time */
945dfecf96Smrg    LispObj **circles;
955dfecf96Smrg    long num_circles;
965dfecf96Smrg} read_info;
975dfecf96Smrg
985dfecf96Smrg/*
995dfecf96Smrg * Protypes
1005dfecf96Smrg */
1015dfecf96Smrgstatic LispObj *LispReadChar(LispBuiltin*, int);
1025dfecf96Smrg
1035dfecf96Smrgstatic int LispGetLine(LispObj*);
1045dfecf96Smrg#ifdef __GNUC__
1055dfecf96Smrg#define PRINTF_FORMAT	__attribute__ ((format (printf, 3, 4)))
1065dfecf96Smrg#else
1075dfecf96Smrg#define PRINTF_FORMAT	/**/
1085dfecf96Smrg#endif
1095dfecf96Smrgstatic void LispReadError(LispObj*, int, char*, ...);
1105dfecf96Smrg#undef PRINTF_FORMAT
1115dfecf96Smrgstatic void LispReadFixCircle(LispObj*, read_info*);
1125dfecf96Smrgstatic LispObj *LispReadLabelCircle(LispObj*, read_info*);
1135dfecf96Smrgstatic int LispReadCheckCircle(LispObj*, read_info*);
1145dfecf96Smrgstatic LispObj *LispDoRead(read_info*);
1155dfecf96Smrgstatic int LispSkipWhiteSpace(void);
1165dfecf96Smrgstatic LispObj *LispReadList(read_info*);
1175dfecf96Smrgstatic LispObj *LispReadQuote(read_info*);
1185dfecf96Smrgstatic LispObj *LispReadBackquote(read_info*);
1195dfecf96Smrgstatic LispObj *LispReadCommaquote(read_info*);
1205dfecf96Smrgstatic LispObj *LispReadObject(int, read_info*);
1215dfecf96Smrgstatic LispObj *LispParseAtom(char*, char*, int, int, LispObj*, int);
1225dfecf96Smrgstatic LispObj *LispParseNumber(char*, int, LispObj*, int);
1235dfecf96Smrgstatic int StringInRadix(char*, int, int);
1245dfecf96Smrgstatic int AtomSeparator(int, int, int);
1255dfecf96Smrgstatic LispObj *LispReadVector(read_info*);
1265dfecf96Smrgstatic LispObj *LispReadMacro(read_info*);
1275dfecf96Smrgstatic LispObj *LispReadFunction(read_info*);
1285dfecf96Smrgstatic LispObj *LispReadRational(int, read_info*);
1295dfecf96Smrgstatic LispObj *LispReadCharacter(read_info*);
1305dfecf96Smrgstatic void LispSkipComment(void);
1315dfecf96Smrgstatic LispObj *LispReadEval(read_info*);
1325dfecf96Smrgstatic LispObj *LispReadComplex(read_info*);
1335dfecf96Smrgstatic LispObj *LispReadPathname(read_info*);
1345dfecf96Smrgstatic LispObj *LispReadStruct(read_info*);
1355dfecf96Smrgstatic LispObj *LispReadMacroArg(read_info*);
1365dfecf96Smrgstatic LispObj *LispReadArray(long, read_info*);
1375dfecf96Smrgstatic LispObj *LispReadFeature(int, read_info*);
1385dfecf96Smrgstatic LispObj *LispEvalFeature(LispObj*);
1395dfecf96Smrg
1405dfecf96Smrg/*
1415dfecf96Smrg * Initialization
1425dfecf96Smrg */
1435dfecf96Smrgstatic char *Char_Nul[] = {"Null", "Nul", NULL};
1445dfecf96Smrgstatic char *Char_Soh[] = {"Soh", NULL};
1455dfecf96Smrgstatic char *Char_Stx[] = {"Stx", NULL};
1465dfecf96Smrgstatic char *Char_Etx[] = {"Etx", NULL};
1475dfecf96Smrgstatic char *Char_Eot[] = {"Eot", NULL};
1485dfecf96Smrgstatic char *Char_Enq[] = {"Enq", NULL};
1495dfecf96Smrgstatic char *Char_Ack[] = {"Ack", NULL};
1505dfecf96Smrgstatic char *Char_Bel[] = {"Bell", "Bel", NULL};
1515dfecf96Smrgstatic char *Char_Bs[]  = {"Backspace", "Bs", NULL};
1525dfecf96Smrgstatic char *Char_Tab[] = {"Tab", NULL};
1535dfecf96Smrgstatic char *Char_Nl[]  = {"Newline", "Nl", "Lf", "Linefeed", NULL};
1545dfecf96Smrgstatic char *Char_Vt[]  = {"Vt", NULL};
1555dfecf96Smrgstatic char *Char_Np[]  = {"Page", "Np", NULL};
1565dfecf96Smrgstatic char *Char_Cr[]  = {"Return", "Cr", NULL};
1575dfecf96Smrgstatic char *Char_Ff[]  = {"So", "Ff", NULL};
1585dfecf96Smrgstatic char *Char_Si[]  = {"Si", NULL};
1595dfecf96Smrgstatic char *Char_Dle[] = {"Dle", NULL};
1605dfecf96Smrgstatic char *Char_Dc1[] = {"Dc1", NULL};
1615dfecf96Smrgstatic char *Char_Dc2[] = {"Dc2", NULL};
1625dfecf96Smrgstatic char *Char_Dc3[] = {"Dc3", NULL};
1635dfecf96Smrgstatic char *Char_Dc4[] = {"Dc4", NULL};
1645dfecf96Smrgstatic char *Char_Nak[] = {"Nak", NULL};
1655dfecf96Smrgstatic char *Char_Syn[] = {"Syn", NULL};
1665dfecf96Smrgstatic char *Char_Etb[] = {"Etb", NULL};
1675dfecf96Smrgstatic char *Char_Can[] = {"Can", NULL};
1685dfecf96Smrgstatic char *Char_Em[]  = {"Em", NULL};
1695dfecf96Smrgstatic char *Char_Sub[] = {"Sub", NULL};
1705dfecf96Smrgstatic char *Char_Esc[] = {"Escape", "Esc", NULL};
1715dfecf96Smrgstatic char *Char_Fs[]  = {"Fs", NULL};
1725dfecf96Smrgstatic char *Char_Gs[]  = {"Gs", NULL};
1735dfecf96Smrgstatic char *Char_Rs[]  = {"Rs", NULL};
1745dfecf96Smrgstatic char *Char_Us[]  = {"Us", NULL};
1755dfecf96Smrgstatic char *Char_Sp[]  = {"Space", "Sp", NULL};
1765dfecf96Smrgstatic char *Char_Del[] = {"Rubout", "Del", "Delete", NULL};
1775dfecf96Smrg
1785dfecf96SmrgLispCharInfo LispChars[256] = {
1795dfecf96Smrg    {Char_Nul},
1805dfecf96Smrg    {Char_Soh},
1815dfecf96Smrg    {Char_Stx},
1825dfecf96Smrg    {Char_Etx},
1835dfecf96Smrg    {Char_Eot},
1845dfecf96Smrg    {Char_Enq},
1855dfecf96Smrg    {Char_Ack},
1865dfecf96Smrg    {Char_Bel},
1875dfecf96Smrg    {Char_Bs},
1885dfecf96Smrg    {Char_Tab},
1895dfecf96Smrg    {Char_Nl},
1905dfecf96Smrg    {Char_Vt},
1915dfecf96Smrg    {Char_Np},
1925dfecf96Smrg    {Char_Cr},
1935dfecf96Smrg    {Char_Ff},
1945dfecf96Smrg    {Char_Si},
1955dfecf96Smrg    {Char_Dle},
1965dfecf96Smrg    {Char_Dc1},
1975dfecf96Smrg    {Char_Dc2},
1985dfecf96Smrg    {Char_Dc3},
1995dfecf96Smrg    {Char_Dc4},
2005dfecf96Smrg    {Char_Nak},
2015dfecf96Smrg    {Char_Syn},
2025dfecf96Smrg    {Char_Etb},
2035dfecf96Smrg    {Char_Can},
2045dfecf96Smrg    {Char_Em},
2055dfecf96Smrg    {Char_Sub},
2065dfecf96Smrg    {Char_Esc},
2075dfecf96Smrg    {Char_Fs},
2085dfecf96Smrg    {Char_Gs},
2095dfecf96Smrg    {Char_Rs},
2105dfecf96Smrg    {Char_Us},
2115dfecf96Smrg    {Char_Sp},
2125dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2135dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2145dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2155dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2165dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2175dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2185dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2195dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2205dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2215dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2225dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2235dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2245dfecf96Smrg    {Char_Del},
2255dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2265dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2275dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2285dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2295dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2305dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2315dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2325dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2335dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2345dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2355dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2365dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2375dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2385dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2395dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
2405dfecf96Smrg    {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
2415dfecf96Smrg
2425dfecf96Smrg};
2435dfecf96Smrg
2445dfecf96SmrgAtom_id Sand, Sor, Snot;
2455dfecf96Smrg
2465dfecf96Smrg
2475dfecf96Smrg/*
2485dfecf96Smrg * Implementation
2495dfecf96Smrg */
2505dfecf96SmrgLispObj *
2515dfecf96SmrgLisp_Read(LispBuiltin *builtin)
2525dfecf96Smrg/*
2535dfecf96Smrg read &optional input-stream eof-error-p eof-value recursive-p
2545dfecf96Smrg */
2555dfecf96Smrg{
2565dfecf96Smrg    LispObj *result;
2575dfecf96Smrg
2585dfecf96Smrg    LispObj *input_stream, *eof_error_p, *eof_value;
2595dfecf96Smrg
2605dfecf96Smrg    eof_value = ARGUMENT(2);
2615dfecf96Smrg    eof_error_p = ARGUMENT(1);
2625dfecf96Smrg    input_stream = ARGUMENT(0);
2635dfecf96Smrg
2645dfecf96Smrg    if (input_stream == UNSPEC)
2655dfecf96Smrg	input_stream = NIL;
2665dfecf96Smrg    else if (input_stream != NIL) {
2675dfecf96Smrg	CHECK_STREAM(input_stream);
2685dfecf96Smrg	else if (!input_stream->data.stream.readable)
2695dfecf96Smrg	    LispDestroy("%s: stream %s is not readable",
2705dfecf96Smrg			STRFUN(builtin), STROBJ(input_stream));
2715dfecf96Smrg	LispPushInput(input_stream);
2725dfecf96Smrg    }
2735dfecf96Smrg    else if (CONSP(lisp__data.input_list)) {
2745dfecf96Smrg	input_stream = STANDARD_INPUT;
2755dfecf96Smrg	LispPushInput(input_stream);
2765dfecf96Smrg    }
2775dfecf96Smrg
2785dfecf96Smrg    if (eof_value == UNSPEC)
2795dfecf96Smrg	eof_value = NIL;
2805dfecf96Smrg
2815dfecf96Smrg    result = LispRead();
2825dfecf96Smrg    if (input_stream != NIL)
2835dfecf96Smrg	LispPopInput(input_stream);
2845dfecf96Smrg
2855dfecf96Smrg    if (result == NULL) {
2865dfecf96Smrg	if (eof_error_p != NIL)
2875dfecf96Smrg	    LispDestroy("%s: EOF reading stream %s",
2885dfecf96Smrg			STRFUN(builtin), STROBJ(input_stream));
2895dfecf96Smrg	else
2905dfecf96Smrg	    result = eof_value;
2915dfecf96Smrg    }
2925dfecf96Smrg
2935dfecf96Smrg    return (result);
2945dfecf96Smrg}
2955dfecf96Smrg
2965dfecf96Smrgstatic LispObj *
2975dfecf96SmrgLispReadChar(LispBuiltin *builtin, int nohang)
2985dfecf96Smrg{
2995dfecf96Smrg    int character;
3005dfecf96Smrg
3015dfecf96Smrg    LispObj *input_stream, *eof_error_p, *eof_value;
3025dfecf96Smrg
3035dfecf96Smrg    eof_value = ARGUMENT(2);
3045dfecf96Smrg    eof_error_p = ARGUMENT(1);
3055dfecf96Smrg    input_stream = ARGUMENT(0);
3065dfecf96Smrg
3075dfecf96Smrg    if (input_stream == UNSPEC)
3085dfecf96Smrg	input_stream = NIL;
3095dfecf96Smrg    else if (input_stream != NIL) {
3105dfecf96Smrg	CHECK_STREAM(input_stream);
3115dfecf96Smrg    }
3125dfecf96Smrg    else
3135dfecf96Smrg	input_stream = lisp__data.input;
3145dfecf96Smrg
3155dfecf96Smrg    if (eof_value == UNSPEC)
3165dfecf96Smrg	eof_value = NIL;
3175dfecf96Smrg
3185dfecf96Smrg    character = EOF;
3195dfecf96Smrg
3205dfecf96Smrg    if (input_stream->data.stream.readable) {
3215dfecf96Smrg	LispFile *file = NULL;
3225dfecf96Smrg
3235dfecf96Smrg	switch (input_stream->data.stream.type) {
3245dfecf96Smrg	    case LispStreamStandard:
3255dfecf96Smrg	    case LispStreamFile:
3265dfecf96Smrg		file = FSTREAMP(input_stream);
3275dfecf96Smrg		break;
3285dfecf96Smrg	    case LispStreamPipe:
3295dfecf96Smrg		file = IPSTREAMP(input_stream);
3305dfecf96Smrg		break;
3315dfecf96Smrg	    case LispStreamString:
3325dfecf96Smrg		character = LispSgetc(SSTREAMP(input_stream));
3335dfecf96Smrg		break;
3345dfecf96Smrg	    default:
3355dfecf96Smrg		break;
3365dfecf96Smrg	}
3375dfecf96Smrg	if (file != NULL) {
3385dfecf96Smrg	    if (file->available || file->offset < file->length)
3395dfecf96Smrg		character = LispFgetc(file);
3405dfecf96Smrg	    else {
3415dfecf96Smrg		if (nohang && !file->nonblock) {
3425dfecf96Smrg		    if (fcntl(file->descriptor, F_SETFL, O_NONBLOCK) < 0)
3435dfecf96Smrg			LispDestroy("%s: fcntl(%d): %s",
3445dfecf96Smrg				    STRFUN(builtin), file->descriptor,
3455dfecf96Smrg				    strerror(errno));
3465dfecf96Smrg		    file->nonblock = 1;
3475dfecf96Smrg		}
3485dfecf96Smrg		else if (!nohang && file->nonblock) {
3495dfecf96Smrg		    if (fcntl(file->descriptor, F_SETFL, 0) < 0)
3505dfecf96Smrg			LispDestroy("%s: fcntl(%d): %s",
3515dfecf96Smrg				    STRFUN(builtin), file->descriptor,
3525dfecf96Smrg				    strerror(errno));
3535dfecf96Smrg		    file->nonblock = 0;
3545dfecf96Smrg		}
3555dfecf96Smrg		if (nohang) {
3565dfecf96Smrg		    unsigned char ch;
3575dfecf96Smrg
3585dfecf96Smrg		    if (read(file->descriptor, &ch, 1) == 1)
3595dfecf96Smrg			character = ch;
3605dfecf96Smrg		    else if (errno == EAGAIN)
3615dfecf96Smrg			return (NIL);	/* XXX no character available */
3625dfecf96Smrg		    else
3635dfecf96Smrg			character = EOF;
3645dfecf96Smrg		}
3655dfecf96Smrg		else
3665dfecf96Smrg		    character = LispFgetc(file);
3675dfecf96Smrg	    }
3685dfecf96Smrg	}
3695dfecf96Smrg    }
3705dfecf96Smrg    else
3715dfecf96Smrg	LispDestroy("%s: stream %s is unreadable",
3725dfecf96Smrg		    STRFUN(builtin), STROBJ(input_stream));
3735dfecf96Smrg
3745dfecf96Smrg    if (character == EOF) {
3755dfecf96Smrg	if (eof_error_p != NIL)
3765dfecf96Smrg	    LispDestroy("%s: EOF reading stream %s",
3775dfecf96Smrg			STRFUN(builtin), STROBJ(input_stream));
3785dfecf96Smrg
3795dfecf96Smrg	return (eof_value);
3805dfecf96Smrg    }
3815dfecf96Smrg
3825dfecf96Smrg    return (SCHAR(character));
3835dfecf96Smrg}
3845dfecf96Smrg
3855dfecf96SmrgLispObj *
3865dfecf96SmrgLisp_ReadChar(LispBuiltin *builtin)
3875dfecf96Smrg/*
3885dfecf96Smrg read-char &optional input-stream eof-error-p eof-value recursive-p
3895dfecf96Smrg */
3905dfecf96Smrg{
3915dfecf96Smrg    return (LispReadChar(builtin, 0));
3925dfecf96Smrg}
3935dfecf96Smrg
3945dfecf96SmrgLispObj *
3955dfecf96SmrgLisp_ReadCharNoHang(LispBuiltin *builtin)
3965dfecf96Smrg/*
3975dfecf96Smrg read-char-no-hang &optional input-stream eof-error-p eof-value recursive-p
3985dfecf96Smrg */
3995dfecf96Smrg{
4005dfecf96Smrg    return (LispReadChar(builtin, 1));
4015dfecf96Smrg}
4025dfecf96Smrg
4035dfecf96SmrgLispObj *
4045dfecf96SmrgLisp_ReadLine(LispBuiltin *builtin)
4055dfecf96Smrg/*
4065dfecf96Smrg read-line &optional input-stream eof-error-p eof-value recursive-p
4075dfecf96Smrg */
4085dfecf96Smrg{
4095dfecf96Smrg    char *string;
4105dfecf96Smrg    int ch, length;
4115dfecf96Smrg    LispObj *result, *status = NIL;
4125dfecf96Smrg
4135dfecf96Smrg    LispObj *input_stream, *eof_error_p, *eof_value;
4145dfecf96Smrg
4155dfecf96Smrg    eof_value = ARGUMENT(2);
4165dfecf96Smrg    eof_error_p = ARGUMENT(1);
4175dfecf96Smrg    input_stream = ARGUMENT(0);
4185dfecf96Smrg
4195dfecf96Smrg    if (input_stream == UNSPEC)
4205dfecf96Smrg	input_stream = NIL;
4215dfecf96Smrg    else if (input_stream == NIL)
4225dfecf96Smrg	input_stream = STANDARD_INPUT;
4235dfecf96Smrg    else {
4245dfecf96Smrg	CHECK_STREAM(input_stream);
4255dfecf96Smrg    }
4265dfecf96Smrg
4275dfecf96Smrg    if (eof_value == UNSPEC)
4285dfecf96Smrg	eof_value = NIL;
4295dfecf96Smrg
4305dfecf96Smrg    result = NIL;
4315dfecf96Smrg    string = NULL;
4325dfecf96Smrg    length = 0;
4335dfecf96Smrg
4345dfecf96Smrg    if (!input_stream->data.stream.readable)
4355dfecf96Smrg	LispDestroy("%s: stream %s is unreadable",
4365dfecf96Smrg		    STRFUN(builtin), STROBJ(input_stream));
4375dfecf96Smrg    if (input_stream->data.stream.type == LispStreamString) {
4385dfecf96Smrg	char *start, *end, *ptr;
4395dfecf96Smrg
4405dfecf96Smrg	if (SSTREAMP(input_stream)->input >=
4415dfecf96Smrg	    SSTREAMP(input_stream)->length) {
4425dfecf96Smrg	    if (eof_error_p != NIL)
4435dfecf96Smrg		LispDestroy("%s: EOS found reading %s",
4445dfecf96Smrg			    STRFUN(builtin), STROBJ(input_stream));
4455dfecf96Smrg
4465dfecf96Smrg	    status = T;
4475dfecf96Smrg	    result = eof_value;
4485dfecf96Smrg	    goto read_line_done;
4495dfecf96Smrg	}
4505dfecf96Smrg
4515dfecf96Smrg	start = SSTREAMP(input_stream)->string +
4525dfecf96Smrg		SSTREAMP(input_stream)->input;
4535dfecf96Smrg	end = SSTREAMP(input_stream)->string +
4545dfecf96Smrg	      SSTREAMP(input_stream)->length;
4555dfecf96Smrg	/* Search for a newline */
4565dfecf96Smrg	for (ptr = start; *ptr != '\n' && ptr < end; ptr++)
4575dfecf96Smrg	    ;
4585dfecf96Smrg	if (ptr == end)
4595dfecf96Smrg	    status = T;
4605dfecf96Smrg	else if (!SSTREAMP(input_stream)->binary)
4615dfecf96Smrg	    ++SSTREAMP(input_stream)->line;
4625dfecf96Smrg	length = ptr - start;
4635dfecf96Smrg	string = LispMalloc(length + 1);
4645dfecf96Smrg	memcpy(string, start, length);
4655dfecf96Smrg	string[length] = '\0';
4665dfecf96Smrg	result = LSTRING2(string, length);
4675dfecf96Smrg	/* macro LSTRING2 does not make a copy of it's arguments, and
4685dfecf96Smrg	 * calls LispMused on it. */
4695dfecf96Smrg	SSTREAMP(input_stream)->input += length + (status == NIL);
4705dfecf96Smrg    }
4715dfecf96Smrg    else /*if (input_stream->data.stream.type == LispStreamFile ||
4725dfecf96Smrg	     input_stream->data.stream.type == LispStreamStandard ||
4735dfecf96Smrg	     input_stream->data.stream.type == LispStreamPipe)*/ {
4745dfecf96Smrg	LispFile *file;
4755dfecf96Smrg
4765dfecf96Smrg	if (input_stream->data.stream.type == LispStreamPipe)
4775dfecf96Smrg	    file = IPSTREAMP(input_stream);
4785dfecf96Smrg	else
4795dfecf96Smrg	    file = FSTREAMP(input_stream);
4805dfecf96Smrg
4815dfecf96Smrg	if (file->nonblock) {
4825dfecf96Smrg	    if (fcntl(file->descriptor, F_SETFL, 0) < 0)
4835dfecf96Smrg		LispDestroy("%s: fcntl: %s",
4845dfecf96Smrg			    STRFUN(builtin), strerror(errno));
4855dfecf96Smrg	    file->nonblock = 0;
4865dfecf96Smrg	}
4875dfecf96Smrg
4885dfecf96Smrg	while (1) {
4895dfecf96Smrg	    ch = LispFgetc(file);
4905dfecf96Smrg	    if (ch == EOF) {
4915dfecf96Smrg		if (length)
4925dfecf96Smrg		    break;
4935dfecf96Smrg		if (eof_error_p != NIL)
4945dfecf96Smrg		    LispDestroy("%s: EOF found reading %s",
4955dfecf96Smrg				STRFUN(builtin), STROBJ(input_stream));
4965dfecf96Smrg		if (string)
4975dfecf96Smrg		    LispFree(string);
4985dfecf96Smrg
4995dfecf96Smrg		status = T;
5005dfecf96Smrg		result = eof_value;
5015dfecf96Smrg		goto read_line_done;
5025dfecf96Smrg	    }
5035dfecf96Smrg	    else if (ch == '\n')
5045dfecf96Smrg		break;
5055dfecf96Smrg	    else if ((length % 64) == 0)
5065dfecf96Smrg		string = LispRealloc(string, length + 64);
5075dfecf96Smrg	    string[length++] = ch;
5085dfecf96Smrg	}
5095dfecf96Smrg	if (string) {
5105dfecf96Smrg	    if ((length % 64) == 0)
5115dfecf96Smrg		string = LispRealloc(string, length + 1);
5125dfecf96Smrg	    string[length] = '\0';
5135dfecf96Smrg	    result = LSTRING2(string, length);
5145dfecf96Smrg	}
5155dfecf96Smrg	else
5165dfecf96Smrg	    result = STRING("");
5175dfecf96Smrg    }
5185dfecf96Smrg
5195dfecf96Smrgread_line_done:
5205dfecf96Smrg    RETURN(0) = status;
5215dfecf96Smrg    RETURN_COUNT = 1;
5225dfecf96Smrg
5235dfecf96Smrg    return (result);
5245dfecf96Smrg}
5255dfecf96Smrg
5265dfecf96SmrgLispObj *
5275dfecf96SmrgLispRead(void)
5285dfecf96Smrg{
5295dfecf96Smrg    READ_ENTER();
5305dfecf96Smrg    read_info info;
5315dfecf96Smrg    LispObj *result, *code = COD;
5325dfecf96Smrg
5335dfecf96Smrg    info.level = info.nodot = info.discard = 0;
5345dfecf96Smrg    info.circle_count = 0;
5355dfecf96Smrg    info.objects = NULL;
5365dfecf96Smrg    info.num_objects = 0;
5375dfecf96Smrg
5385dfecf96Smrg    result = LispDoRead(&info);
5395dfecf96Smrg
5405dfecf96Smrg    /* fix circular/shared lists, note that this is done when returning to
5415dfecf96Smrg     * the toplevel, so, if some circular/shared reference was evaluated,
5425dfecf96Smrg     * it should have generated an expected error */
5435dfecf96Smrg    if (info.num_objects) {
5445dfecf96Smrg	if (info.circle_count) {
5455dfecf96Smrg	    info.circles = NULL;
5465dfecf96Smrg	    info.num_circles = 0;
5475dfecf96Smrg	    LispReadFixCircle(result, &info);
5485dfecf96Smrg	    if (info.num_circles)
5495dfecf96Smrg		LispFree(info.circles);
5505dfecf96Smrg	}
5515dfecf96Smrg	LispFree(info.objects);
5525dfecf96Smrg    }
5535dfecf96Smrg
5545dfecf96Smrg    if (result == EOLIST)
5555dfecf96Smrg	READ_ERROR0("object cannot start with #\\)");
5565dfecf96Smrg    else if (result == DOT)
5575dfecf96Smrg	READ_ERROR0("dot allowed only on lists");
5585dfecf96Smrg
5595dfecf96Smrg    if (result != NULL && POINTERP(result)) {
5605dfecf96Smrg	if (code == NIL)
5615dfecf96Smrg	    COD = result;
5625dfecf96Smrg	else
5635dfecf96Smrg	    COD = CONS(COD, result);
5645dfecf96Smrg    }
5655dfecf96Smrg
5665dfecf96Smrg    return (result);
5675dfecf96Smrg}
5685dfecf96Smrg
5695dfecf96Smrgstatic int
5705dfecf96SmrgLispGetLine(LispObj *stream)
5715dfecf96Smrg{
5725dfecf96Smrg    int line = -1;
5735dfecf96Smrg
5745dfecf96Smrg    if (STREAMP(stream)) {
5755dfecf96Smrg	switch (stream->data.stream.type) {
5765dfecf96Smrg	    case LispStreamStandard:
5775dfecf96Smrg	    case LispStreamFile:
5785dfecf96Smrg		if (!FSTREAMP(stream)->binary)
5795dfecf96Smrg		    line = FSTREAMP(stream)->line;
5805dfecf96Smrg		break;
5815dfecf96Smrg	    case LispStreamPipe:
5825dfecf96Smrg		if (!IPSTREAMP(stream)->binary)
5835dfecf96Smrg		    line = IPSTREAMP(stream)->line;
5845dfecf96Smrg		break;
5855dfecf96Smrg	    case LispStreamString:
5865dfecf96Smrg		if (!SSTREAMP(stream)->binary)
5875dfecf96Smrg		    line = SSTREAMP(stream)->line;
5885dfecf96Smrg		break;
5895dfecf96Smrg	    default:
5905dfecf96Smrg		break;
5915dfecf96Smrg	}
5925dfecf96Smrg    }
5935dfecf96Smrg    else if (stream == NIL && !Stdin->binary)
5945dfecf96Smrg	line = Stdin->line;
5955dfecf96Smrg
5965dfecf96Smrg    return (line);
5975dfecf96Smrg}
5985dfecf96Smrg
5995dfecf96Smrgstatic void
6005dfecf96SmrgLispReadError(LispObj *stream, int line, char *fmt, ...)
6015dfecf96Smrg{
6025dfecf96Smrg    char string[128], *buffer_string;
6035dfecf96Smrg    LispObj *buffer = LSTRINGSTREAM("", STREAM_READ | STREAM_WRITE, 0);
6045dfecf96Smrg    int length;
6055dfecf96Smrg    va_list ap;
6065dfecf96Smrg
6075dfecf96Smrg    va_start(ap, fmt);
6085dfecf96Smrg    vsnprintf(string, sizeof(string), fmt, ap);
6095dfecf96Smrg    va_end(ap);
6105dfecf96Smrg
6115dfecf96Smrg    LispFwrite(Stderr, "*** Reading ", 12);
6125dfecf96Smrg    LispWriteObject(buffer, stream);
6135dfecf96Smrg    buffer_string = LispGetSstring(SSTREAMP(buffer), &length);
6145dfecf96Smrg    LispFwrite(Stderr, buffer_string, length);
6155dfecf96Smrg    LispFwrite(Stderr, " at line ", 9);
6165dfecf96Smrg    if (line < 0)
6175dfecf96Smrg	LispFwrite(Stderr, "?\n", 2);
6185dfecf96Smrg    else {
6195dfecf96Smrg	char str[32];
6205dfecf96Smrg
6215dfecf96Smrg	sprintf(str, "%d\n", line);
6225dfecf96Smrg	LispFputs(Stderr, str);
6235dfecf96Smrg    }
6245dfecf96Smrg
6255dfecf96Smrg    LispDestroy("READ: %s", string);
6265dfecf96Smrg}
6275dfecf96Smrg
6285dfecf96Smrgstatic void
6295dfecf96SmrgLispReadFixCircle(LispObj *object, read_info *info)
6305dfecf96Smrg{
6315dfecf96Smrg    LispObj *cons;
6325dfecf96Smrg
6335dfecf96Smrgfix_again:
6345dfecf96Smrg    switch (OBJECT_TYPE(object)) {
6355dfecf96Smrg	case LispCons_t:
6365dfecf96Smrg	    for (cons = object;
6375dfecf96Smrg		 CONSP(object);
6385dfecf96Smrg		 cons = object, object = CDR(object)) {
6395dfecf96Smrg		if (READLABELP(CAR(object)))
6405dfecf96Smrg		    CAR(object) = LispReadLabelCircle(CAR(object), info);
6415dfecf96Smrg		else if (LispReadCheckCircle(object, info))
6425dfecf96Smrg		    return;
6435dfecf96Smrg		else
6445dfecf96Smrg		    LispReadFixCircle(CAR(object), info);
6455dfecf96Smrg	    }
6465dfecf96Smrg	    if (READLABELP(object))
6475dfecf96Smrg		CDR(cons) = LispReadLabelCircle(object, info);
6485dfecf96Smrg	    else
6495dfecf96Smrg		goto fix_again;
6505dfecf96Smrg	    break;
6515dfecf96Smrg	case LispArray_t:
6525dfecf96Smrg	    if (READLABELP(object->data.array.list))
6535dfecf96Smrg		object->data.array.list =
6545dfecf96Smrg		    LispReadLabelCircle(object->data.array.list, info);
6555dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6565dfecf96Smrg		object = object->data.array.list;
6575dfecf96Smrg		goto fix_again;
6585dfecf96Smrg	    }
6595dfecf96Smrg	    break;
6605dfecf96Smrg	case LispStruct_t:
6615dfecf96Smrg	    if (READLABELP(object->data.struc.fields))
6625dfecf96Smrg		object->data.struc.fields =
6635dfecf96Smrg		    LispReadLabelCircle(object->data.struc.fields, info);
6645dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6655dfecf96Smrg		object = object->data.struc.fields;
6665dfecf96Smrg		goto fix_again;
6675dfecf96Smrg	    }
6685dfecf96Smrg	    break;
6695dfecf96Smrg	case LispQuote_t:
6705dfecf96Smrg	case LispBackquote_t:
6715dfecf96Smrg	case LispFunctionQuote_t:
6725dfecf96Smrg	    if (READLABELP(object->data.quote))
6735dfecf96Smrg		object->data.quote =
6745dfecf96Smrg		    LispReadLabelCircle(object->data.quote, info);
6755dfecf96Smrg	    else {
6765dfecf96Smrg		object = object->data.quote;
6775dfecf96Smrg		goto fix_again;
6785dfecf96Smrg	    }
6795dfecf96Smrg	    break;
6805dfecf96Smrg	case LispComma_t:
6815dfecf96Smrg	    if (READLABELP(object->data.comma.eval))
6825dfecf96Smrg		object->data.comma.eval =
6835dfecf96Smrg		    LispReadLabelCircle(object->data.comma.eval, info);
6845dfecf96Smrg	    else {
6855dfecf96Smrg		object = object->data.comma.eval;
6865dfecf96Smrg		goto fix_again;
6875dfecf96Smrg	    }
6885dfecf96Smrg	    break;
6895dfecf96Smrg	case LispLambda_t:
6905dfecf96Smrg	    if (READLABELP(object->data.lambda.code))
6915dfecf96Smrg		object->data.lambda.code =
6925dfecf96Smrg		    LispReadLabelCircle(object->data.lambda.code, info);
6935dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6945dfecf96Smrg		object = object->data.lambda.code;
6955dfecf96Smrg		goto fix_again;
6965dfecf96Smrg	    }
6975dfecf96Smrg	    break;
6985dfecf96Smrg	default:
6995dfecf96Smrg	    break;
7005dfecf96Smrg    }
7015dfecf96Smrg}
7025dfecf96Smrg
7035dfecf96Smrgstatic LispObj *
7045dfecf96SmrgLispReadLabelCircle(LispObj *label, read_info *info)
7055dfecf96Smrg{
7065dfecf96Smrg    long i, value = READLABEL_VALUE(label);
7075dfecf96Smrg
7085dfecf96Smrg    for (i = 0; i < info->num_objects; i++)
7095dfecf96Smrg	if (info->objects[i].label == value)
7105dfecf96Smrg	    return (info->objects[i].object);
7115dfecf96Smrg
7125dfecf96Smrg    LispDestroy("READ: internal error");
7135dfecf96Smrg    /*NOTREACHED*/
7145dfecf96Smrg    return (label);
7155dfecf96Smrg}
7165dfecf96Smrg
7175dfecf96Smrgstatic int
7185dfecf96SmrgLispReadCheckCircle(LispObj *object, read_info *info)
7195dfecf96Smrg{
7205dfecf96Smrg    long i;
7215dfecf96Smrg
7225dfecf96Smrg    for (i = 0; i < info->num_circles; i++)
7235dfecf96Smrg	if (info->circles[i] == object)
7245dfecf96Smrg	    return (1);
7255dfecf96Smrg
7265dfecf96Smrg    if ((info->num_circles % 16) == 0)
7275dfecf96Smrg	info->circles = LispRealloc(info->circles, sizeof(LispObj*) *
7285dfecf96Smrg				    (info->num_circles + 16));
7295dfecf96Smrg    info->circles[info->num_circles++] = object;
7305dfecf96Smrg
7315dfecf96Smrg    return (0);
7325dfecf96Smrg}
7335dfecf96Smrg
7345dfecf96Smrgstatic LispObj *
7355dfecf96SmrgLispDoRead(read_info *info)
7365dfecf96Smrg{
7375dfecf96Smrg    LispObj *object;
7385dfecf96Smrg    int ch = LispSkipWhiteSpace();
7395dfecf96Smrg
7405dfecf96Smrg    switch (ch) {
7415dfecf96Smrg	case '(':
7425dfecf96Smrg	    object = LispReadList(info);
7435dfecf96Smrg	    break;
7445dfecf96Smrg	case ')':
7455dfecf96Smrg	    for (ch = LispGet(); ch != EOF && ch != '\n'; ch = LispGet()) {
7465dfecf96Smrg		if (!isspace(ch)) {
7475dfecf96Smrg		    LispUnget(ch);
7485dfecf96Smrg		    break;
7495dfecf96Smrg		}
7505dfecf96Smrg	    }
7515dfecf96Smrg	    return (EOLIST);
7525dfecf96Smrg	case EOF:
7535dfecf96Smrg	    return (NULL);
7545dfecf96Smrg	case '\'':
7555dfecf96Smrg	    object = LispReadQuote(info);
7565dfecf96Smrg	    break;
7575dfecf96Smrg	case '`':
7585dfecf96Smrg	    object = LispReadBackquote(info);
7595dfecf96Smrg	    break;
7605dfecf96Smrg	case ',':
7615dfecf96Smrg	    object = LispReadCommaquote(info);
7625dfecf96Smrg	    break;
7635dfecf96Smrg	case '#':
7645dfecf96Smrg	    object = LispReadMacro(info);
7655dfecf96Smrg	    break;
7665dfecf96Smrg	default:
7675dfecf96Smrg	    LispUnget(ch);
7685dfecf96Smrg	    object = LispReadObject(0, info);
7695dfecf96Smrg	    break;
7705dfecf96Smrg    }
7715dfecf96Smrg
7725dfecf96Smrg    return (object);
7735dfecf96Smrg}
7745dfecf96Smrg
7755dfecf96Smrgstatic LispObj *
7765dfecf96SmrgLispReadMacro(read_info *info)
7775dfecf96Smrg{
7785dfecf96Smrg    READ_ENTER();
7795dfecf96Smrg    LispObj *result = NULL;
7805dfecf96Smrg    int ch = LispGet();
7815dfecf96Smrg
7825dfecf96Smrg    switch (ch) {
7835dfecf96Smrg	case '(':
7845dfecf96Smrg	    result = LispReadVector(info);
7855dfecf96Smrg	    break;
7865dfecf96Smrg	case '\'':
7875dfecf96Smrg	   result = LispReadFunction(info);
7885dfecf96Smrg	   break;
7895dfecf96Smrg	case 'b':
7905dfecf96Smrg	case 'B':
7915dfecf96Smrg	    result = LispReadRational(2, info);
7925dfecf96Smrg	    break;
7935dfecf96Smrg	case 'o':
7945dfecf96Smrg	case 'O':
7955dfecf96Smrg	    result = LispReadRational(8, info);
7965dfecf96Smrg	    break;
7975dfecf96Smrg	case 'x':
7985dfecf96Smrg	case 'X':
7995dfecf96Smrg	    result = LispReadRational(16, info);
8005dfecf96Smrg	    break;
8015dfecf96Smrg	case '\\':
8025dfecf96Smrg	    result = LispReadCharacter(info);
8035dfecf96Smrg	    break;
8045dfecf96Smrg	case '|':
8055dfecf96Smrg	    LispSkipComment();
8065dfecf96Smrg	    result = LispDoRead(info);
8075dfecf96Smrg	    break;
8085dfecf96Smrg	case '.':	/* eval when compiling */
8095dfecf96Smrg	case ',':	/* eval when loading */
8105dfecf96Smrg	    result = LispReadEval(info);
8115dfecf96Smrg	    break;
8125dfecf96Smrg	case 'c':
8135dfecf96Smrg	case 'C':
8145dfecf96Smrg	    result = LispReadComplex(info);
8155dfecf96Smrg	    break;
8165dfecf96Smrg	case 'p':
8175dfecf96Smrg	case 'P':
8185dfecf96Smrg	    result = LispReadPathname(info);
8195dfecf96Smrg	    break;
8205dfecf96Smrg	case 's':
8215dfecf96Smrg	case 'S':
8225dfecf96Smrg	    result = LispReadStruct(info);
8235dfecf96Smrg	    break;
8245dfecf96Smrg	case '+':
8255dfecf96Smrg	    result = LispReadFeature(1, info);
8265dfecf96Smrg	    break;
8275dfecf96Smrg	case '-':
8285dfecf96Smrg	    result = LispReadFeature(0, info);
8295dfecf96Smrg	    break;
8305dfecf96Smrg	case ':':
8315dfecf96Smrg	    /* Uninterned symbol */
8325dfecf96Smrg	    result = LispReadObject(1, info);
8335dfecf96Smrg	    break;
8345dfecf96Smrg	default:
8355dfecf96Smrg	    if (isdigit(ch)) {
8365dfecf96Smrg		LispUnget(ch);
8375dfecf96Smrg		result = LispReadMacroArg(info);
8385dfecf96Smrg	    }
8395dfecf96Smrg	    else if (!info->discard)
8405dfecf96Smrg		READ_ERROR1("undefined dispatch macro character #%c", ch);
8415dfecf96Smrg	    break;
8425dfecf96Smrg    }
8435dfecf96Smrg
8445dfecf96Smrg    return (result);
8455dfecf96Smrg}
8465dfecf96Smrg
8475dfecf96Smrgstatic LispObj *
8485dfecf96SmrgLispReadMacroArg(read_info *info)
8495dfecf96Smrg{
8505dfecf96Smrg    READ_ENTER();
8515dfecf96Smrg    LispObj *result = NIL;
8525dfecf96Smrg    long i, integer;
8535dfecf96Smrg    int ch;
8545dfecf96Smrg
8555dfecf96Smrg    /* skip leading zeros */
8565dfecf96Smrg    while (ch = LispGet(), ch != EOF && isdigit(ch) && ch == '0')
8575dfecf96Smrg	;
8585dfecf96Smrg
8595dfecf96Smrg    if (ch == EOF)
8605dfecf96Smrg	READ_ERROR_EOF();
8615dfecf96Smrg
8625dfecf96Smrg    /* if ch is not a number the argument was zero */
8635dfecf96Smrg    if (isdigit(ch)) {
8645dfecf96Smrg	char stk[32], *str;
8655dfecf96Smrg	int len = 1;
8665dfecf96Smrg
8675dfecf96Smrg	stk[0] = ch;
8685dfecf96Smrg	for (;;) {
8695dfecf96Smrg	    ch = LispGet();
8705dfecf96Smrg	    if (!isdigit(ch))
8715dfecf96Smrg		break;
8725dfecf96Smrg	    if (len + 1 >= sizeof(stk))
8735dfecf96Smrg		READ_ERROR_FIXNUM();
8745dfecf96Smrg	    stk[len++] = ch;
8755dfecf96Smrg	}
8765dfecf96Smrg	stk[len] = '\0';
8775dfecf96Smrg	errno = 0;
8785dfecf96Smrg	integer = strtol(stk, &str, 10);
8795dfecf96Smrg	/* number is positive because sign is not processed here */
8805dfecf96Smrg	if (*str || errno == ERANGE || integer > MOST_POSITIVE_FIXNUM)
8815dfecf96Smrg	    READ_ERROR_FIXNUM();
8825dfecf96Smrg    }
8835dfecf96Smrg    else
8845dfecf96Smrg	integer = 0;
8855dfecf96Smrg
8865dfecf96Smrg    switch (ch) {
8875dfecf96Smrg	case 'a':
8885dfecf96Smrg	case 'A':
8895dfecf96Smrg	    if (integer == 1) {
8905dfecf96Smrg		/* LispReadArray and LispReadList expect
8915dfecf96Smrg		 * the '(' being already read  */
8925dfecf96Smrg		if ((ch = LispSkipWhiteSpace()) != '(') {
8935dfecf96Smrg		    if (info->discard)
8945dfecf96Smrg			return (ch == EOF ? NULL : NIL);
8955dfecf96Smrg		    READ_ERROR0("bad array specification");
8965dfecf96Smrg		}
8975dfecf96Smrg		result = LispReadVector(info);
8985dfecf96Smrg	    }
8995dfecf96Smrg	    else
9005dfecf96Smrg		result = LispReadArray(integer, info);
9015dfecf96Smrg	    break;
9025dfecf96Smrg	case 'r':
9035dfecf96Smrg	case 'R':
9045dfecf96Smrg	    result = LispReadRational(integer, info);
9055dfecf96Smrg	    break;
9065dfecf96Smrg	case '=':
9075dfecf96Smrg	    if (integer > MAX_LABEL_VALUE)
9085dfecf96Smrg		READ_ERROR_FIXNUM();
9095dfecf96Smrg	    if (!info->discard) {
9105dfecf96Smrg		long num_objects = info->num_objects;
9115dfecf96Smrg
9125dfecf96Smrg		/* check for duplicated label */
9135dfecf96Smrg		for (i = 0; i < info->num_objects; i++) {
9145dfecf96Smrg		    if (info->objects[i].label == integer)
9155dfecf96Smrg			READ_ERROR1("label #%ld# defined more than once",
9165dfecf96Smrg				    integer);
9175dfecf96Smrg		}
9185dfecf96Smrg		info->objects = LispRealloc(info->objects,
9195dfecf96Smrg					    sizeof(object_info) *
9205dfecf96Smrg					    (num_objects + 1));
9215dfecf96Smrg		/* if this label is referenced it is a shared/circular object */
9225dfecf96Smrg		info->objects[num_objects].label = integer;
9235dfecf96Smrg		info->objects[num_objects].object = NULL;
9245dfecf96Smrg		info->objects[num_objects].num_circles = 0;
9255dfecf96Smrg		++info->num_objects;
9265dfecf96Smrg		result = LispDoRead(info);
9275dfecf96Smrg		if (READLABELP(result) && READLABEL_VALUE(result) == integer)
9285dfecf96Smrg		    READ_ERROR2("incorrect syntax #%ld= #%ld#",
9295dfecf96Smrg				integer, integer);
9305dfecf96Smrg		/* any reference to it now is not shared/circular */
9315dfecf96Smrg		info->objects[num_objects].object = result;
9325dfecf96Smrg	    }
9335dfecf96Smrg	    else
9345dfecf96Smrg		result = LispDoRead(info);
9355dfecf96Smrg	    break;
9365dfecf96Smrg	case '#':
9375dfecf96Smrg	    if (integer > MAX_LABEL_VALUE)
9385dfecf96Smrg		READ_ERROR_FIXNUM();
9395dfecf96Smrg	    if (!info->discard) {
9405dfecf96Smrg		/* search object */
9415dfecf96Smrg		for (i = 0; i < info->num_objects; i++) {
9425dfecf96Smrg		    if (info->objects[i].label == integer) {
9435dfecf96Smrg			result = info->objects[i].object;
9445dfecf96Smrg			if (result == NULL) {
9455dfecf96Smrg			    ++info->objects[i].num_circles;
9465dfecf96Smrg			    ++info->circle_count;
9475dfecf96Smrg			    result = READLABEL(integer);
9485dfecf96Smrg			}
9495dfecf96Smrg			break;
9505dfecf96Smrg		    }
9515dfecf96Smrg		}
9525dfecf96Smrg		if (i == info->num_objects)
9535dfecf96Smrg		    READ_ERROR1("undefined label #%ld#", integer);
9545dfecf96Smrg	    }
9555dfecf96Smrg	    break;
9565dfecf96Smrg	default:
9575dfecf96Smrg	    if (!info->discard)
9585dfecf96Smrg		READ_ERROR1("undefined dispatch macro character #%c", ch);
9595dfecf96Smrg	    break;
9605dfecf96Smrg    }
9615dfecf96Smrg
9625dfecf96Smrg    return (result);
9635dfecf96Smrg}
9645dfecf96Smrg
9655dfecf96Smrgstatic int
9665dfecf96SmrgLispSkipWhiteSpace(void)
9675dfecf96Smrg{
9685dfecf96Smrg    int ch;
9695dfecf96Smrg
9705dfecf96Smrg    for (;;) {
9715dfecf96Smrg	while (ch = LispGet(), isspace(ch) && ch != EOF)
9725dfecf96Smrg	    ;
9735dfecf96Smrg	if (ch == ';') {
9745dfecf96Smrg	    while (ch = LispGet(), ch != '\n' && ch != EOF)
9755dfecf96Smrg		;
9765dfecf96Smrg	    if (ch == EOF)
9775dfecf96Smrg		return (EOF);
9785dfecf96Smrg	}
9795dfecf96Smrg	else
9805dfecf96Smrg	    break;
9815dfecf96Smrg    }
9825dfecf96Smrg
9835dfecf96Smrg    return (ch);
9845dfecf96Smrg}
9855dfecf96Smrg
9865dfecf96Smrg/* any data in the format '(' FORM ')' is read here */
9875dfecf96Smrgstatic LispObj *
9885dfecf96SmrgLispReadList(read_info *info)
9895dfecf96Smrg{
9905dfecf96Smrg    READ_ENTER();
9915dfecf96Smrg    GC_ENTER();
9925dfecf96Smrg    LispObj *result, *cons, *object;
9935dfecf96Smrg    int dot = 0;
9945dfecf96Smrg
9955dfecf96Smrg    ++info->level;
9965dfecf96Smrg    /* check for () */
9975dfecf96Smrg    object = LispDoRead(info);
9985dfecf96Smrg    if (object == EOLIST) {
9995dfecf96Smrg	--info->level;
10005dfecf96Smrg
10015dfecf96Smrg	return (NIL);
10025dfecf96Smrg    }
10035dfecf96Smrg
10045dfecf96Smrg    if (object == DOT)
10055dfecf96Smrg	READ_ERROR0("illegal start of dotted list");
10065dfecf96Smrg
10075dfecf96Smrg    result = cons = CONS(object, NIL);
10085dfecf96Smrg
10095dfecf96Smrg    /* make sure GC will not release data being read */
10105dfecf96Smrg    GC_PROTECT(result);
10115dfecf96Smrg
10125dfecf96Smrg    while ((object = LispDoRead(info)) != EOLIST) {
10135dfecf96Smrg	if (object == NULL)
10145dfecf96Smrg	    READ_ERROR_EOF();
10155dfecf96Smrg	if (object == DOT) {
10165dfecf96Smrg	    if (info->nodot == info->level)
10175dfecf96Smrg		READ_ERROR0("dotted list not allowed");
10185dfecf96Smrg	    /* this is a dotted list */
10195dfecf96Smrg	    if (dot)
10205dfecf96Smrg		READ_ERROR0("more than one . in list");
10215dfecf96Smrg	    dot = 1;
10225dfecf96Smrg	}
10235dfecf96Smrg	else {
10245dfecf96Smrg	    if (dot) {
10255dfecf96Smrg		/* only one object after a dot */
10265dfecf96Smrg		if (++dot > 2)
10275dfecf96Smrg		    READ_ERROR0("more than one object after . in list");
10285dfecf96Smrg		RPLACD(cons, object);
10295dfecf96Smrg	    }
10305dfecf96Smrg	    else {
10315dfecf96Smrg		RPLACD(cons, CONS(object, NIL));
10325dfecf96Smrg		cons = CDR(cons);
10335dfecf96Smrg	    }
10345dfecf96Smrg	}
10355dfecf96Smrg    }
10365dfecf96Smrg
10375dfecf96Smrg    /* this will happen if last list element was a dot */
10385dfecf96Smrg    if (dot == 1)
10395dfecf96Smrg	READ_ERROR0("illegal end of dotted list");
10405dfecf96Smrg
10415dfecf96Smrg    --info->level;
10425dfecf96Smrg    GC_LEAVE();
10435dfecf96Smrg
10445dfecf96Smrg    return (result);
10455dfecf96Smrg}
10465dfecf96Smrg
10475dfecf96Smrgstatic LispObj *
10485dfecf96SmrgLispReadQuote(read_info *info)
10495dfecf96Smrg{
10505dfecf96Smrg    READ_ENTER();
10515dfecf96Smrg    LispObj *quote = LispDoRead(info), *result;
10525dfecf96Smrg
10535dfecf96Smrg    if (INVALIDP(quote))
10545dfecf96Smrg	READ_ERROR_INVARG();
10555dfecf96Smrg
10565dfecf96Smrg    result = QUOTE(quote);
10575dfecf96Smrg
10585dfecf96Smrg    return (result);
10595dfecf96Smrg}
10605dfecf96Smrg
10615dfecf96Smrgstatic LispObj *
10625dfecf96SmrgLispReadBackquote(read_info *info)
10635dfecf96Smrg{
10645dfecf96Smrg    READ_ENTER();
10655dfecf96Smrg    LispObj *backquote = LispDoRead(info), *result;
10665dfecf96Smrg
10675dfecf96Smrg    if (INVALIDP(backquote))
10685dfecf96Smrg	READ_ERROR_INVARG();
10695dfecf96Smrg
10705dfecf96Smrg    result = BACKQUOTE(backquote);
10715dfecf96Smrg
10725dfecf96Smrg    return (result);
10735dfecf96Smrg}
10745dfecf96Smrg
10755dfecf96Smrgstatic LispObj *
10765dfecf96SmrgLispReadCommaquote(read_info *info)
10775dfecf96Smrg{
10785dfecf96Smrg    READ_ENTER();
10795dfecf96Smrg    LispObj *comma, *result;
10805dfecf96Smrg    int atlist = LispGet();
10815dfecf96Smrg
10825dfecf96Smrg    if (atlist == EOF)
10835dfecf96Smrg	READ_ERROR_EOF();
10845dfecf96Smrg    else if (atlist != '@' && atlist != '.')
10855dfecf96Smrg	LispUnget(atlist);
10865dfecf96Smrg
10875dfecf96Smrg    comma = LispDoRead(info);
10885dfecf96Smrg    if (comma == DOT) {
10895dfecf96Smrg	atlist = '@';
10905dfecf96Smrg	comma = LispDoRead(info);
10915dfecf96Smrg    }
10925dfecf96Smrg    if (INVALIDP(comma))
10935dfecf96Smrg	READ_ERROR_INVARG();
10945dfecf96Smrg
10955dfecf96Smrg    result = COMMA(comma, atlist == '@' || atlist == '.');
10965dfecf96Smrg
10975dfecf96Smrg    return (result);
10985dfecf96Smrg}
10995dfecf96Smrg
11005dfecf96Smrg/*
11015dfecf96Smrg * Read anything that is not readily identifiable by it's first character
11025dfecf96Smrg * and also put the code for reading atoms, numbers and strings together.
11035dfecf96Smrg */
11045dfecf96Smrgstatic LispObj *
11055dfecf96SmrgLispReadObject(int unintern, read_info *info)
11065dfecf96Smrg{
11075dfecf96Smrg    READ_ENTER();
11085dfecf96Smrg    LispObj *object;
11095dfecf96Smrg    char stk[128], *string, *package, *symbol;
11105dfecf96Smrg    int ch, length, backslash, size, quote, unreadable, collon;
11115dfecf96Smrg
11125dfecf96Smrg    package = symbol = string = stk;
11135dfecf96Smrg    size = sizeof(stk);
11145dfecf96Smrg    backslash = quote = unreadable = collon = 0;
11155dfecf96Smrg    length = 0;
11165dfecf96Smrg
11175dfecf96Smrg    ch = LispGet();
11185dfecf96Smrg    if (unintern && (ch == ':' || ch == '"'))
11195dfecf96Smrg	READ_ERROR0("syntax error after #:");
11205dfecf96Smrg    else if (ch == '"' || ch == '|')
11215dfecf96Smrg	quote = ch;
11225dfecf96Smrg    else if (ch == '\\') {
11235dfecf96Smrg	unreadable = backslash = 1;
11245dfecf96Smrg	string[length++] = ch;
11255dfecf96Smrg    }
11265dfecf96Smrg    else if (ch == ':') {
11275dfecf96Smrg	collon = 1;
11285dfecf96Smrg	string[length++] = ch;
11295dfecf96Smrg	symbol = string + 1;
1130f14f4646Smrg	ch = LispGet();
1131f14f4646Smrg	if (ch == '|') {
1132f14f4646Smrg	    quote = ch;
1133f14f4646Smrg	    unreadable = 1;
1134f14f4646Smrg	}
1135f14f4646Smrg	else if (ch != EOF)
1136f14f4646Smrg	    LispUnget(ch);
11375dfecf96Smrg    }
11385dfecf96Smrg    else if (ch) {
11395dfecf96Smrg	if (islower(ch))
11405dfecf96Smrg	    ch = toupper(ch);
11415dfecf96Smrg	string[length++] = ch;
11425dfecf96Smrg    }
11435dfecf96Smrg    else
11445dfecf96Smrg	unreadable = 1;
11455dfecf96Smrg
11465dfecf96Smrg    /* read remaining data */
11475dfecf96Smrg    for (; ch;) {
11485dfecf96Smrg	ch = LispGet();
11495dfecf96Smrg
11505dfecf96Smrg	if (ch == EOF) {
11515dfecf96Smrg	    if (quote) {
11525dfecf96Smrg		/* if quote, file ended with an open quoted object */
11535dfecf96Smrg		if (string != stk)
11545dfecf96Smrg		    LispFree(string);
11555dfecf96Smrg		return (NULL);
11565dfecf96Smrg	    }
11575dfecf96Smrg	    break;
11585dfecf96Smrg	}
11595dfecf96Smrg	else if (ch == '\0')
11605dfecf96Smrg	    break;
11615dfecf96Smrg
11625dfecf96Smrg	if (ch == '\\') {
11635dfecf96Smrg	    backslash = !backslash;
11645dfecf96Smrg	    if (quote == '"') {
11655dfecf96Smrg		/* only remove backslashs from strings */
11665dfecf96Smrg		if (backslash)
11675dfecf96Smrg		    continue;
11685dfecf96Smrg	    }
11695dfecf96Smrg	    else
11705dfecf96Smrg		unreadable = 1;
11715dfecf96Smrg	}
11725dfecf96Smrg	else if (backslash)
11735dfecf96Smrg	    backslash = 0;
11745dfecf96Smrg	else if (ch == quote)
11755dfecf96Smrg	    break;
11765dfecf96Smrg	else if (!quote && !backslash) {
11775dfecf96Smrg	    if (islower(ch))
11785dfecf96Smrg		ch = toupper(ch);
11795dfecf96Smrg	    else if (isspace(ch))
11805dfecf96Smrg		break;
11815dfecf96Smrg	    else if (AtomSeparator(ch, 0, 0)) {
11825dfecf96Smrg		LispUnget(ch);
11835dfecf96Smrg		break;
11845dfecf96Smrg	    }
11855dfecf96Smrg	    else if (ch == ':') {
11865dfecf96Smrg		if (collon == 0 ||
11875dfecf96Smrg		    (collon == (1 - unintern) && symbol == string + length)) {
11885dfecf96Smrg		    ++collon;
11895dfecf96Smrg		    symbol = string + length + 1;
11905dfecf96Smrg		}
11915dfecf96Smrg		else
11925dfecf96Smrg		    READ_ERROR0("too many collons");
11935dfecf96Smrg	    }
11945dfecf96Smrg	}
11955dfecf96Smrg
11965dfecf96Smrg	if (length + 2 >= size) {
11975dfecf96Smrg	    if (string == stk) {
11985dfecf96Smrg		size = 1024;
11995dfecf96Smrg		string = LispMalloc(size);
12005dfecf96Smrg		strcpy(string, stk);
12015dfecf96Smrg	    }
12025dfecf96Smrg	    else {
12035dfecf96Smrg		size += 1024;
12045dfecf96Smrg		string = LispRealloc(string, size);
12055dfecf96Smrg	    }
12065dfecf96Smrg	    symbol = string + (symbol - package);
12075dfecf96Smrg	    package = string;
12085dfecf96Smrg	}
12095dfecf96Smrg	string[length++] = ch;
12105dfecf96Smrg    }
12115dfecf96Smrg
12125dfecf96Smrg    if (info->discard) {
12135dfecf96Smrg	if (string != stk)
12145dfecf96Smrg	    LispFree(string);
12155dfecf96Smrg
12165dfecf96Smrg	return (ch == EOF ? NULL : NIL);
12175dfecf96Smrg    }
12185dfecf96Smrg
12195dfecf96Smrg    string[length] = '\0';
12205dfecf96Smrg
12215dfecf96Smrg    if (unintern) {
12225dfecf96Smrg	if (length == 0)
12235dfecf96Smrg	    READ_ERROR0("syntax error after #:");
12245dfecf96Smrg	object = UNINTERNED_ATOM(string);
12255dfecf96Smrg    }
12265dfecf96Smrg
12275dfecf96Smrg    else if (quote == '"')
12285dfecf96Smrg	object = LSTRING(string, length);
12295dfecf96Smrg
12305dfecf96Smrg    else if (collon) {
12315dfecf96Smrg	/* Package specified in object name */
12325dfecf96Smrg	symbol[-1] = '\0';
12335dfecf96Smrg	if (collon > 1)
12345dfecf96Smrg	    symbol[-2] = '\0';
12355dfecf96Smrg	object = LispParseAtom(package, symbol,
12365dfecf96Smrg			       collon == 2, unreadable,
12375dfecf96Smrg			       read__stream, read__line);
12385dfecf96Smrg    }
12395dfecf96Smrg
1240f14f4646Smrg    else if (quote == '|' || (unreadable && !collon)) {
1241f14f4646Smrg	/* Set unreadable field, this atom needs quoting to be read back */
1242f14f4646Smrg	object = ATOM(string);
1243f14f4646Smrg	object->data.atom->unreadable = 1;
1244f14f4646Smrg    }
1245f14f4646Smrg
12465dfecf96Smrg    /* Check some common symbols */
12475dfecf96Smrg    else if (length == 1 && string[0] == 'T')
12485dfecf96Smrg	/* The T */
12495dfecf96Smrg	object = T;
12505dfecf96Smrg
12515dfecf96Smrg    else if (length == 1 && string[0] == '.')
12525dfecf96Smrg	/* The dot */
12535dfecf96Smrg	object = DOT;
12545dfecf96Smrg
12555dfecf96Smrg    else if (length == 3 &&
12565dfecf96Smrg	     string[0] == 'N' && string[1] == 'I' && string[2] == 'L')
12575dfecf96Smrg	/* The NIL */
12585dfecf96Smrg	object = NIL;
12595dfecf96Smrg
12605dfecf96Smrg    else if (isdigit(string[0]) || string[0] == '.' ||
12615dfecf96Smrg	     ((string[0] == '-' || string[0] == '+') && string[1]))
12625dfecf96Smrg	/* Looks like a number */
12635dfecf96Smrg	object = LispParseNumber(string, 10, read__stream, read__line);
12645dfecf96Smrg
12655dfecf96Smrg    else
12665dfecf96Smrg	/* A normal atom */
12675dfecf96Smrg	object = ATOM(string);
12685dfecf96Smrg
12695dfecf96Smrg    if (string != stk)
12705dfecf96Smrg	LispFree(string);
12715dfecf96Smrg
12725dfecf96Smrg    return (object);
12735dfecf96Smrg}
12745dfecf96Smrg
12755dfecf96Smrgstatic LispObj *
12765dfecf96SmrgLispParseAtom(char *package, char *symbol, int intern, int unreadable,
12775dfecf96Smrg	      LispObj *read__stream, int read__line)
12785dfecf96Smrg{
12795dfecf96Smrg    LispObj *object = NULL, *thepackage = NULL;
12805dfecf96Smrg    LispPackage *pack = NULL;
12815dfecf96Smrg
12825dfecf96Smrg    if (!unreadable) {
12835dfecf96Smrg	/* Until NIL and T be treated as normal symbols */
12845dfecf96Smrg	if (symbol[0] == 'N' && symbol[1] == 'I' &&
12855dfecf96Smrg	    symbol[2] == 'L' && symbol[3] == '\0')
12865dfecf96Smrg	    return (NIL);
12875dfecf96Smrg	if (symbol[0] == 'T' && symbol[1] == '\0')
12885dfecf96Smrg	    return (T);
12895dfecf96Smrg	unreadable = !LispCheckAtomString(symbol);
12905dfecf96Smrg    }
12915dfecf96Smrg
12925dfecf96Smrg    /* If package is empty, it is a keyword */
12935dfecf96Smrg    if (package[0] == '\0') {
12945dfecf96Smrg	thepackage = lisp__data.keyword;
12955dfecf96Smrg	pack = lisp__data.key;
12965dfecf96Smrg    }
12975dfecf96Smrg
12985dfecf96Smrg    else {
12995dfecf96Smrg	/* Else, search it in the package list */
13005dfecf96Smrg	thepackage = LispFindPackageFromString(package);
13015dfecf96Smrg
13025dfecf96Smrg	if (thepackage == NIL)
13035dfecf96Smrg	    READ_ERROR1("the package %s is not available", package);
13045dfecf96Smrg
13055dfecf96Smrg	pack = thepackage->data.package.package;
13065dfecf96Smrg    }
13075dfecf96Smrg
13085dfecf96Smrg    if (pack == lisp__data.pack && intern) {
13095dfecf96Smrg	/* Redundant package specification, since requesting a
13105dfecf96Smrg	 * intern symbol, create it if does not exist */
13115dfecf96Smrg
13125dfecf96Smrg	object = ATOM(symbol);
13135dfecf96Smrg	if (unreadable)
13145dfecf96Smrg	    object->data.atom->unreadable = 1;
13155dfecf96Smrg    }
13165dfecf96Smrg
13175dfecf96Smrg    else if (intern || pack == lisp__data.key) {
13185dfecf96Smrg	/* Symbol is created, or just fetched from the specified package */
13195dfecf96Smrg
13205dfecf96Smrg	LispPackage *savepack;
13215dfecf96Smrg	LispObj *savepackage = PACKAGE;
13225dfecf96Smrg
13235dfecf96Smrg	/* Remember curent package */
13245dfecf96Smrg	savepack = lisp__data.pack;
13255dfecf96Smrg
13265dfecf96Smrg	/* Temporarily set another package */
13275dfecf96Smrg	lisp__data.pack = pack;
13285dfecf96Smrg	PACKAGE = thepackage;
13295dfecf96Smrg
13305dfecf96Smrg	/* Get the object pointer */
13315dfecf96Smrg	if (pack == lisp__data.key)
1332f14f4646Smrg	    object = KEYWORD(LispDoGetAtom(symbol, 0)->key->value);
13335dfecf96Smrg	else
13345dfecf96Smrg	    object = ATOM(symbol);
13355dfecf96Smrg	if (unreadable)
13365dfecf96Smrg	    object->data.atom->unreadable = 1;
13375dfecf96Smrg
13385dfecf96Smrg	/* Restore current package */
13395dfecf96Smrg	lisp__data.pack = savepack;
13405dfecf96Smrg	PACKAGE = savepackage;
13415dfecf96Smrg    }
13425dfecf96Smrg
13435dfecf96Smrg    else {
13445dfecf96Smrg	/* Symbol must exist (and be extern) in the specified package */
13455dfecf96Smrg
13465dfecf96Smrg	LispAtom *atom;
13475dfecf96Smrg
1348f14f4646Smrg	atom = (LispAtom *)hash_check(pack->atoms, symbol, strlen(symbol));
1349f14f4646Smrg	if (atom)
1350f14f4646Smrg	    object = atom->object;
13515dfecf96Smrg
13525dfecf96Smrg	/* No object found */
13535dfecf96Smrg	if (object == NULL || object->data.atom->ext == 0)
13545dfecf96Smrg	    READ_ERROR2("no extern symbol %s in package %s", symbol, package);
13555dfecf96Smrg    }
13565dfecf96Smrg
13575dfecf96Smrg    return (object);
13585dfecf96Smrg}
13595dfecf96Smrg
13605dfecf96Smrgstatic LispObj *
13615dfecf96SmrgLispParseNumber(char *str, int radix, LispObj *read__stream, int read__line)
13625dfecf96Smrg{
13635dfecf96Smrg    int len;
13645dfecf96Smrg    long integer;
13655dfecf96Smrg    double dfloat;
13665dfecf96Smrg    char *ratio, *ptr;
13675dfecf96Smrg    LispObj *number;
13685dfecf96Smrg    mpi *bignum;
13695dfecf96Smrg    mpr *bigratio;
13705dfecf96Smrg
13715dfecf96Smrg    if (radix < 2 || radix > 36)
13725dfecf96Smrg	READ_ERROR1("radix %d is not in the range 2 to 36", radix);
13735dfecf96Smrg
13745dfecf96Smrg    if (*str == '\0')
13755dfecf96Smrg	return (NULL);
13765dfecf96Smrg
13775dfecf96Smrg    ratio = strchr(str, '/');
13785dfecf96Smrg    if (ratio) {
13795dfecf96Smrg	/* check if looks like a correctly specified ratio */
13805dfecf96Smrg	if (ratio[1] == '\0' || strchr(ratio + 1, '/') != NULL)
13815dfecf96Smrg	    return (ATOM(str));
13825dfecf96Smrg
13835dfecf96Smrg	/* ratio must point to an integer in radix base */
13845dfecf96Smrg	*ratio++ = '\0';
13855dfecf96Smrg    }
13865dfecf96Smrg    else if (radix == 10) {
13875dfecf96Smrg	int dot = 0;
13885dfecf96Smrg	int type = 0;
13895dfecf96Smrg
13905dfecf96Smrg	/* check if it is a floating point number */
13915dfecf96Smrg	ptr = str;
13925dfecf96Smrg	if (*ptr == '-' || *ptr == '+')
13935dfecf96Smrg	    ++ptr;
13945dfecf96Smrg	else if (*ptr == '.') {
13955dfecf96Smrg	    dot = 1;
13965dfecf96Smrg	    ++ptr;
13975dfecf96Smrg	}
13985dfecf96Smrg	while (*ptr) {
13995dfecf96Smrg	    if (*ptr == '.') {
14005dfecf96Smrg		if (dot)
14015dfecf96Smrg		    return (ATOM(str));
14025dfecf96Smrg		/* ignore it if last char is a dot */
14035dfecf96Smrg		if (ptr[1] == '\0') {
14045dfecf96Smrg		    *ptr = '\0';
14055dfecf96Smrg		    break;
14065dfecf96Smrg		}
14075dfecf96Smrg		dot = 1;
14085dfecf96Smrg	    }
14095dfecf96Smrg	    else if (!isdigit(*ptr))
14105dfecf96Smrg		break;
14115dfecf96Smrg	    ++ptr;
14125dfecf96Smrg	}
14135dfecf96Smrg
14145dfecf96Smrg	switch (*ptr) {
14155dfecf96Smrg	    case '\0':
14165dfecf96Smrg		if (dot)		/* if dot, it is default float */
14175dfecf96Smrg		    type = 'E';
14185dfecf96Smrg		break;
14195dfecf96Smrg	    case 'E': case 'S': case 'F': case 'D': case 'L':
14205dfecf96Smrg		type = *ptr;
14215dfecf96Smrg		*ptr = 'E';
14225dfecf96Smrg		break;
14235dfecf96Smrg	    default:
14245dfecf96Smrg		return (ATOM(str));	/* syntax error */
14255dfecf96Smrg	}
14265dfecf96Smrg
14275dfecf96Smrg	/* if type set, it is not an integer specification */
14285dfecf96Smrg	if (type) {
14295dfecf96Smrg	    if (*ptr) {
14305dfecf96Smrg		int itype = *ptr;
14315dfecf96Smrg		char *ptype = ptr;
14325dfecf96Smrg
14335dfecf96Smrg		++ptr;
14345dfecf96Smrg		if (*ptr == '+' || *ptr == '-')
14355dfecf96Smrg		    ++ptr;
14365dfecf96Smrg		while (*ptr && isdigit(*ptr))
14375dfecf96Smrg		    ++ptr;
14385dfecf96Smrg		if (*ptr) {
14395dfecf96Smrg		    *ptype = itype;
14405dfecf96Smrg
14415dfecf96Smrg		    return (ATOM(str));
14425dfecf96Smrg		}
14435dfecf96Smrg	    }
14445dfecf96Smrg
14455dfecf96Smrg	    dfloat = strtod(str, NULL);
14465dfecf96Smrg	    if (!finite(dfloat))
14475dfecf96Smrg		READ_ERROR0("floating point overflow");
14485dfecf96Smrg
14495dfecf96Smrg	    return (DFLOAT(dfloat));
14505dfecf96Smrg	}
14515dfecf96Smrg    }
14525dfecf96Smrg
14535dfecf96Smrg    /* check if correctly specified in the given radix */
14545dfecf96Smrg    len = strlen(str) - 1;
14555dfecf96Smrg    if (!ratio && radix != 10 && str[len] == '.')
14565dfecf96Smrg	str[len] = '\0';
14575dfecf96Smrg
14585dfecf96Smrg    if (ratio || radix != 10) {
14595dfecf96Smrg	if (!StringInRadix(str, radix, 1)) {
14605dfecf96Smrg	    if (ratio)
14615dfecf96Smrg		ratio[-1] = '/';
14625dfecf96Smrg	    return (ATOM(str));
14635dfecf96Smrg	}
14645dfecf96Smrg	if (ratio && !StringInRadix(ratio, radix, 0)) {
14655dfecf96Smrg	    ratio[-1] = '/';
14665dfecf96Smrg	    return (ATOM(str));
14675dfecf96Smrg	}
14685dfecf96Smrg    }
14695dfecf96Smrg
14705dfecf96Smrg    bignum = NULL;
14715dfecf96Smrg    bigratio = NULL;
14725dfecf96Smrg
14735dfecf96Smrg    errno = 0;
14745dfecf96Smrg    integer = strtol(str, NULL, radix);
14755dfecf96Smrg
14765dfecf96Smrg    /* if does not fit in a long */
14775dfecf96Smrg    if (errno == ERANGE &&
14785dfecf96Smrg	((*str == '-' && integer == LONG_MIN) ||
14795dfecf96Smrg	 (*str != '-' && integer == LONG_MAX))) {
14805dfecf96Smrg	bignum = LispMalloc(sizeof(mpi));
14815dfecf96Smrg	mpi_init(bignum);
14825dfecf96Smrg	mpi_setstr(bignum, str, radix);
14835dfecf96Smrg    }
14845dfecf96Smrg
14855dfecf96Smrg
14865dfecf96Smrg    if (ratio && integer != 0) {
14875dfecf96Smrg	long denominator;
14885dfecf96Smrg
14895dfecf96Smrg	errno = 0;
14905dfecf96Smrg	denominator = strtol(ratio, NULL, radix);
14915dfecf96Smrg	if (denominator == 0)
14925dfecf96Smrg	    READ_ERROR0("divide by zero");
14935dfecf96Smrg
14945dfecf96Smrg	if (bignum == NULL) {
14955dfecf96Smrg	    if (integer == MINSLONG ||
14965dfecf96Smrg		(denominator == LONG_MAX && errno == ERANGE)) {
14975dfecf96Smrg		bigratio = LispMalloc(sizeof(mpr));
14985dfecf96Smrg		mpr_init(bigratio);
14995dfecf96Smrg		mpi_seti(mpr_num(bigratio), integer);
15005dfecf96Smrg		mpi_setstr(mpr_den(bigratio), ratio, radix);
15015dfecf96Smrg	    }
15025dfecf96Smrg	}
15035dfecf96Smrg	else {
15045dfecf96Smrg	    bigratio = LispMalloc(sizeof(mpr));
15055dfecf96Smrg	    mpr_init(bigratio);
15065dfecf96Smrg	    mpi_set(mpr_num(bigratio), bignum);
15075dfecf96Smrg	    mpi_clear(bignum);
15085dfecf96Smrg	    LispFree(bignum);
15095dfecf96Smrg	    mpi_setstr(mpr_den(bigratio), ratio, radix);
15105dfecf96Smrg	}
15115dfecf96Smrg
15125dfecf96Smrg	if (bigratio) {
15135dfecf96Smrg	    mpr_canonicalize(bigratio);
15145dfecf96Smrg	    if (mpi_fiti(mpr_num(bigratio)) &&
15155dfecf96Smrg		mpi_fiti(mpr_den(bigratio))) {
15165dfecf96Smrg		integer = mpi_geti(mpr_num(bigratio));
15175dfecf96Smrg		denominator = mpi_geti(mpr_den(bigratio));
15185dfecf96Smrg		mpr_clear(bigratio);
15195dfecf96Smrg		LispFree(bigratio);
15205dfecf96Smrg		if (denominator == 1)
15215dfecf96Smrg		    number = INTEGER(integer);
15225dfecf96Smrg		else
15235dfecf96Smrg		    number = RATIO(integer, denominator);
15245dfecf96Smrg	    }
15255dfecf96Smrg	    else
15265dfecf96Smrg		number = BIGRATIO(bigratio);
15275dfecf96Smrg	}
15285dfecf96Smrg	else {
15295dfecf96Smrg	    long num = integer, den = denominator, rest;
15305dfecf96Smrg
15315dfecf96Smrg	    if (num < 0)
15325dfecf96Smrg		num = -num;
15335dfecf96Smrg	    for (;;) {
15345dfecf96Smrg		if ((rest = den % num) == 0)
15355dfecf96Smrg		    break;
15365dfecf96Smrg		den = num;
15375dfecf96Smrg		num = rest;
15385dfecf96Smrg	    }
15395dfecf96Smrg	    if (den != 1) {
15405dfecf96Smrg		denominator /= num;
15415dfecf96Smrg		integer /= num;
15425dfecf96Smrg	    }
15435dfecf96Smrg	    if (denominator < 0) {
15445dfecf96Smrg		integer = -integer;
15455dfecf96Smrg		denominator = -denominator;
15465dfecf96Smrg	    }
15475dfecf96Smrg	    if (denominator == 1)
15485dfecf96Smrg		number = INTEGER(integer);
15495dfecf96Smrg	    else
15505dfecf96Smrg		number = RATIO(integer, denominator);
15515dfecf96Smrg	}
15525dfecf96Smrg    }
15535dfecf96Smrg    else if (bignum)
15545dfecf96Smrg	number = BIGNUM(bignum);
15555dfecf96Smrg    else
15565dfecf96Smrg	number = INTEGER(integer);
15575dfecf96Smrg
15585dfecf96Smrg    return (number);
15595dfecf96Smrg}
15605dfecf96Smrg
15615dfecf96Smrgstatic int
15625dfecf96SmrgStringInRadix(char *str, int radix, int skip_sign)
15635dfecf96Smrg{
15645dfecf96Smrg    if (skip_sign && (*str == '-' || *str == '+'))
15655dfecf96Smrg	++str;
15665dfecf96Smrg    while (*str) {
15675dfecf96Smrg	if (*str >= '0' && *str <= '9') {
15685dfecf96Smrg	    if (*str - '0' >= radix)
15695dfecf96Smrg		return (0);
15705dfecf96Smrg	}
15715dfecf96Smrg	else if (*str >= 'A' && *str <= 'Z') {
15725dfecf96Smrg	    if (radix <= 10 || *str - 'A' + 10 >= radix)
15735dfecf96Smrg		return (0);
15745dfecf96Smrg	}
15755dfecf96Smrg	else
15765dfecf96Smrg	    return (0);
15775dfecf96Smrg	str++;
15785dfecf96Smrg    }
15795dfecf96Smrg
15805dfecf96Smrg    return (1);
15815dfecf96Smrg}
15825dfecf96Smrg
15835dfecf96Smrgstatic int
15845dfecf96SmrgAtomSeparator(int ch, int check_space, int check_backslash)
15855dfecf96Smrg{
15865dfecf96Smrg    if (check_space && isspace(ch))
15875dfecf96Smrg	return (1);
15885dfecf96Smrg    if (check_backslash && ch == '\\')
15895dfecf96Smrg	return (1);
15905dfecf96Smrg    return (strchr("(),\";'`#|,", ch) != NULL);
15915dfecf96Smrg}
15925dfecf96Smrg
15935dfecf96Smrgstatic LispObj *
15945dfecf96SmrgLispReadVector(read_info *info)
15955dfecf96Smrg{
15965dfecf96Smrg    LispObj *objects;
15975dfecf96Smrg    int nodot = info->nodot;
15985dfecf96Smrg
15995dfecf96Smrg    info->nodot = info->level + 1;
16005dfecf96Smrg    objects = LispReadList(info);
16015dfecf96Smrg    info->nodot = nodot;
16025dfecf96Smrg
16035dfecf96Smrg    if (info->discard)
16045dfecf96Smrg	return (objects);
16055dfecf96Smrg
16065dfecf96Smrg    return (VECTOR(objects));
16075dfecf96Smrg}
16085dfecf96Smrg
16095dfecf96Smrgstatic LispObj *
16105dfecf96SmrgLispReadFunction(read_info *info)
16115dfecf96Smrg{
16125dfecf96Smrg    READ_ENTER();
16135dfecf96Smrg    int nodot = info->nodot;
16145dfecf96Smrg    LispObj *function;
16155dfecf96Smrg
16165dfecf96Smrg    info->nodot = info->level + 1;
16175dfecf96Smrg    function = LispDoRead(info);
16185dfecf96Smrg    info->nodot = nodot;
16195dfecf96Smrg
16205dfecf96Smrg    if (info->discard)
16215dfecf96Smrg	return (function);
16225dfecf96Smrg
16235dfecf96Smrg    if (INVALIDP(function))
16245dfecf96Smrg	READ_ERROR_INVARG();
16255dfecf96Smrg    else if (CONSP(function)) {
16265dfecf96Smrg	if (CAR(function) != Olambda)
16275dfecf96Smrg	    READ_ERROR_INVARG();
16285dfecf96Smrg
16295dfecf96Smrg	return (FUNCTION_QUOTE(function));
16305dfecf96Smrg    }
16315dfecf96Smrg    else if (!SYMBOLP(function))
16325dfecf96Smrg	READ_ERROR_INVARG();
16335dfecf96Smrg
16345dfecf96Smrg    return (FUNCTION_QUOTE(function));
16355dfecf96Smrg}
16365dfecf96Smrg
16375dfecf96Smrgstatic LispObj *
16385dfecf96SmrgLispReadRational(int radix, read_info *info)
16395dfecf96Smrg{
16405dfecf96Smrg    READ_ENTER();
16415dfecf96Smrg    LispObj *number;
16425dfecf96Smrg    int ch, len, size;
16435dfecf96Smrg    char stk[128], *str;
16445dfecf96Smrg
16455dfecf96Smrg    len = 0;
16465dfecf96Smrg    str = stk;
16475dfecf96Smrg    size = sizeof(stk);
16485dfecf96Smrg
16495dfecf96Smrg    for (;;) {
16505dfecf96Smrg	ch = LispGet();
16515dfecf96Smrg	if (ch == EOF || isspace(ch))
16525dfecf96Smrg	    break;
16535dfecf96Smrg	else if (AtomSeparator(ch, 0, 1)) {
16545dfecf96Smrg	    LispUnget(ch);
16555dfecf96Smrg	    break;
16565dfecf96Smrg	}
16575dfecf96Smrg	else if (islower(ch))
16585dfecf96Smrg	    ch = toupper(ch);
16595dfecf96Smrg	if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') &&
16605dfecf96Smrg	    ch != '+' && ch != '-' && ch != '/') {
16615dfecf96Smrg	    if (str != stk)
16625dfecf96Smrg		LispFree(str);
16635dfecf96Smrg	    if (!info->discard)
16645dfecf96Smrg		READ_ERROR1("bad character %c for rational number", ch);
16655dfecf96Smrg	}
16665dfecf96Smrg	if (len + 1 >= size) {
16675dfecf96Smrg	    if (str == stk) {
16685dfecf96Smrg		size = 512;
16695dfecf96Smrg		str = LispMalloc(size);
16705dfecf96Smrg		strcpy(str + 1, stk + 1);
16715dfecf96Smrg	    }
16725dfecf96Smrg	    else {
16735dfecf96Smrg		size += 512;
16745dfecf96Smrg		str = LispRealloc(str, size);
16755dfecf96Smrg	    }
16765dfecf96Smrg	}
16775dfecf96Smrg	str[len++] = ch;
16785dfecf96Smrg    }
16795dfecf96Smrg
16805dfecf96Smrg    if (info->discard) {
16815dfecf96Smrg	if (str != stk)
16825dfecf96Smrg	    LispFree(str);
16835dfecf96Smrg
16845dfecf96Smrg	return (ch == EOF ? NULL : NIL);
16855dfecf96Smrg    }
16865dfecf96Smrg
16875dfecf96Smrg    str[len] = '\0';
16885dfecf96Smrg
16895dfecf96Smrg    number = LispParseNumber(str, radix, read__stream, read__line);
16905dfecf96Smrg    if (str != stk)
16915dfecf96Smrg	LispFree(str);
16925dfecf96Smrg
16935dfecf96Smrg    if (!RATIONALP(number))
16945dfecf96Smrg	READ_ERROR0("bad rational number specification");
16955dfecf96Smrg
16965dfecf96Smrg    return (number);
16975dfecf96Smrg}
16985dfecf96Smrg
16995dfecf96Smrgstatic LispObj *
17005dfecf96SmrgLispReadCharacter(read_info *info)
17015dfecf96Smrg{
17025dfecf96Smrg    READ_ENTER();
17035dfecf96Smrg    long c;
17045dfecf96Smrg    int ch, len;
17055dfecf96Smrg    char stk[64];
17065dfecf96Smrg
17075dfecf96Smrg    ch = LispGet();
17085dfecf96Smrg    if (ch == EOF)
17095dfecf96Smrg	return (NULL);
17105dfecf96Smrg
17115dfecf96Smrg    stk[0] = ch;
17125dfecf96Smrg    len = 1;
17135dfecf96Smrg
17145dfecf96Smrg    for (;;) {
17155dfecf96Smrg	ch = LispGet();
17165dfecf96Smrg	if (ch == EOF)
17175dfecf96Smrg	    break;
17185dfecf96Smrg	else if (ch != '-' && !isalnum(ch)) {
17195dfecf96Smrg	    LispUnget(ch);
17205dfecf96Smrg	    break;
17215dfecf96Smrg	}
17225dfecf96Smrg	if (len + 1 < sizeof(stk))
17235dfecf96Smrg	    stk[len++] = ch;
17245dfecf96Smrg    }
17255dfecf96Smrg    if (len > 1) {
17265dfecf96Smrg	char **names;
17275dfecf96Smrg	int found = 0;
17285dfecf96Smrg	stk[len] = '\0';
17295dfecf96Smrg
17305dfecf96Smrg	for (c = ch = 0; ch <= ' ' && !found; ch++) {
17315dfecf96Smrg	    for (names = LispChars[ch].names; *names; names++)
17325dfecf96Smrg		if (strcasecmp(*names, stk) == 0) {
17335dfecf96Smrg		    c = ch;
17345dfecf96Smrg		    found = 1;
17355dfecf96Smrg		    break;
17365dfecf96Smrg		}
17375dfecf96Smrg	}
17385dfecf96Smrg	if (!found) {
17395dfecf96Smrg	    for (names = LispChars[0177].names; *names; names++)
17405dfecf96Smrg		if (strcasecmp(*names, stk) == 0) {
17415dfecf96Smrg		    c = 0177;
17425dfecf96Smrg		    found = 1;
17435dfecf96Smrg		    break;
17445dfecf96Smrg		}
17455dfecf96Smrg	}
17465dfecf96Smrg
17475dfecf96Smrg	if (!found) {
17485dfecf96Smrg	    if (info->discard)
17495dfecf96Smrg		return (NIL);
17505dfecf96Smrg	    READ_ERROR1("unkwnown character %s", stk);
17515dfecf96Smrg	}
17525dfecf96Smrg    }
17535dfecf96Smrg    else
17545dfecf96Smrg	c = stk[0];
17555dfecf96Smrg
17565dfecf96Smrg    return (SCHAR(c));
17575dfecf96Smrg}
17585dfecf96Smrg
17595dfecf96Smrgstatic void
17605dfecf96SmrgLispSkipComment(void)
17615dfecf96Smrg{
17625dfecf96Smrg    READ_ENTER();
17635dfecf96Smrg    int ch, comm = 1;
17645dfecf96Smrg
17655dfecf96Smrg    for (;;) {
17665dfecf96Smrg	ch = LispGet();
17675dfecf96Smrg	if (ch == '#') {
17685dfecf96Smrg	    ch = LispGet();
17695dfecf96Smrg	    if (ch == '|')
17705dfecf96Smrg		++comm;
17715dfecf96Smrg	    continue;
17725dfecf96Smrg	}
17735dfecf96Smrg	while (ch == '|') {
17745dfecf96Smrg	    ch = LispGet();
17755dfecf96Smrg	    if (ch == '#' && --comm == 0)
17765dfecf96Smrg		return;
17775dfecf96Smrg	}
17785dfecf96Smrg	if (ch == EOF)
17795dfecf96Smrg	    READ_ERROR_EOF();
17805dfecf96Smrg    }
17815dfecf96Smrg}
17825dfecf96Smrg
17835dfecf96Smrgstatic LispObj *
17845dfecf96SmrgLispReadEval(read_info *info)
17855dfecf96Smrg{
17865dfecf96Smrg    READ_ENTER();
17875dfecf96Smrg    int nodot = info->nodot;
17885dfecf96Smrg    LispObj *code;
17895dfecf96Smrg
17905dfecf96Smrg    info->nodot = info->level + 1;
17915dfecf96Smrg    code = LispDoRead(info);
17925dfecf96Smrg    info->nodot = nodot;
17935dfecf96Smrg
17945dfecf96Smrg    if (info->discard)
17955dfecf96Smrg	return (code);
17965dfecf96Smrg
17975dfecf96Smrg    if (INVALIDP(code))
17985dfecf96Smrg	READ_ERROR_INVARG();
17995dfecf96Smrg
18005dfecf96Smrg    return (EVAL(code));
18015dfecf96Smrg}
18025dfecf96Smrg
18035dfecf96Smrgstatic LispObj *
18045dfecf96SmrgLispReadComplex(read_info *info)
18055dfecf96Smrg{
18065dfecf96Smrg    READ_ENTER();
18075dfecf96Smrg    GC_ENTER();
18085dfecf96Smrg    int nodot = info->nodot;
18095dfecf96Smrg    LispObj *number, *arguments;
18105dfecf96Smrg
18115dfecf96Smrg    info->nodot = info->level + 1;
18125dfecf96Smrg    arguments = LispDoRead(info);
18135dfecf96Smrg    info->nodot = nodot;
18145dfecf96Smrg
18155dfecf96Smrg    /* form read */
18165dfecf96Smrg    if (info->discard)
18175dfecf96Smrg	return (arguments);
18185dfecf96Smrg
18195dfecf96Smrg    if (INVALIDP(arguments) || !CONSP(arguments))
18205dfecf96Smrg	READ_ERROR_INVARG();
18215dfecf96Smrg
18225dfecf96Smrg    GC_PROTECT(arguments);
18235dfecf96Smrg    number = APPLY(Ocomplex, arguments);
18245dfecf96Smrg    GC_LEAVE();
18255dfecf96Smrg
18265dfecf96Smrg    return (number);
18275dfecf96Smrg}
18285dfecf96Smrg
18295dfecf96Smrgstatic LispObj *
18305dfecf96SmrgLispReadPathname(read_info *info)
18315dfecf96Smrg{
18325dfecf96Smrg    READ_ENTER();
18335dfecf96Smrg    GC_ENTER();
18345dfecf96Smrg    int nodot = info->nodot;
18355dfecf96Smrg    LispObj *path, *arguments;
18365dfecf96Smrg
18375dfecf96Smrg    info->nodot = info->level + 1;
18385dfecf96Smrg    arguments = LispDoRead(info);
18395dfecf96Smrg    info->nodot = nodot;
18405dfecf96Smrg
18415dfecf96Smrg    /* form read */
18425dfecf96Smrg    if (info->discard)
18435dfecf96Smrg	return (arguments);
18445dfecf96Smrg
18455dfecf96Smrg    if (INVALIDP(arguments))
18465dfecf96Smrg	READ_ERROR_INVARG();
18475dfecf96Smrg
18485dfecf96Smrg    GC_PROTECT(arguments);
18495dfecf96Smrg    path = APPLY1(Oparse_namestring, arguments);
18505dfecf96Smrg    GC_LEAVE();
18515dfecf96Smrg
18525dfecf96Smrg    return (path);
18535dfecf96Smrg}
18545dfecf96Smrg
18555dfecf96Smrgstatic LispObj *
18565dfecf96SmrgLispReadStruct(read_info *info)
18575dfecf96Smrg{
18585dfecf96Smrg    READ_ENTER();
18595dfecf96Smrg    GC_ENTER();
18605dfecf96Smrg    int len, nodot = info->nodot;
18615dfecf96Smrg    char stk[128], *str;
18625dfecf96Smrg    LispObj *struc, *fields;
18635dfecf96Smrg
18645dfecf96Smrg    info->nodot = info->level + 1;
18655dfecf96Smrg    fields = LispDoRead(info);
18665dfecf96Smrg    info->nodot = nodot;
18675dfecf96Smrg
18685dfecf96Smrg    /* form read */
18695dfecf96Smrg    if (info->discard)
18705dfecf96Smrg	return (fields);
18715dfecf96Smrg
18725dfecf96Smrg    if (INVALIDP(fields) || !CONSP(fields) || !SYMBOLP(CAR(fields)))
18735dfecf96Smrg	READ_ERROR_INVARG();
18745dfecf96Smrg
18755dfecf96Smrg    GC_PROTECT(fields);
18765dfecf96Smrg
1877f14f4646Smrg    len = ATOMID(CAR(fields))->length;
18785dfecf96Smrg	   /* MAKE- */
18795dfecf96Smrg    if (len + 6 > sizeof(stk))
18805dfecf96Smrg	str = LispMalloc(len + 6);
18815dfecf96Smrg    else
18825dfecf96Smrg	str = stk;
1883f14f4646Smrg    sprintf(str, "MAKE-%s", ATOMID(CAR(fields))->value);
18845dfecf96Smrg    RPLACA(fields, ATOM(str));
18855dfecf96Smrg    if (str != stk)
18865dfecf96Smrg	LispFree(str);
18875dfecf96Smrg    struc = APPLY(Omake_struct, fields);
18885dfecf96Smrg    GC_LEAVE();
18895dfecf96Smrg
18905dfecf96Smrg    return (struc);
18915dfecf96Smrg}
18925dfecf96Smrg
18935dfecf96Smrg/* XXX This is broken, needs a rewritten as soon as true vector/arrays be
18945dfecf96Smrg * implemented. */
18955dfecf96Smrgstatic LispObj *
18965dfecf96SmrgLispReadArray(long dimensions, read_info *info)
18975dfecf96Smrg{
18985dfecf96Smrg    READ_ENTER();
18995dfecf96Smrg    GC_ENTER();
19005dfecf96Smrg    long count;
19015dfecf96Smrg    int nodot = info->nodot;
19025dfecf96Smrg    LispObj *arguments, *initial, *dim, *cons, *array, *data;
19035dfecf96Smrg
19045dfecf96Smrg    info->nodot = info->level + 1;
19055dfecf96Smrg    data = LispDoRead(info);
19065dfecf96Smrg    info->nodot = nodot;
19075dfecf96Smrg
19085dfecf96Smrg    /* form read */
19095dfecf96Smrg    if (info->discard)
19105dfecf96Smrg	return (data);
19115dfecf96Smrg
19125dfecf96Smrg    if (INVALIDP(data))
19135dfecf96Smrg	READ_ERROR_INVARG();
19145dfecf96Smrg
19155dfecf96Smrg    initial = Kinitial_contents;
19165dfecf96Smrg
19175dfecf96Smrg    dim = cons = NIL;
19185dfecf96Smrg    if (dimensions) {
19195dfecf96Smrg	LispObj *array;
19205dfecf96Smrg
19215dfecf96Smrg	for (count = 0, array = data; count < dimensions; count++) {
19225dfecf96Smrg	    long length;
19235dfecf96Smrg	    LispObj *item;
19245dfecf96Smrg
19255dfecf96Smrg	    if (!CONSP(array))
19265dfecf96Smrg		READ_ERROR0("bad array for given dimension");
19275dfecf96Smrg	    item = array;
19285dfecf96Smrg	    array = CAR(array);
19295dfecf96Smrg
19305dfecf96Smrg	    for (length = 0; CONSP(item); item = CDR(item), length++)
19315dfecf96Smrg		;
19325dfecf96Smrg
19335dfecf96Smrg	    if (dim == NIL) {
19345dfecf96Smrg		dim = cons = CONS(FIXNUM(length), NIL);
19355dfecf96Smrg		GC_PROTECT(dim);
19365dfecf96Smrg	    }
19375dfecf96Smrg	    else {
19385dfecf96Smrg		RPLACD(cons, CONS(FIXNUM(length), NIL));
19395dfecf96Smrg		cons = CDR(cons);
19405dfecf96Smrg	    }
19415dfecf96Smrg	}
19425dfecf96Smrg    }
19435dfecf96Smrg
19445dfecf96Smrg    arguments = CONS(dim, CONS(initial, CONS(data, NIL)));
19455dfecf96Smrg    GC_PROTECT(arguments);
19465dfecf96Smrg    array = APPLY(Omake_array, arguments);
19475dfecf96Smrg    GC_LEAVE();
19485dfecf96Smrg
19495dfecf96Smrg    return (array);
19505dfecf96Smrg}
19515dfecf96Smrg
19525dfecf96Smrgstatic LispObj *
19535dfecf96SmrgLispReadFeature(int with, read_info *info)
19545dfecf96Smrg{
19555dfecf96Smrg    READ_ENTER();
19565dfecf96Smrg    LispObj *status;
19575dfecf96Smrg    LispObj *feature = LispDoRead(info);
19585dfecf96Smrg
19595dfecf96Smrg    /* form read */
19605dfecf96Smrg    if (info->discard)
19615dfecf96Smrg	return (feature);
19625dfecf96Smrg
19635dfecf96Smrg    if (INVALIDP(feature))
19645dfecf96Smrg	READ_ERROR_INVARG();
19655dfecf96Smrg
19665dfecf96Smrg    /* paranoia check, features must be a list, possibly empty */
19675dfecf96Smrg    if (!CONSP(FEATURES) && FEATURES != NIL)
19685dfecf96Smrg	READ_ERROR1("%s is not a list", STROBJ(FEATURES));
19695dfecf96Smrg
19705dfecf96Smrg    status = LispEvalFeature(feature);
19715dfecf96Smrg
19725dfecf96Smrg    if (with) {
19735dfecf96Smrg	if (status == T)
19745dfecf96Smrg	    return (LispDoRead(info));
19755dfecf96Smrg
19765dfecf96Smrg	/* need to use the field discard because the following expression
19775dfecf96Smrg	 * may be #.FORM or #,FORM or any other form that may generate
19785dfecf96Smrg	 * side effects */
19795dfecf96Smrg	info->discard = 1;
19805dfecf96Smrg	LispDoRead(info);
19815dfecf96Smrg	info->discard = 0;
19825dfecf96Smrg
19835dfecf96Smrg	return (LispDoRead(info));
19845dfecf96Smrg    }
19855dfecf96Smrg
19865dfecf96Smrg    if (status == NIL)
19875dfecf96Smrg	return (LispDoRead(info));
19885dfecf96Smrg
19895dfecf96Smrg    info->discard = 1;
19905dfecf96Smrg    LispDoRead(info);
19915dfecf96Smrg    info->discard = 0;
19925dfecf96Smrg
19935dfecf96Smrg    return (LispDoRead(info));
19945dfecf96Smrg}
19955dfecf96Smrg
19965dfecf96Smrg/*
19975dfecf96Smrg * A very simple eval loop with AND, NOT, and OR functions for testing
19985dfecf96Smrg * the available features.
19995dfecf96Smrg */
20005dfecf96Smrgstatic LispObj *
20015dfecf96SmrgLispEvalFeature(LispObj *feature)
20025dfecf96Smrg{
20035dfecf96Smrg    READ_ENTER();
20045dfecf96Smrg    Atom_id test;
20055dfecf96Smrg    LispObj *object;
20065dfecf96Smrg
20075dfecf96Smrg    if (CONSP(feature)) {
20085dfecf96Smrg	LispObj *function = CAR(feature), *arguments = CDR(feature);
20095dfecf96Smrg
20105dfecf96Smrg	if (!SYMBOLP(function))
20115dfecf96Smrg	    READ_ERROR1("bad feature test function %s", STROBJ(function));
20125dfecf96Smrg	if (!CONSP(arguments))
20135dfecf96Smrg	    READ_ERROR1("bad feature test arguments %s", STROBJ(arguments));
20145dfecf96Smrg	test = ATOMID(function);
20155dfecf96Smrg	if (test == Sand) {
20165dfecf96Smrg	    for (; CONSP(arguments); arguments = CDR(arguments)) {
20175dfecf96Smrg		if (LispEvalFeature(CAR(arguments)) == NIL)
20185dfecf96Smrg		    return (NIL);
20195dfecf96Smrg	    }
20205dfecf96Smrg	    return (T);
20215dfecf96Smrg	}
20225dfecf96Smrg	else if (test == Sor) {
20235dfecf96Smrg	    for (; CONSP(arguments); arguments = CDR(arguments)) {
20245dfecf96Smrg		if (LispEvalFeature(CAR(arguments)) == T)
20255dfecf96Smrg		    return (T);
20265dfecf96Smrg	    }
20275dfecf96Smrg	    return (NIL);
20285dfecf96Smrg	}
20295dfecf96Smrg	else if (test == Snot) {
20305dfecf96Smrg	    if (CONSP(CDR(arguments)))
20315dfecf96Smrg		READ_ERROR0("too many arguments to NOT");
20325dfecf96Smrg
20335dfecf96Smrg	    return (LispEvalFeature(CAR(arguments)) == NIL ? T : NIL);
20345dfecf96Smrg	}
20355dfecf96Smrg	else
20365dfecf96Smrg	    READ_ERROR1("unimplemented feature test function %s", test);
20375dfecf96Smrg    }
20385dfecf96Smrg
20395dfecf96Smrg    if (KEYWORDP(feature))
20405dfecf96Smrg	feature = feature->data.quote;
20415dfecf96Smrg    else if (!SYMBOLP(feature))
20425dfecf96Smrg	READ_ERROR1("bad feature specification %s", STROBJ(feature));
20435dfecf96Smrg
20445dfecf96Smrg    test = ATOMID(feature);
20455dfecf96Smrg
20465dfecf96Smrg    for (object = FEATURES; CONSP(object); object = CDR(object)) {
20475dfecf96Smrg	/* paranoia check, elements in the feature list must ge keywords */
20485dfecf96Smrg	if (!KEYWORDP(CAR(object)))
20495dfecf96Smrg	    READ_ERROR1("%s is not a keyword", STROBJ(CAR(object)));
20505dfecf96Smrg	if (ATOMID(CAR(object)) == test)
20515dfecf96Smrg	    return (T);
20525dfecf96Smrg    }
20535dfecf96Smrg
20545dfecf96Smrg    /* unknown feature */
20555dfecf96Smrg    return (NIL);
20565dfecf96Smrg}
2057