read.c revision f765521f
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
109f765521fSmrgstatic void LispReadError(LispObj*, int, const 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 */
143f765521fSmrgstatic const char * const Char_Nul[] = {"Null", "Nul", NULL};
144f765521fSmrgstatic const char * const Char_Soh[] = {"Soh", NULL};
145f765521fSmrgstatic const char * const Char_Stx[] = {"Stx", NULL};
146f765521fSmrgstatic const char * const Char_Etx[] = {"Etx", NULL};
147f765521fSmrgstatic const char * const Char_Eot[] = {"Eot", NULL};
148f765521fSmrgstatic const char * const Char_Enq[] = {"Enq", NULL};
149f765521fSmrgstatic const char * const Char_Ack[] = {"Ack", NULL};
150f765521fSmrgstatic const char * const Char_Bel[] = {"Bell", "Bel", NULL};
151f765521fSmrgstatic const char * const Char_Bs[]  = {"Backspace", "Bs", NULL};
152f765521fSmrgstatic const char * const Char_Tab[] = {"Tab", NULL};
153f765521fSmrgstatic const char * const Char_Nl[]  = {"Newline", "Nl", "Lf", "Linefeed", NULL};
154f765521fSmrgstatic const char * const Char_Vt[]  = {"Vt", NULL};
155f765521fSmrgstatic const char * const Char_Np[]  = {"Page", "Np", NULL};
156f765521fSmrgstatic const char * const Char_Cr[]  = {"Return", "Cr", NULL};
157f765521fSmrgstatic const char * const Char_Ff[]  = {"So", "Ff", NULL};
158f765521fSmrgstatic const char * const Char_Si[]  = {"Si", NULL};
159f765521fSmrgstatic const char * const Char_Dle[] = {"Dle", NULL};
160f765521fSmrgstatic const char * const Char_Dc1[] = {"Dc1", NULL};
161f765521fSmrgstatic const char * const Char_Dc2[] = {"Dc2", NULL};
162f765521fSmrgstatic const char * const Char_Dc3[] = {"Dc3", NULL};
163f765521fSmrgstatic const char * const Char_Dc4[] = {"Dc4", NULL};
164f765521fSmrgstatic const char * const Char_Nak[] = {"Nak", NULL};
165f765521fSmrgstatic const char * const Char_Syn[] = {"Syn", NULL};
166f765521fSmrgstatic const char * const Char_Etb[] = {"Etb", NULL};
167f765521fSmrgstatic const char * const Char_Can[] = {"Can", NULL};
168f765521fSmrgstatic const char * const Char_Em[]  = {"Em", NULL};
169f765521fSmrgstatic const char * const Char_Sub[] = {"Sub", NULL};
170f765521fSmrgstatic const char * const Char_Esc[] = {"Escape", "Esc", NULL};
171f765521fSmrgstatic const char * const Char_Fs[]  = {"Fs", NULL};
172f765521fSmrgstatic const char * const Char_Gs[]  = {"Gs", NULL};
173f765521fSmrgstatic const char * const Char_Rs[]  = {"Rs", NULL};
174f765521fSmrgstatic const char * const Char_Us[]  = {"Us", NULL};
175f765521fSmrgstatic const char * const Char_Sp[]  = {"Space", "Sp", NULL};
176f765521fSmrgstatic const char * const Char_Del[] = {"Rubout", "Del", "Delete", NULL};
177f765521fSmrg
178f765521fSmrgconst LispCharInfo 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
600f765521fSmrgLispReadError(LispObj *stream, int line, const char *fmt, ...)
6015dfecf96Smrg{
602f765521fSmrg    char string[128];
603f765521fSmrg    const char *buffer_string;
6045dfecf96Smrg    LispObj *buffer = LSTRINGSTREAM("", STREAM_READ | STREAM_WRITE, 0);
6055dfecf96Smrg    int length;
6065dfecf96Smrg    va_list ap;
6075dfecf96Smrg
6085dfecf96Smrg    va_start(ap, fmt);
6095dfecf96Smrg    vsnprintf(string, sizeof(string), fmt, ap);
6105dfecf96Smrg    va_end(ap);
6115dfecf96Smrg
6125dfecf96Smrg    LispFwrite(Stderr, "*** Reading ", 12);
6135dfecf96Smrg    LispWriteObject(buffer, stream);
6145dfecf96Smrg    buffer_string = LispGetSstring(SSTREAMP(buffer), &length);
6155dfecf96Smrg    LispFwrite(Stderr, buffer_string, length);
6165dfecf96Smrg    LispFwrite(Stderr, " at line ", 9);
6175dfecf96Smrg    if (line < 0)
6185dfecf96Smrg	LispFwrite(Stderr, "?\n", 2);
6195dfecf96Smrg    else {
6205dfecf96Smrg	char str[32];
6215dfecf96Smrg
6225dfecf96Smrg	sprintf(str, "%d\n", line);
6235dfecf96Smrg	LispFputs(Stderr, str);
6245dfecf96Smrg    }
6255dfecf96Smrg
6265dfecf96Smrg    LispDestroy("READ: %s", string);
6275dfecf96Smrg}
6285dfecf96Smrg
6295dfecf96Smrgstatic void
6305dfecf96SmrgLispReadFixCircle(LispObj *object, read_info *info)
6315dfecf96Smrg{
6325dfecf96Smrg    LispObj *cons;
6335dfecf96Smrg
6345dfecf96Smrgfix_again:
6355dfecf96Smrg    switch (OBJECT_TYPE(object)) {
6365dfecf96Smrg	case LispCons_t:
6375dfecf96Smrg	    for (cons = object;
6385dfecf96Smrg		 CONSP(object);
6395dfecf96Smrg		 cons = object, object = CDR(object)) {
6405dfecf96Smrg		if (READLABELP(CAR(object)))
6415dfecf96Smrg		    CAR(object) = LispReadLabelCircle(CAR(object), info);
6425dfecf96Smrg		else if (LispReadCheckCircle(object, info))
6435dfecf96Smrg		    return;
6445dfecf96Smrg		else
6455dfecf96Smrg		    LispReadFixCircle(CAR(object), info);
6465dfecf96Smrg	    }
6475dfecf96Smrg	    if (READLABELP(object))
6485dfecf96Smrg		CDR(cons) = LispReadLabelCircle(object, info);
6495dfecf96Smrg	    else
6505dfecf96Smrg		goto fix_again;
6515dfecf96Smrg	    break;
6525dfecf96Smrg	case LispArray_t:
6535dfecf96Smrg	    if (READLABELP(object->data.array.list))
6545dfecf96Smrg		object->data.array.list =
6555dfecf96Smrg		    LispReadLabelCircle(object->data.array.list, info);
6565dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6575dfecf96Smrg		object = object->data.array.list;
6585dfecf96Smrg		goto fix_again;
6595dfecf96Smrg	    }
6605dfecf96Smrg	    break;
6615dfecf96Smrg	case LispStruct_t:
6625dfecf96Smrg	    if (READLABELP(object->data.struc.fields))
6635dfecf96Smrg		object->data.struc.fields =
6645dfecf96Smrg		    LispReadLabelCircle(object->data.struc.fields, info);
6655dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6665dfecf96Smrg		object = object->data.struc.fields;
6675dfecf96Smrg		goto fix_again;
6685dfecf96Smrg	    }
6695dfecf96Smrg	    break;
6705dfecf96Smrg	case LispQuote_t:
6715dfecf96Smrg	case LispBackquote_t:
6725dfecf96Smrg	case LispFunctionQuote_t:
6735dfecf96Smrg	    if (READLABELP(object->data.quote))
6745dfecf96Smrg		object->data.quote =
6755dfecf96Smrg		    LispReadLabelCircle(object->data.quote, info);
6765dfecf96Smrg	    else {
6775dfecf96Smrg		object = object->data.quote;
6785dfecf96Smrg		goto fix_again;
6795dfecf96Smrg	    }
6805dfecf96Smrg	    break;
6815dfecf96Smrg	case LispComma_t:
6825dfecf96Smrg	    if (READLABELP(object->data.comma.eval))
6835dfecf96Smrg		object->data.comma.eval =
6845dfecf96Smrg		    LispReadLabelCircle(object->data.comma.eval, info);
6855dfecf96Smrg	    else {
6865dfecf96Smrg		object = object->data.comma.eval;
6875dfecf96Smrg		goto fix_again;
6885dfecf96Smrg	    }
6895dfecf96Smrg	    break;
6905dfecf96Smrg	case LispLambda_t:
6915dfecf96Smrg	    if (READLABELP(object->data.lambda.code))
6925dfecf96Smrg		object->data.lambda.code =
6935dfecf96Smrg		    LispReadLabelCircle(object->data.lambda.code, info);
6945dfecf96Smrg	    else if (!LispReadCheckCircle(object, info)) {
6955dfecf96Smrg		object = object->data.lambda.code;
6965dfecf96Smrg		goto fix_again;
6975dfecf96Smrg	    }
6985dfecf96Smrg	    break;
6995dfecf96Smrg	default:
7005dfecf96Smrg	    break;
7015dfecf96Smrg    }
7025dfecf96Smrg}
7035dfecf96Smrg
7045dfecf96Smrgstatic LispObj *
7055dfecf96SmrgLispReadLabelCircle(LispObj *label, read_info *info)
7065dfecf96Smrg{
7075dfecf96Smrg    long i, value = READLABEL_VALUE(label);
7085dfecf96Smrg
7095dfecf96Smrg    for (i = 0; i < info->num_objects; i++)
7105dfecf96Smrg	if (info->objects[i].label == value)
7115dfecf96Smrg	    return (info->objects[i].object);
7125dfecf96Smrg
7135dfecf96Smrg    LispDestroy("READ: internal error");
7145dfecf96Smrg    /*NOTREACHED*/
7155dfecf96Smrg    return (label);
7165dfecf96Smrg}
7175dfecf96Smrg
7185dfecf96Smrgstatic int
7195dfecf96SmrgLispReadCheckCircle(LispObj *object, read_info *info)
7205dfecf96Smrg{
7215dfecf96Smrg    long i;
7225dfecf96Smrg
7235dfecf96Smrg    for (i = 0; i < info->num_circles; i++)
7245dfecf96Smrg	if (info->circles[i] == object)
7255dfecf96Smrg	    return (1);
7265dfecf96Smrg
7275dfecf96Smrg    if ((info->num_circles % 16) == 0)
7285dfecf96Smrg	info->circles = LispRealloc(info->circles, sizeof(LispObj*) *
7295dfecf96Smrg				    (info->num_circles + 16));
7305dfecf96Smrg    info->circles[info->num_circles++] = object;
7315dfecf96Smrg
7325dfecf96Smrg    return (0);
7335dfecf96Smrg}
7345dfecf96Smrg
7355dfecf96Smrgstatic LispObj *
7365dfecf96SmrgLispDoRead(read_info *info)
7375dfecf96Smrg{
7385dfecf96Smrg    LispObj *object;
7395dfecf96Smrg    int ch = LispSkipWhiteSpace();
7405dfecf96Smrg
7415dfecf96Smrg    switch (ch) {
7425dfecf96Smrg	case '(':
7435dfecf96Smrg	    object = LispReadList(info);
7445dfecf96Smrg	    break;
7455dfecf96Smrg	case ')':
7465dfecf96Smrg	    for (ch = LispGet(); ch != EOF && ch != '\n'; ch = LispGet()) {
7475dfecf96Smrg		if (!isspace(ch)) {
7485dfecf96Smrg		    LispUnget(ch);
7495dfecf96Smrg		    break;
7505dfecf96Smrg		}
7515dfecf96Smrg	    }
7525dfecf96Smrg	    return (EOLIST);
7535dfecf96Smrg	case EOF:
7545dfecf96Smrg	    return (NULL);
7555dfecf96Smrg	case '\'':
7565dfecf96Smrg	    object = LispReadQuote(info);
7575dfecf96Smrg	    break;
7585dfecf96Smrg	case '`':
7595dfecf96Smrg	    object = LispReadBackquote(info);
7605dfecf96Smrg	    break;
7615dfecf96Smrg	case ',':
7625dfecf96Smrg	    object = LispReadCommaquote(info);
7635dfecf96Smrg	    break;
7645dfecf96Smrg	case '#':
7655dfecf96Smrg	    object = LispReadMacro(info);
7665dfecf96Smrg	    break;
7675dfecf96Smrg	default:
7685dfecf96Smrg	    LispUnget(ch);
7695dfecf96Smrg	    object = LispReadObject(0, info);
7705dfecf96Smrg	    break;
7715dfecf96Smrg    }
7725dfecf96Smrg
7735dfecf96Smrg    return (object);
7745dfecf96Smrg}
7755dfecf96Smrg
7765dfecf96Smrgstatic LispObj *
7775dfecf96SmrgLispReadMacro(read_info *info)
7785dfecf96Smrg{
7795dfecf96Smrg    READ_ENTER();
7805dfecf96Smrg    LispObj *result = NULL;
7815dfecf96Smrg    int ch = LispGet();
7825dfecf96Smrg
7835dfecf96Smrg    switch (ch) {
7845dfecf96Smrg	case '(':
7855dfecf96Smrg	    result = LispReadVector(info);
7865dfecf96Smrg	    break;
7875dfecf96Smrg	case '\'':
7885dfecf96Smrg	   result = LispReadFunction(info);
7895dfecf96Smrg	   break;
7905dfecf96Smrg	case 'b':
7915dfecf96Smrg	case 'B':
7925dfecf96Smrg	    result = LispReadRational(2, info);
7935dfecf96Smrg	    break;
7945dfecf96Smrg	case 'o':
7955dfecf96Smrg	case 'O':
7965dfecf96Smrg	    result = LispReadRational(8, info);
7975dfecf96Smrg	    break;
7985dfecf96Smrg	case 'x':
7995dfecf96Smrg	case 'X':
8005dfecf96Smrg	    result = LispReadRational(16, info);
8015dfecf96Smrg	    break;
8025dfecf96Smrg	case '\\':
8035dfecf96Smrg	    result = LispReadCharacter(info);
8045dfecf96Smrg	    break;
8055dfecf96Smrg	case '|':
8065dfecf96Smrg	    LispSkipComment();
8075dfecf96Smrg	    result = LispDoRead(info);
8085dfecf96Smrg	    break;
8095dfecf96Smrg	case '.':	/* eval when compiling */
8105dfecf96Smrg	case ',':	/* eval when loading */
8115dfecf96Smrg	    result = LispReadEval(info);
8125dfecf96Smrg	    break;
8135dfecf96Smrg	case 'c':
8145dfecf96Smrg	case 'C':
8155dfecf96Smrg	    result = LispReadComplex(info);
8165dfecf96Smrg	    break;
8175dfecf96Smrg	case 'p':
8185dfecf96Smrg	case 'P':
8195dfecf96Smrg	    result = LispReadPathname(info);
8205dfecf96Smrg	    break;
8215dfecf96Smrg	case 's':
8225dfecf96Smrg	case 'S':
8235dfecf96Smrg	    result = LispReadStruct(info);
8245dfecf96Smrg	    break;
8255dfecf96Smrg	case '+':
8265dfecf96Smrg	    result = LispReadFeature(1, info);
8275dfecf96Smrg	    break;
8285dfecf96Smrg	case '-':
8295dfecf96Smrg	    result = LispReadFeature(0, info);
8305dfecf96Smrg	    break;
8315dfecf96Smrg	case ':':
8325dfecf96Smrg	    /* Uninterned symbol */
8335dfecf96Smrg	    result = LispReadObject(1, info);
8345dfecf96Smrg	    break;
8355dfecf96Smrg	default:
8365dfecf96Smrg	    if (isdigit(ch)) {
8375dfecf96Smrg		LispUnget(ch);
8385dfecf96Smrg		result = LispReadMacroArg(info);
8395dfecf96Smrg	    }
8405dfecf96Smrg	    else if (!info->discard)
8415dfecf96Smrg		READ_ERROR1("undefined dispatch macro character #%c", ch);
8425dfecf96Smrg	    break;
8435dfecf96Smrg    }
8445dfecf96Smrg
8455dfecf96Smrg    return (result);
8465dfecf96Smrg}
8475dfecf96Smrg
8485dfecf96Smrgstatic LispObj *
8495dfecf96SmrgLispReadMacroArg(read_info *info)
8505dfecf96Smrg{
8515dfecf96Smrg    READ_ENTER();
8525dfecf96Smrg    LispObj *result = NIL;
8535dfecf96Smrg    long i, integer;
8545dfecf96Smrg    int ch;
8555dfecf96Smrg
8565dfecf96Smrg    /* skip leading zeros */
8575dfecf96Smrg    while (ch = LispGet(), ch != EOF && isdigit(ch) && ch == '0')
8585dfecf96Smrg	;
8595dfecf96Smrg
8605dfecf96Smrg    if (ch == EOF)
8615dfecf96Smrg	READ_ERROR_EOF();
8625dfecf96Smrg
8635dfecf96Smrg    /* if ch is not a number the argument was zero */
8645dfecf96Smrg    if (isdigit(ch)) {
8655dfecf96Smrg	char stk[32], *str;
8665dfecf96Smrg	int len = 1;
8675dfecf96Smrg
8685dfecf96Smrg	stk[0] = ch;
8695dfecf96Smrg	for (;;) {
8705dfecf96Smrg	    ch = LispGet();
8715dfecf96Smrg	    if (!isdigit(ch))
8725dfecf96Smrg		break;
8735dfecf96Smrg	    if (len + 1 >= sizeof(stk))
8745dfecf96Smrg		READ_ERROR_FIXNUM();
8755dfecf96Smrg	    stk[len++] = ch;
8765dfecf96Smrg	}
8775dfecf96Smrg	stk[len] = '\0';
8785dfecf96Smrg	errno = 0;
8795dfecf96Smrg	integer = strtol(stk, &str, 10);
8805dfecf96Smrg	/* number is positive because sign is not processed here */
8815dfecf96Smrg	if (*str || errno == ERANGE || integer > MOST_POSITIVE_FIXNUM)
8825dfecf96Smrg	    READ_ERROR_FIXNUM();
8835dfecf96Smrg    }
8845dfecf96Smrg    else
8855dfecf96Smrg	integer = 0;
8865dfecf96Smrg
8875dfecf96Smrg    switch (ch) {
8885dfecf96Smrg	case 'a':
8895dfecf96Smrg	case 'A':
8905dfecf96Smrg	    if (integer == 1) {
8915dfecf96Smrg		/* LispReadArray and LispReadList expect
8925dfecf96Smrg		 * the '(' being already read  */
8935dfecf96Smrg		if ((ch = LispSkipWhiteSpace()) != '(') {
8945dfecf96Smrg		    if (info->discard)
8955dfecf96Smrg			return (ch == EOF ? NULL : NIL);
8965dfecf96Smrg		    READ_ERROR0("bad array specification");
8975dfecf96Smrg		}
8985dfecf96Smrg		result = LispReadVector(info);
8995dfecf96Smrg	    }
9005dfecf96Smrg	    else
9015dfecf96Smrg		result = LispReadArray(integer, info);
9025dfecf96Smrg	    break;
9035dfecf96Smrg	case 'r':
9045dfecf96Smrg	case 'R':
9055dfecf96Smrg	    result = LispReadRational(integer, info);
9065dfecf96Smrg	    break;
9075dfecf96Smrg	case '=':
9085dfecf96Smrg	    if (integer > MAX_LABEL_VALUE)
9095dfecf96Smrg		READ_ERROR_FIXNUM();
9105dfecf96Smrg	    if (!info->discard) {
9115dfecf96Smrg		long num_objects = info->num_objects;
9125dfecf96Smrg
9135dfecf96Smrg		/* check for duplicated label */
9145dfecf96Smrg		for (i = 0; i < info->num_objects; i++) {
9155dfecf96Smrg		    if (info->objects[i].label == integer)
9165dfecf96Smrg			READ_ERROR1("label #%ld# defined more than once",
9175dfecf96Smrg				    integer);
9185dfecf96Smrg		}
9195dfecf96Smrg		info->objects = LispRealloc(info->objects,
9205dfecf96Smrg					    sizeof(object_info) *
9215dfecf96Smrg					    (num_objects + 1));
9225dfecf96Smrg		/* if this label is referenced it is a shared/circular object */
9235dfecf96Smrg		info->objects[num_objects].label = integer;
9245dfecf96Smrg		info->objects[num_objects].object = NULL;
9255dfecf96Smrg		info->objects[num_objects].num_circles = 0;
9265dfecf96Smrg		++info->num_objects;
9275dfecf96Smrg		result = LispDoRead(info);
9285dfecf96Smrg		if (READLABELP(result) && READLABEL_VALUE(result) == integer)
9295dfecf96Smrg		    READ_ERROR2("incorrect syntax #%ld= #%ld#",
9305dfecf96Smrg				integer, integer);
9315dfecf96Smrg		/* any reference to it now is not shared/circular */
9325dfecf96Smrg		info->objects[num_objects].object = result;
9335dfecf96Smrg	    }
9345dfecf96Smrg	    else
9355dfecf96Smrg		result = LispDoRead(info);
9365dfecf96Smrg	    break;
9375dfecf96Smrg	case '#':
9385dfecf96Smrg	    if (integer > MAX_LABEL_VALUE)
9395dfecf96Smrg		READ_ERROR_FIXNUM();
9405dfecf96Smrg	    if (!info->discard) {
9415dfecf96Smrg		/* search object */
9425dfecf96Smrg		for (i = 0; i < info->num_objects; i++) {
9435dfecf96Smrg		    if (info->objects[i].label == integer) {
9445dfecf96Smrg			result = info->objects[i].object;
9455dfecf96Smrg			if (result == NULL) {
9465dfecf96Smrg			    ++info->objects[i].num_circles;
9475dfecf96Smrg			    ++info->circle_count;
9485dfecf96Smrg			    result = READLABEL(integer);
9495dfecf96Smrg			}
9505dfecf96Smrg			break;
9515dfecf96Smrg		    }
9525dfecf96Smrg		}
9535dfecf96Smrg		if (i == info->num_objects)
9545dfecf96Smrg		    READ_ERROR1("undefined label #%ld#", integer);
9555dfecf96Smrg	    }
9565dfecf96Smrg	    break;
9575dfecf96Smrg	default:
9585dfecf96Smrg	    if (!info->discard)
9595dfecf96Smrg		READ_ERROR1("undefined dispatch macro character #%c", ch);
9605dfecf96Smrg	    break;
9615dfecf96Smrg    }
9625dfecf96Smrg
9635dfecf96Smrg    return (result);
9645dfecf96Smrg}
9655dfecf96Smrg
9665dfecf96Smrgstatic int
9675dfecf96SmrgLispSkipWhiteSpace(void)
9685dfecf96Smrg{
9695dfecf96Smrg    int ch;
9705dfecf96Smrg
9715dfecf96Smrg    for (;;) {
9725dfecf96Smrg	while (ch = LispGet(), isspace(ch) && ch != EOF)
9735dfecf96Smrg	    ;
9745dfecf96Smrg	if (ch == ';') {
9755dfecf96Smrg	    while (ch = LispGet(), ch != '\n' && ch != EOF)
9765dfecf96Smrg		;
9775dfecf96Smrg	    if (ch == EOF)
9785dfecf96Smrg		return (EOF);
9795dfecf96Smrg	}
9805dfecf96Smrg	else
9815dfecf96Smrg	    break;
9825dfecf96Smrg    }
9835dfecf96Smrg
9845dfecf96Smrg    return (ch);
9855dfecf96Smrg}
9865dfecf96Smrg
9875dfecf96Smrg/* any data in the format '(' FORM ')' is read here */
9885dfecf96Smrgstatic LispObj *
9895dfecf96SmrgLispReadList(read_info *info)
9905dfecf96Smrg{
9915dfecf96Smrg    READ_ENTER();
9925dfecf96Smrg    GC_ENTER();
9935dfecf96Smrg    LispObj *result, *cons, *object;
9945dfecf96Smrg    int dot = 0;
9955dfecf96Smrg
9965dfecf96Smrg    ++info->level;
9975dfecf96Smrg    /* check for () */
9985dfecf96Smrg    object = LispDoRead(info);
9995dfecf96Smrg    if (object == EOLIST) {
10005dfecf96Smrg	--info->level;
10015dfecf96Smrg
10025dfecf96Smrg	return (NIL);
10035dfecf96Smrg    }
10045dfecf96Smrg
10055dfecf96Smrg    if (object == DOT)
10065dfecf96Smrg	READ_ERROR0("illegal start of dotted list");
10075dfecf96Smrg
10085dfecf96Smrg    result = cons = CONS(object, NIL);
10095dfecf96Smrg
10105dfecf96Smrg    /* make sure GC will not release data being read */
10115dfecf96Smrg    GC_PROTECT(result);
10125dfecf96Smrg
10135dfecf96Smrg    while ((object = LispDoRead(info)) != EOLIST) {
10145dfecf96Smrg	if (object == NULL)
10155dfecf96Smrg	    READ_ERROR_EOF();
10165dfecf96Smrg	if (object == DOT) {
10175dfecf96Smrg	    if (info->nodot == info->level)
10185dfecf96Smrg		READ_ERROR0("dotted list not allowed");
10195dfecf96Smrg	    /* this is a dotted list */
10205dfecf96Smrg	    if (dot)
10215dfecf96Smrg		READ_ERROR0("more than one . in list");
10225dfecf96Smrg	    dot = 1;
10235dfecf96Smrg	}
10245dfecf96Smrg	else {
10255dfecf96Smrg	    if (dot) {
10265dfecf96Smrg		/* only one object after a dot */
10275dfecf96Smrg		if (++dot > 2)
10285dfecf96Smrg		    READ_ERROR0("more than one object after . in list");
10295dfecf96Smrg		RPLACD(cons, object);
10305dfecf96Smrg	    }
10315dfecf96Smrg	    else {
10325dfecf96Smrg		RPLACD(cons, CONS(object, NIL));
10335dfecf96Smrg		cons = CDR(cons);
10345dfecf96Smrg	    }
10355dfecf96Smrg	}
10365dfecf96Smrg    }
10375dfecf96Smrg
10385dfecf96Smrg    /* this will happen if last list element was a dot */
10395dfecf96Smrg    if (dot == 1)
10405dfecf96Smrg	READ_ERROR0("illegal end of dotted list");
10415dfecf96Smrg
10425dfecf96Smrg    --info->level;
10435dfecf96Smrg    GC_LEAVE();
10445dfecf96Smrg
10455dfecf96Smrg    return (result);
10465dfecf96Smrg}
10475dfecf96Smrg
10485dfecf96Smrgstatic LispObj *
10495dfecf96SmrgLispReadQuote(read_info *info)
10505dfecf96Smrg{
10515dfecf96Smrg    READ_ENTER();
10525dfecf96Smrg    LispObj *quote = LispDoRead(info), *result;
10535dfecf96Smrg
10545dfecf96Smrg    if (INVALIDP(quote))
10555dfecf96Smrg	READ_ERROR_INVARG();
10565dfecf96Smrg
10575dfecf96Smrg    result = QUOTE(quote);
10585dfecf96Smrg
10595dfecf96Smrg    return (result);
10605dfecf96Smrg}
10615dfecf96Smrg
10625dfecf96Smrgstatic LispObj *
10635dfecf96SmrgLispReadBackquote(read_info *info)
10645dfecf96Smrg{
10655dfecf96Smrg    READ_ENTER();
10665dfecf96Smrg    LispObj *backquote = LispDoRead(info), *result;
10675dfecf96Smrg
10685dfecf96Smrg    if (INVALIDP(backquote))
10695dfecf96Smrg	READ_ERROR_INVARG();
10705dfecf96Smrg
10715dfecf96Smrg    result = BACKQUOTE(backquote);
10725dfecf96Smrg
10735dfecf96Smrg    return (result);
10745dfecf96Smrg}
10755dfecf96Smrg
10765dfecf96Smrgstatic LispObj *
10775dfecf96SmrgLispReadCommaquote(read_info *info)
10785dfecf96Smrg{
10795dfecf96Smrg    READ_ENTER();
10805dfecf96Smrg    LispObj *comma, *result;
10815dfecf96Smrg    int atlist = LispGet();
10825dfecf96Smrg
10835dfecf96Smrg    if (atlist == EOF)
10845dfecf96Smrg	READ_ERROR_EOF();
10855dfecf96Smrg    else if (atlist != '@' && atlist != '.')
10865dfecf96Smrg	LispUnget(atlist);
10875dfecf96Smrg
10885dfecf96Smrg    comma = LispDoRead(info);
10895dfecf96Smrg    if (comma == DOT) {
10905dfecf96Smrg	atlist = '@';
10915dfecf96Smrg	comma = LispDoRead(info);
10925dfecf96Smrg    }
10935dfecf96Smrg    if (INVALIDP(comma))
10945dfecf96Smrg	READ_ERROR_INVARG();
10955dfecf96Smrg
10965dfecf96Smrg    result = COMMA(comma, atlist == '@' || atlist == '.');
10975dfecf96Smrg
10985dfecf96Smrg    return (result);
10995dfecf96Smrg}
11005dfecf96Smrg
11015dfecf96Smrg/*
11025dfecf96Smrg * Read anything that is not readily identifiable by it's first character
11035dfecf96Smrg * and also put the code for reading atoms, numbers and strings together.
11045dfecf96Smrg */
11055dfecf96Smrgstatic LispObj *
11065dfecf96SmrgLispReadObject(int unintern, read_info *info)
11075dfecf96Smrg{
11085dfecf96Smrg    READ_ENTER();
11095dfecf96Smrg    LispObj *object;
11105dfecf96Smrg    char stk[128], *string, *package, *symbol;
11115dfecf96Smrg    int ch, length, backslash, size, quote, unreadable, collon;
11125dfecf96Smrg
11135dfecf96Smrg    package = symbol = string = stk;
11145dfecf96Smrg    size = sizeof(stk);
11155dfecf96Smrg    backslash = quote = unreadable = collon = 0;
11165dfecf96Smrg    length = 0;
11175dfecf96Smrg
11185dfecf96Smrg    ch = LispGet();
11195dfecf96Smrg    if (unintern && (ch == ':' || ch == '"'))
11205dfecf96Smrg	READ_ERROR0("syntax error after #:");
11215dfecf96Smrg    else if (ch == '"' || ch == '|')
11225dfecf96Smrg	quote = ch;
11235dfecf96Smrg    else if (ch == '\\') {
11245dfecf96Smrg	unreadable = backslash = 1;
11255dfecf96Smrg	string[length++] = ch;
11265dfecf96Smrg    }
11275dfecf96Smrg    else if (ch == ':') {
11285dfecf96Smrg	collon = 1;
11295dfecf96Smrg	string[length++] = ch;
11305dfecf96Smrg	symbol = string + 1;
1131f14f4646Smrg	ch = LispGet();
1132f14f4646Smrg	if (ch == '|') {
1133f14f4646Smrg	    quote = ch;
1134f14f4646Smrg	    unreadable = 1;
1135f14f4646Smrg	}
1136f14f4646Smrg	else if (ch != EOF)
1137f14f4646Smrg	    LispUnget(ch);
11385dfecf96Smrg    }
11395dfecf96Smrg    else if (ch) {
11405dfecf96Smrg	if (islower(ch))
11415dfecf96Smrg	    ch = toupper(ch);
11425dfecf96Smrg	string[length++] = ch;
11435dfecf96Smrg    }
11445dfecf96Smrg    else
11455dfecf96Smrg	unreadable = 1;
11465dfecf96Smrg
11475dfecf96Smrg    /* read remaining data */
11485dfecf96Smrg    for (; ch;) {
11495dfecf96Smrg	ch = LispGet();
11505dfecf96Smrg
11515dfecf96Smrg	if (ch == EOF) {
11525dfecf96Smrg	    if (quote) {
11535dfecf96Smrg		/* if quote, file ended with an open quoted object */
11545dfecf96Smrg		if (string != stk)
11555dfecf96Smrg		    LispFree(string);
11565dfecf96Smrg		return (NULL);
11575dfecf96Smrg	    }
11585dfecf96Smrg	    break;
11595dfecf96Smrg	}
11605dfecf96Smrg	else if (ch == '\0')
11615dfecf96Smrg	    break;
11625dfecf96Smrg
11635dfecf96Smrg	if (ch == '\\') {
11645dfecf96Smrg	    backslash = !backslash;
11655dfecf96Smrg	    if (quote == '"') {
11665dfecf96Smrg		/* only remove backslashs from strings */
11675dfecf96Smrg		if (backslash)
11685dfecf96Smrg		    continue;
11695dfecf96Smrg	    }
11705dfecf96Smrg	    else
11715dfecf96Smrg		unreadable = 1;
11725dfecf96Smrg	}
11735dfecf96Smrg	else if (backslash)
11745dfecf96Smrg	    backslash = 0;
11755dfecf96Smrg	else if (ch == quote)
11765dfecf96Smrg	    break;
11775dfecf96Smrg	else if (!quote && !backslash) {
11785dfecf96Smrg	    if (islower(ch))
11795dfecf96Smrg		ch = toupper(ch);
11805dfecf96Smrg	    else if (isspace(ch))
11815dfecf96Smrg		break;
11825dfecf96Smrg	    else if (AtomSeparator(ch, 0, 0)) {
11835dfecf96Smrg		LispUnget(ch);
11845dfecf96Smrg		break;
11855dfecf96Smrg	    }
11865dfecf96Smrg	    else if (ch == ':') {
11875dfecf96Smrg		if (collon == 0 ||
11885dfecf96Smrg		    (collon == (1 - unintern) && symbol == string + length)) {
11895dfecf96Smrg		    ++collon;
11905dfecf96Smrg		    symbol = string + length + 1;
11915dfecf96Smrg		}
11925dfecf96Smrg		else
11935dfecf96Smrg		    READ_ERROR0("too many collons");
11945dfecf96Smrg	    }
11955dfecf96Smrg	}
11965dfecf96Smrg
11975dfecf96Smrg	if (length + 2 >= size) {
11985dfecf96Smrg	    if (string == stk) {
11995dfecf96Smrg		size = 1024;
12005dfecf96Smrg		string = LispMalloc(size);
12015dfecf96Smrg		strcpy(string, stk);
12025dfecf96Smrg	    }
12035dfecf96Smrg	    else {
12045dfecf96Smrg		size += 1024;
12055dfecf96Smrg		string = LispRealloc(string, size);
12065dfecf96Smrg	    }
12075dfecf96Smrg	    symbol = string + (symbol - package);
12085dfecf96Smrg	    package = string;
12095dfecf96Smrg	}
12105dfecf96Smrg	string[length++] = ch;
12115dfecf96Smrg    }
12125dfecf96Smrg
12135dfecf96Smrg    if (info->discard) {
12145dfecf96Smrg	if (string != stk)
12155dfecf96Smrg	    LispFree(string);
12165dfecf96Smrg
12175dfecf96Smrg	return (ch == EOF ? NULL : NIL);
12185dfecf96Smrg    }
12195dfecf96Smrg
12205dfecf96Smrg    string[length] = '\0';
12215dfecf96Smrg
12225dfecf96Smrg    if (unintern) {
12235dfecf96Smrg	if (length == 0)
12245dfecf96Smrg	    READ_ERROR0("syntax error after #:");
12255dfecf96Smrg	object = UNINTERNED_ATOM(string);
12265dfecf96Smrg    }
12275dfecf96Smrg
12285dfecf96Smrg    else if (quote == '"')
12295dfecf96Smrg	object = LSTRING(string, length);
12305dfecf96Smrg
12315dfecf96Smrg    else if (collon) {
12325dfecf96Smrg	/* Package specified in object name */
12335dfecf96Smrg	symbol[-1] = '\0';
12345dfecf96Smrg	if (collon > 1)
12355dfecf96Smrg	    symbol[-2] = '\0';
12365dfecf96Smrg	object = LispParseAtom(package, symbol,
12375dfecf96Smrg			       collon == 2, unreadable,
12385dfecf96Smrg			       read__stream, read__line);
12395dfecf96Smrg    }
12405dfecf96Smrg
1241f14f4646Smrg    else if (quote == '|' || (unreadable && !collon)) {
1242f14f4646Smrg	/* Set unreadable field, this atom needs quoting to be read back */
1243f14f4646Smrg	object = ATOM(string);
1244f14f4646Smrg	object->data.atom->unreadable = 1;
1245f14f4646Smrg    }
1246f14f4646Smrg
12475dfecf96Smrg    /* Check some common symbols */
12485dfecf96Smrg    else if (length == 1 && string[0] == 'T')
12495dfecf96Smrg	/* The T */
12505dfecf96Smrg	object = T;
12515dfecf96Smrg
12525dfecf96Smrg    else if (length == 1 && string[0] == '.')
12535dfecf96Smrg	/* The dot */
12545dfecf96Smrg	object = DOT;
12555dfecf96Smrg
12565dfecf96Smrg    else if (length == 3 &&
12575dfecf96Smrg	     string[0] == 'N' && string[1] == 'I' && string[2] == 'L')
12585dfecf96Smrg	/* The NIL */
12595dfecf96Smrg	object = NIL;
12605dfecf96Smrg
12615dfecf96Smrg    else if (isdigit(string[0]) || string[0] == '.' ||
12625dfecf96Smrg	     ((string[0] == '-' || string[0] == '+') && string[1]))
12635dfecf96Smrg	/* Looks like a number */
12645dfecf96Smrg	object = LispParseNumber(string, 10, read__stream, read__line);
12655dfecf96Smrg
12665dfecf96Smrg    else
12675dfecf96Smrg	/* A normal atom */
12685dfecf96Smrg	object = ATOM(string);
12695dfecf96Smrg
12705dfecf96Smrg    if (string != stk)
12715dfecf96Smrg	LispFree(string);
12725dfecf96Smrg
12735dfecf96Smrg    return (object);
12745dfecf96Smrg}
12755dfecf96Smrg
12765dfecf96Smrgstatic LispObj *
12775dfecf96SmrgLispParseAtom(char *package, char *symbol, int intern, int unreadable,
12785dfecf96Smrg	      LispObj *read__stream, int read__line)
12795dfecf96Smrg{
12805dfecf96Smrg    LispObj *object = NULL, *thepackage = NULL;
12815dfecf96Smrg    LispPackage *pack = NULL;
12825dfecf96Smrg
12835dfecf96Smrg    if (!unreadable) {
12845dfecf96Smrg	/* Until NIL and T be treated as normal symbols */
12855dfecf96Smrg	if (symbol[0] == 'N' && symbol[1] == 'I' &&
12865dfecf96Smrg	    symbol[2] == 'L' && symbol[3] == '\0')
12875dfecf96Smrg	    return (NIL);
12885dfecf96Smrg	if (symbol[0] == 'T' && symbol[1] == '\0')
12895dfecf96Smrg	    return (T);
12905dfecf96Smrg	unreadable = !LispCheckAtomString(symbol);
12915dfecf96Smrg    }
12925dfecf96Smrg
12935dfecf96Smrg    /* If package is empty, it is a keyword */
12945dfecf96Smrg    if (package[0] == '\0') {
12955dfecf96Smrg	thepackage = lisp__data.keyword;
12965dfecf96Smrg	pack = lisp__data.key;
12975dfecf96Smrg    }
12985dfecf96Smrg
12995dfecf96Smrg    else {
13005dfecf96Smrg	/* Else, search it in the package list */
13015dfecf96Smrg	thepackage = LispFindPackageFromString(package);
13025dfecf96Smrg
13035dfecf96Smrg	if (thepackage == NIL)
13045dfecf96Smrg	    READ_ERROR1("the package %s is not available", package);
13055dfecf96Smrg
13065dfecf96Smrg	pack = thepackage->data.package.package;
13075dfecf96Smrg    }
13085dfecf96Smrg
13095dfecf96Smrg    if (pack == lisp__data.pack && intern) {
13105dfecf96Smrg	/* Redundant package specification, since requesting a
13115dfecf96Smrg	 * intern symbol, create it if does not exist */
13125dfecf96Smrg
13135dfecf96Smrg	object = ATOM(symbol);
13145dfecf96Smrg	if (unreadable)
13155dfecf96Smrg	    object->data.atom->unreadable = 1;
13165dfecf96Smrg    }
13175dfecf96Smrg
13185dfecf96Smrg    else if (intern || pack == lisp__data.key) {
13195dfecf96Smrg	/* Symbol is created, or just fetched from the specified package */
13205dfecf96Smrg
13215dfecf96Smrg	LispPackage *savepack;
13225dfecf96Smrg	LispObj *savepackage = PACKAGE;
13235dfecf96Smrg
13245dfecf96Smrg	/* Remember curent package */
13255dfecf96Smrg	savepack = lisp__data.pack;
13265dfecf96Smrg
13275dfecf96Smrg	/* Temporarily set another package */
13285dfecf96Smrg	lisp__data.pack = pack;
13295dfecf96Smrg	PACKAGE = thepackage;
13305dfecf96Smrg
13315dfecf96Smrg	/* Get the object pointer */
13325dfecf96Smrg	if (pack == lisp__data.key)
1333f14f4646Smrg	    object = KEYWORD(LispDoGetAtom(symbol, 0)->key->value);
13345dfecf96Smrg	else
13355dfecf96Smrg	    object = ATOM(symbol);
13365dfecf96Smrg	if (unreadable)
13375dfecf96Smrg	    object->data.atom->unreadable = 1;
13385dfecf96Smrg
13395dfecf96Smrg	/* Restore current package */
13405dfecf96Smrg	lisp__data.pack = savepack;
13415dfecf96Smrg	PACKAGE = savepackage;
13425dfecf96Smrg    }
13435dfecf96Smrg
13445dfecf96Smrg    else {
13455dfecf96Smrg	/* Symbol must exist (and be extern) in the specified package */
13465dfecf96Smrg
13475dfecf96Smrg	LispAtom *atom;
13485dfecf96Smrg
1349f14f4646Smrg	atom = (LispAtom *)hash_check(pack->atoms, symbol, strlen(symbol));
1350f14f4646Smrg	if (atom)
1351f14f4646Smrg	    object = atom->object;
13525dfecf96Smrg
13535dfecf96Smrg	/* No object found */
13545dfecf96Smrg	if (object == NULL || object->data.atom->ext == 0)
13555dfecf96Smrg	    READ_ERROR2("no extern symbol %s in package %s", symbol, package);
13565dfecf96Smrg    }
13575dfecf96Smrg
13585dfecf96Smrg    return (object);
13595dfecf96Smrg}
13605dfecf96Smrg
13615dfecf96Smrgstatic LispObj *
13625dfecf96SmrgLispParseNumber(char *str, int radix, LispObj *read__stream, int read__line)
13635dfecf96Smrg{
13645dfecf96Smrg    int len;
13655dfecf96Smrg    long integer;
13665dfecf96Smrg    double dfloat;
13675dfecf96Smrg    char *ratio, *ptr;
13685dfecf96Smrg    LispObj *number;
13695dfecf96Smrg    mpi *bignum;
13705dfecf96Smrg    mpr *bigratio;
13715dfecf96Smrg
13725dfecf96Smrg    if (radix < 2 || radix > 36)
13735dfecf96Smrg	READ_ERROR1("radix %d is not in the range 2 to 36", radix);
13745dfecf96Smrg
13755dfecf96Smrg    if (*str == '\0')
13765dfecf96Smrg	return (NULL);
13775dfecf96Smrg
13785dfecf96Smrg    ratio = strchr(str, '/');
13795dfecf96Smrg    if (ratio) {
13805dfecf96Smrg	/* check if looks like a correctly specified ratio */
13815dfecf96Smrg	if (ratio[1] == '\0' || strchr(ratio + 1, '/') != NULL)
13825dfecf96Smrg	    return (ATOM(str));
13835dfecf96Smrg
13845dfecf96Smrg	/* ratio must point to an integer in radix base */
13855dfecf96Smrg	*ratio++ = '\0';
13865dfecf96Smrg    }
13875dfecf96Smrg    else if (radix == 10) {
13885dfecf96Smrg	int dot = 0;
13895dfecf96Smrg	int type = 0;
13905dfecf96Smrg
13915dfecf96Smrg	/* check if it is a floating point number */
13925dfecf96Smrg	ptr = str;
13935dfecf96Smrg	if (*ptr == '-' || *ptr == '+')
13945dfecf96Smrg	    ++ptr;
13955dfecf96Smrg	else if (*ptr == '.') {
13965dfecf96Smrg	    dot = 1;
13975dfecf96Smrg	    ++ptr;
13985dfecf96Smrg	}
13995dfecf96Smrg	while (*ptr) {
14005dfecf96Smrg	    if (*ptr == '.') {
14015dfecf96Smrg		if (dot)
14025dfecf96Smrg		    return (ATOM(str));
14035dfecf96Smrg		/* ignore it if last char is a dot */
14045dfecf96Smrg		if (ptr[1] == '\0') {
14055dfecf96Smrg		    *ptr = '\0';
14065dfecf96Smrg		    break;
14075dfecf96Smrg		}
14085dfecf96Smrg		dot = 1;
14095dfecf96Smrg	    }
14105dfecf96Smrg	    else if (!isdigit(*ptr))
14115dfecf96Smrg		break;
14125dfecf96Smrg	    ++ptr;
14135dfecf96Smrg	}
14145dfecf96Smrg
14155dfecf96Smrg	switch (*ptr) {
14165dfecf96Smrg	    case '\0':
14175dfecf96Smrg		if (dot)		/* if dot, it is default float */
14185dfecf96Smrg		    type = 'E';
14195dfecf96Smrg		break;
14205dfecf96Smrg	    case 'E': case 'S': case 'F': case 'D': case 'L':
14215dfecf96Smrg		type = *ptr;
14225dfecf96Smrg		*ptr = 'E';
14235dfecf96Smrg		break;
14245dfecf96Smrg	    default:
14255dfecf96Smrg		return (ATOM(str));	/* syntax error */
14265dfecf96Smrg	}
14275dfecf96Smrg
14285dfecf96Smrg	/* if type set, it is not an integer specification */
14295dfecf96Smrg	if (type) {
14305dfecf96Smrg	    if (*ptr) {
14315dfecf96Smrg		int itype = *ptr;
14325dfecf96Smrg		char *ptype = ptr;
14335dfecf96Smrg
14345dfecf96Smrg		++ptr;
14355dfecf96Smrg		if (*ptr == '+' || *ptr == '-')
14365dfecf96Smrg		    ++ptr;
14375dfecf96Smrg		while (*ptr && isdigit(*ptr))
14385dfecf96Smrg		    ++ptr;
14395dfecf96Smrg		if (*ptr) {
14405dfecf96Smrg		    *ptype = itype;
14415dfecf96Smrg
14425dfecf96Smrg		    return (ATOM(str));
14435dfecf96Smrg		}
14445dfecf96Smrg	    }
14455dfecf96Smrg
14465dfecf96Smrg	    dfloat = strtod(str, NULL);
14475dfecf96Smrg	    if (!finite(dfloat))
14485dfecf96Smrg		READ_ERROR0("floating point overflow");
14495dfecf96Smrg
14505dfecf96Smrg	    return (DFLOAT(dfloat));
14515dfecf96Smrg	}
14525dfecf96Smrg    }
14535dfecf96Smrg
14545dfecf96Smrg    /* check if correctly specified in the given radix */
14555dfecf96Smrg    len = strlen(str) - 1;
14565dfecf96Smrg    if (!ratio && radix != 10 && str[len] == '.')
14575dfecf96Smrg	str[len] = '\0';
14585dfecf96Smrg
14595dfecf96Smrg    if (ratio || radix != 10) {
14605dfecf96Smrg	if (!StringInRadix(str, radix, 1)) {
14615dfecf96Smrg	    if (ratio)
14625dfecf96Smrg		ratio[-1] = '/';
14635dfecf96Smrg	    return (ATOM(str));
14645dfecf96Smrg	}
14655dfecf96Smrg	if (ratio && !StringInRadix(ratio, radix, 0)) {
14665dfecf96Smrg	    ratio[-1] = '/';
14675dfecf96Smrg	    return (ATOM(str));
14685dfecf96Smrg	}
14695dfecf96Smrg    }
14705dfecf96Smrg
14715dfecf96Smrg    bignum = NULL;
14725dfecf96Smrg    bigratio = NULL;
14735dfecf96Smrg
14745dfecf96Smrg    errno = 0;
14755dfecf96Smrg    integer = strtol(str, NULL, radix);
14765dfecf96Smrg
14775dfecf96Smrg    /* if does not fit in a long */
147831de2854Smrg    if (errno == ERANGE) {
14795dfecf96Smrg	bignum = LispMalloc(sizeof(mpi));
14805dfecf96Smrg	mpi_init(bignum);
14815dfecf96Smrg	mpi_setstr(bignum, str, radix);
14825dfecf96Smrg    }
14835dfecf96Smrg
14845dfecf96Smrg
14855dfecf96Smrg    if (ratio && integer != 0) {
14865dfecf96Smrg	long denominator;
14875dfecf96Smrg
14885dfecf96Smrg	errno = 0;
14895dfecf96Smrg	denominator = strtol(ratio, NULL, radix);
14905dfecf96Smrg	if (denominator == 0)
14915dfecf96Smrg	    READ_ERROR0("divide by zero");
14925dfecf96Smrg
14935dfecf96Smrg	if (bignum == NULL) {
14945dfecf96Smrg	    if (integer == MINSLONG ||
14955dfecf96Smrg		(denominator == LONG_MAX && errno == ERANGE)) {
14965dfecf96Smrg		bigratio = LispMalloc(sizeof(mpr));
14975dfecf96Smrg		mpr_init(bigratio);
14985dfecf96Smrg		mpi_seti(mpr_num(bigratio), integer);
14995dfecf96Smrg		mpi_setstr(mpr_den(bigratio), ratio, radix);
15005dfecf96Smrg	    }
15015dfecf96Smrg	}
15025dfecf96Smrg	else {
15035dfecf96Smrg	    bigratio = LispMalloc(sizeof(mpr));
15045dfecf96Smrg	    mpr_init(bigratio);
15055dfecf96Smrg	    mpi_set(mpr_num(bigratio), bignum);
15065dfecf96Smrg	    mpi_clear(bignum);
15075dfecf96Smrg	    LispFree(bignum);
15085dfecf96Smrg	    mpi_setstr(mpr_den(bigratio), ratio, radix);
15095dfecf96Smrg	}
15105dfecf96Smrg
15115dfecf96Smrg	if (bigratio) {
15125dfecf96Smrg	    mpr_canonicalize(bigratio);
15135dfecf96Smrg	    if (mpi_fiti(mpr_num(bigratio)) &&
15145dfecf96Smrg		mpi_fiti(mpr_den(bigratio))) {
15155dfecf96Smrg		integer = mpi_geti(mpr_num(bigratio));
15165dfecf96Smrg		denominator = mpi_geti(mpr_den(bigratio));
15175dfecf96Smrg		mpr_clear(bigratio);
15185dfecf96Smrg		LispFree(bigratio);
15195dfecf96Smrg		if (denominator == 1)
15205dfecf96Smrg		    number = INTEGER(integer);
15215dfecf96Smrg		else
15225dfecf96Smrg		    number = RATIO(integer, denominator);
15235dfecf96Smrg	    }
15245dfecf96Smrg	    else
15255dfecf96Smrg		number = BIGRATIO(bigratio);
15265dfecf96Smrg	}
15275dfecf96Smrg	else {
15285dfecf96Smrg	    long num = integer, den = denominator, rest;
15295dfecf96Smrg
15305dfecf96Smrg	    if (num < 0)
15315dfecf96Smrg		num = -num;
15325dfecf96Smrg	    for (;;) {
15335dfecf96Smrg		if ((rest = den % num) == 0)
15345dfecf96Smrg		    break;
15355dfecf96Smrg		den = num;
15365dfecf96Smrg		num = rest;
15375dfecf96Smrg	    }
15385dfecf96Smrg	    if (den != 1) {
15395dfecf96Smrg		denominator /= num;
15405dfecf96Smrg		integer /= num;
15415dfecf96Smrg	    }
15425dfecf96Smrg	    if (denominator < 0) {
15435dfecf96Smrg		integer = -integer;
15445dfecf96Smrg		denominator = -denominator;
15455dfecf96Smrg	    }
15465dfecf96Smrg	    if (denominator == 1)
15475dfecf96Smrg		number = INTEGER(integer);
15485dfecf96Smrg	    else
15495dfecf96Smrg		number = RATIO(integer, denominator);
15505dfecf96Smrg	}
15515dfecf96Smrg    }
15525dfecf96Smrg    else if (bignum)
15535dfecf96Smrg	number = BIGNUM(bignum);
15545dfecf96Smrg    else
15555dfecf96Smrg	number = INTEGER(integer);
15565dfecf96Smrg
15575dfecf96Smrg    return (number);
15585dfecf96Smrg}
15595dfecf96Smrg
15605dfecf96Smrgstatic int
15615dfecf96SmrgStringInRadix(char *str, int radix, int skip_sign)
15625dfecf96Smrg{
15635dfecf96Smrg    if (skip_sign && (*str == '-' || *str == '+'))
15645dfecf96Smrg	++str;
15655dfecf96Smrg    while (*str) {
15665dfecf96Smrg	if (*str >= '0' && *str <= '9') {
15675dfecf96Smrg	    if (*str - '0' >= radix)
15685dfecf96Smrg		return (0);
15695dfecf96Smrg	}
15705dfecf96Smrg	else if (*str >= 'A' && *str <= 'Z') {
15715dfecf96Smrg	    if (radix <= 10 || *str - 'A' + 10 >= radix)
15725dfecf96Smrg		return (0);
15735dfecf96Smrg	}
15745dfecf96Smrg	else
15755dfecf96Smrg	    return (0);
15765dfecf96Smrg	str++;
15775dfecf96Smrg    }
15785dfecf96Smrg
15795dfecf96Smrg    return (1);
15805dfecf96Smrg}
15815dfecf96Smrg
15825dfecf96Smrgstatic int
15835dfecf96SmrgAtomSeparator(int ch, int check_space, int check_backslash)
15845dfecf96Smrg{
15855dfecf96Smrg    if (check_space && isspace(ch))
15865dfecf96Smrg	return (1);
15875dfecf96Smrg    if (check_backslash && ch == '\\')
15885dfecf96Smrg	return (1);
15895dfecf96Smrg    return (strchr("(),\";'`#|,", ch) != NULL);
15905dfecf96Smrg}
15915dfecf96Smrg
15925dfecf96Smrgstatic LispObj *
15935dfecf96SmrgLispReadVector(read_info *info)
15945dfecf96Smrg{
15955dfecf96Smrg    LispObj *objects;
15965dfecf96Smrg    int nodot = info->nodot;
15975dfecf96Smrg
15985dfecf96Smrg    info->nodot = info->level + 1;
15995dfecf96Smrg    objects = LispReadList(info);
16005dfecf96Smrg    info->nodot = nodot;
16015dfecf96Smrg
16025dfecf96Smrg    if (info->discard)
16035dfecf96Smrg	return (objects);
16045dfecf96Smrg
16055dfecf96Smrg    return (VECTOR(objects));
16065dfecf96Smrg}
16075dfecf96Smrg
16085dfecf96Smrgstatic LispObj *
16095dfecf96SmrgLispReadFunction(read_info *info)
16105dfecf96Smrg{
16115dfecf96Smrg    READ_ENTER();
16125dfecf96Smrg    int nodot = info->nodot;
16135dfecf96Smrg    LispObj *function;
16145dfecf96Smrg
16155dfecf96Smrg    info->nodot = info->level + 1;
16165dfecf96Smrg    function = LispDoRead(info);
16175dfecf96Smrg    info->nodot = nodot;
16185dfecf96Smrg
16195dfecf96Smrg    if (info->discard)
16205dfecf96Smrg	return (function);
16215dfecf96Smrg
16225dfecf96Smrg    if (INVALIDP(function))
16235dfecf96Smrg	READ_ERROR_INVARG();
16245dfecf96Smrg    else if (CONSP(function)) {
16255dfecf96Smrg	if (CAR(function) != Olambda)
16265dfecf96Smrg	    READ_ERROR_INVARG();
16275dfecf96Smrg
16285dfecf96Smrg	return (FUNCTION_QUOTE(function));
16295dfecf96Smrg    }
16305dfecf96Smrg    else if (!SYMBOLP(function))
16315dfecf96Smrg	READ_ERROR_INVARG();
16325dfecf96Smrg
16335dfecf96Smrg    return (FUNCTION_QUOTE(function));
16345dfecf96Smrg}
16355dfecf96Smrg
16365dfecf96Smrgstatic LispObj *
16375dfecf96SmrgLispReadRational(int radix, read_info *info)
16385dfecf96Smrg{
16395dfecf96Smrg    READ_ENTER();
16405dfecf96Smrg    LispObj *number;
16415dfecf96Smrg    int ch, len, size;
16425dfecf96Smrg    char stk[128], *str;
16435dfecf96Smrg
16445dfecf96Smrg    len = 0;
16455dfecf96Smrg    str = stk;
16465dfecf96Smrg    size = sizeof(stk);
16475dfecf96Smrg
16485dfecf96Smrg    for (;;) {
16495dfecf96Smrg	ch = LispGet();
16505dfecf96Smrg	if (ch == EOF || isspace(ch))
16515dfecf96Smrg	    break;
16525dfecf96Smrg	else if (AtomSeparator(ch, 0, 1)) {
16535dfecf96Smrg	    LispUnget(ch);
16545dfecf96Smrg	    break;
16555dfecf96Smrg	}
16565dfecf96Smrg	else if (islower(ch))
16575dfecf96Smrg	    ch = toupper(ch);
16585dfecf96Smrg	if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') &&
16595dfecf96Smrg	    ch != '+' && ch != '-' && ch != '/') {
16605dfecf96Smrg	    if (str != stk)
16615dfecf96Smrg		LispFree(str);
16625dfecf96Smrg	    if (!info->discard)
16635dfecf96Smrg		READ_ERROR1("bad character %c for rational number", ch);
16645dfecf96Smrg	}
16655dfecf96Smrg	if (len + 1 >= size) {
16665dfecf96Smrg	    if (str == stk) {
16675dfecf96Smrg		size = 512;
16685dfecf96Smrg		str = LispMalloc(size);
16695dfecf96Smrg		strcpy(str + 1, stk + 1);
16705dfecf96Smrg	    }
16715dfecf96Smrg	    else {
16725dfecf96Smrg		size += 512;
16735dfecf96Smrg		str = LispRealloc(str, size);
16745dfecf96Smrg	    }
16755dfecf96Smrg	}
16765dfecf96Smrg	str[len++] = ch;
16775dfecf96Smrg    }
16785dfecf96Smrg
16795dfecf96Smrg    if (info->discard) {
16805dfecf96Smrg	if (str != stk)
16815dfecf96Smrg	    LispFree(str);
16825dfecf96Smrg
16835dfecf96Smrg	return (ch == EOF ? NULL : NIL);
16845dfecf96Smrg    }
16855dfecf96Smrg
16865dfecf96Smrg    str[len] = '\0';
16875dfecf96Smrg
16885dfecf96Smrg    number = LispParseNumber(str, radix, read__stream, read__line);
16895dfecf96Smrg    if (str != stk)
16905dfecf96Smrg	LispFree(str);
16915dfecf96Smrg
16925dfecf96Smrg    if (!RATIONALP(number))
16935dfecf96Smrg	READ_ERROR0("bad rational number specification");
16945dfecf96Smrg
16955dfecf96Smrg    return (number);
16965dfecf96Smrg}
16975dfecf96Smrg
16985dfecf96Smrgstatic LispObj *
16995dfecf96SmrgLispReadCharacter(read_info *info)
17005dfecf96Smrg{
17015dfecf96Smrg    READ_ENTER();
17025dfecf96Smrg    long c;
17035dfecf96Smrg    int ch, len;
17045dfecf96Smrg    char stk[64];
17055dfecf96Smrg
17065dfecf96Smrg    ch = LispGet();
17075dfecf96Smrg    if (ch == EOF)
17085dfecf96Smrg	return (NULL);
17095dfecf96Smrg
17105dfecf96Smrg    stk[0] = ch;
17115dfecf96Smrg    len = 1;
17125dfecf96Smrg
17135dfecf96Smrg    for (;;) {
17145dfecf96Smrg	ch = LispGet();
17155dfecf96Smrg	if (ch == EOF)
17165dfecf96Smrg	    break;
17175dfecf96Smrg	else if (ch != '-' && !isalnum(ch)) {
17185dfecf96Smrg	    LispUnget(ch);
17195dfecf96Smrg	    break;
17205dfecf96Smrg	}
17215dfecf96Smrg	if (len + 1 < sizeof(stk))
17225dfecf96Smrg	    stk[len++] = ch;
17235dfecf96Smrg    }
17245dfecf96Smrg    if (len > 1) {
1725f765521fSmrg	const char * const *names;
17265dfecf96Smrg	int found = 0;
17275dfecf96Smrg	stk[len] = '\0';
17285dfecf96Smrg
17295dfecf96Smrg	for (c = ch = 0; ch <= ' ' && !found; ch++) {
17305dfecf96Smrg	    for (names = LispChars[ch].names; *names; names++)
17315dfecf96Smrg		if (strcasecmp(*names, stk) == 0) {
17325dfecf96Smrg		    c = ch;
17335dfecf96Smrg		    found = 1;
17345dfecf96Smrg		    break;
17355dfecf96Smrg		}
17365dfecf96Smrg	}
17375dfecf96Smrg	if (!found) {
17385dfecf96Smrg	    for (names = LispChars[0177].names; *names; names++)
17395dfecf96Smrg		if (strcasecmp(*names, stk) == 0) {
17405dfecf96Smrg		    c = 0177;
17415dfecf96Smrg		    found = 1;
17425dfecf96Smrg		    break;
17435dfecf96Smrg		}
17445dfecf96Smrg	}
17455dfecf96Smrg
17465dfecf96Smrg	if (!found) {
17475dfecf96Smrg	    if (info->discard)
17485dfecf96Smrg		return (NIL);
17495dfecf96Smrg	    READ_ERROR1("unkwnown character %s", stk);
17505dfecf96Smrg	}
17515dfecf96Smrg    }
17525dfecf96Smrg    else
17535dfecf96Smrg	c = stk[0];
17545dfecf96Smrg
17555dfecf96Smrg    return (SCHAR(c));
17565dfecf96Smrg}
17575dfecf96Smrg
17585dfecf96Smrgstatic void
17595dfecf96SmrgLispSkipComment(void)
17605dfecf96Smrg{
17615dfecf96Smrg    READ_ENTER();
17625dfecf96Smrg    int ch, comm = 1;
17635dfecf96Smrg
17645dfecf96Smrg    for (;;) {
17655dfecf96Smrg	ch = LispGet();
17665dfecf96Smrg	if (ch == '#') {
17675dfecf96Smrg	    ch = LispGet();
17685dfecf96Smrg	    if (ch == '|')
17695dfecf96Smrg		++comm;
17705dfecf96Smrg	    continue;
17715dfecf96Smrg	}
17725dfecf96Smrg	while (ch == '|') {
17735dfecf96Smrg	    ch = LispGet();
17745dfecf96Smrg	    if (ch == '#' && --comm == 0)
17755dfecf96Smrg		return;
17765dfecf96Smrg	}
17775dfecf96Smrg	if (ch == EOF)
17785dfecf96Smrg	    READ_ERROR_EOF();
17795dfecf96Smrg    }
17805dfecf96Smrg}
17815dfecf96Smrg
17825dfecf96Smrgstatic LispObj *
17835dfecf96SmrgLispReadEval(read_info *info)
17845dfecf96Smrg{
17855dfecf96Smrg    READ_ENTER();
17865dfecf96Smrg    int nodot = info->nodot;
17875dfecf96Smrg    LispObj *code;
17885dfecf96Smrg
17895dfecf96Smrg    info->nodot = info->level + 1;
17905dfecf96Smrg    code = LispDoRead(info);
17915dfecf96Smrg    info->nodot = nodot;
17925dfecf96Smrg
17935dfecf96Smrg    if (info->discard)
17945dfecf96Smrg	return (code);
17955dfecf96Smrg
17965dfecf96Smrg    if (INVALIDP(code))
17975dfecf96Smrg	READ_ERROR_INVARG();
17985dfecf96Smrg
17995dfecf96Smrg    return (EVAL(code));
18005dfecf96Smrg}
18015dfecf96Smrg
18025dfecf96Smrgstatic LispObj *
18035dfecf96SmrgLispReadComplex(read_info *info)
18045dfecf96Smrg{
18055dfecf96Smrg    READ_ENTER();
18065dfecf96Smrg    GC_ENTER();
18075dfecf96Smrg    int nodot = info->nodot;
18085dfecf96Smrg    LispObj *number, *arguments;
18095dfecf96Smrg
18105dfecf96Smrg    info->nodot = info->level + 1;
18115dfecf96Smrg    arguments = LispDoRead(info);
18125dfecf96Smrg    info->nodot = nodot;
18135dfecf96Smrg
18145dfecf96Smrg    /* form read */
18155dfecf96Smrg    if (info->discard)
18165dfecf96Smrg	return (arguments);
18175dfecf96Smrg
18185dfecf96Smrg    if (INVALIDP(arguments) || !CONSP(arguments))
18195dfecf96Smrg	READ_ERROR_INVARG();
18205dfecf96Smrg
18215dfecf96Smrg    GC_PROTECT(arguments);
18225dfecf96Smrg    number = APPLY(Ocomplex, arguments);
18235dfecf96Smrg    GC_LEAVE();
18245dfecf96Smrg
18255dfecf96Smrg    return (number);
18265dfecf96Smrg}
18275dfecf96Smrg
18285dfecf96Smrgstatic LispObj *
18295dfecf96SmrgLispReadPathname(read_info *info)
18305dfecf96Smrg{
18315dfecf96Smrg    READ_ENTER();
18325dfecf96Smrg    GC_ENTER();
18335dfecf96Smrg    int nodot = info->nodot;
18345dfecf96Smrg    LispObj *path, *arguments;
18355dfecf96Smrg
18365dfecf96Smrg    info->nodot = info->level + 1;
18375dfecf96Smrg    arguments = LispDoRead(info);
18385dfecf96Smrg    info->nodot = nodot;
18395dfecf96Smrg
18405dfecf96Smrg    /* form read */
18415dfecf96Smrg    if (info->discard)
18425dfecf96Smrg	return (arguments);
18435dfecf96Smrg
18445dfecf96Smrg    if (INVALIDP(arguments))
18455dfecf96Smrg	READ_ERROR_INVARG();
18465dfecf96Smrg
18475dfecf96Smrg    GC_PROTECT(arguments);
18485dfecf96Smrg    path = APPLY1(Oparse_namestring, arguments);
18495dfecf96Smrg    GC_LEAVE();
18505dfecf96Smrg
18515dfecf96Smrg    return (path);
18525dfecf96Smrg}
18535dfecf96Smrg
18545dfecf96Smrgstatic LispObj *
18555dfecf96SmrgLispReadStruct(read_info *info)
18565dfecf96Smrg{
18575dfecf96Smrg    READ_ENTER();
18585dfecf96Smrg    GC_ENTER();
18595dfecf96Smrg    int len, nodot = info->nodot;
18605dfecf96Smrg    char stk[128], *str;
18615dfecf96Smrg    LispObj *struc, *fields;
18625dfecf96Smrg
18635dfecf96Smrg    info->nodot = info->level + 1;
18645dfecf96Smrg    fields = LispDoRead(info);
18655dfecf96Smrg    info->nodot = nodot;
18665dfecf96Smrg
18675dfecf96Smrg    /* form read */
18685dfecf96Smrg    if (info->discard)
18695dfecf96Smrg	return (fields);
18705dfecf96Smrg
18715dfecf96Smrg    if (INVALIDP(fields) || !CONSP(fields) || !SYMBOLP(CAR(fields)))
18725dfecf96Smrg	READ_ERROR_INVARG();
18735dfecf96Smrg
18745dfecf96Smrg    GC_PROTECT(fields);
18755dfecf96Smrg
1876f14f4646Smrg    len = ATOMID(CAR(fields))->length;
18775dfecf96Smrg	   /* MAKE- */
18785dfecf96Smrg    if (len + 6 > sizeof(stk))
18795dfecf96Smrg	str = LispMalloc(len + 6);
18805dfecf96Smrg    else
18815dfecf96Smrg	str = stk;
1882f14f4646Smrg    sprintf(str, "MAKE-%s", ATOMID(CAR(fields))->value);
18835dfecf96Smrg    RPLACA(fields, ATOM(str));
18845dfecf96Smrg    if (str != stk)
18855dfecf96Smrg	LispFree(str);
18865dfecf96Smrg    struc = APPLY(Omake_struct, fields);
18875dfecf96Smrg    GC_LEAVE();
18885dfecf96Smrg
18895dfecf96Smrg    return (struc);
18905dfecf96Smrg}
18915dfecf96Smrg
18925dfecf96Smrg/* XXX This is broken, needs a rewritten as soon as true vector/arrays be
18935dfecf96Smrg * implemented. */
18945dfecf96Smrgstatic LispObj *
18955dfecf96SmrgLispReadArray(long dimensions, read_info *info)
18965dfecf96Smrg{
18975dfecf96Smrg    READ_ENTER();
18985dfecf96Smrg    GC_ENTER();
18995dfecf96Smrg    long count;
19005dfecf96Smrg    int nodot = info->nodot;
19015dfecf96Smrg    LispObj *arguments, *initial, *dim, *cons, *array, *data;
19025dfecf96Smrg
19035dfecf96Smrg    info->nodot = info->level + 1;
19045dfecf96Smrg    data = LispDoRead(info);
19055dfecf96Smrg    info->nodot = nodot;
19065dfecf96Smrg
19075dfecf96Smrg    /* form read */
19085dfecf96Smrg    if (info->discard)
19095dfecf96Smrg	return (data);
19105dfecf96Smrg
19115dfecf96Smrg    if (INVALIDP(data))
19125dfecf96Smrg	READ_ERROR_INVARG();
19135dfecf96Smrg
19145dfecf96Smrg    initial = Kinitial_contents;
19155dfecf96Smrg
19165dfecf96Smrg    dim = cons = NIL;
19175dfecf96Smrg    if (dimensions) {
19185dfecf96Smrg	LispObj *array;
19195dfecf96Smrg
19205dfecf96Smrg	for (count = 0, array = data; count < dimensions; count++) {
19215dfecf96Smrg	    long length;
19225dfecf96Smrg	    LispObj *item;
19235dfecf96Smrg
19245dfecf96Smrg	    if (!CONSP(array))
19255dfecf96Smrg		READ_ERROR0("bad array for given dimension");
19265dfecf96Smrg	    item = array;
19275dfecf96Smrg	    array = CAR(array);
19285dfecf96Smrg
19295dfecf96Smrg	    for (length = 0; CONSP(item); item = CDR(item), length++)
19305dfecf96Smrg		;
19315dfecf96Smrg
19325dfecf96Smrg	    if (dim == NIL) {
19335dfecf96Smrg		dim = cons = CONS(FIXNUM(length), NIL);
19345dfecf96Smrg		GC_PROTECT(dim);
19355dfecf96Smrg	    }
19365dfecf96Smrg	    else {
19375dfecf96Smrg		RPLACD(cons, CONS(FIXNUM(length), NIL));
19385dfecf96Smrg		cons = CDR(cons);
19395dfecf96Smrg	    }
19405dfecf96Smrg	}
19415dfecf96Smrg    }
19425dfecf96Smrg
19435dfecf96Smrg    arguments = CONS(dim, CONS(initial, CONS(data, NIL)));
19445dfecf96Smrg    GC_PROTECT(arguments);
19455dfecf96Smrg    array = APPLY(Omake_array, arguments);
19465dfecf96Smrg    GC_LEAVE();
19475dfecf96Smrg
19485dfecf96Smrg    return (array);
19495dfecf96Smrg}
19505dfecf96Smrg
19515dfecf96Smrgstatic LispObj *
19525dfecf96SmrgLispReadFeature(int with, read_info *info)
19535dfecf96Smrg{
19545dfecf96Smrg    READ_ENTER();
19555dfecf96Smrg    LispObj *status;
19565dfecf96Smrg    LispObj *feature = LispDoRead(info);
19575dfecf96Smrg
19585dfecf96Smrg    /* form read */
19595dfecf96Smrg    if (info->discard)
19605dfecf96Smrg	return (feature);
19615dfecf96Smrg
19625dfecf96Smrg    if (INVALIDP(feature))
19635dfecf96Smrg	READ_ERROR_INVARG();
19645dfecf96Smrg
19655dfecf96Smrg    /* paranoia check, features must be a list, possibly empty */
19665dfecf96Smrg    if (!CONSP(FEATURES) && FEATURES != NIL)
19675dfecf96Smrg	READ_ERROR1("%s is not a list", STROBJ(FEATURES));
19685dfecf96Smrg
19695dfecf96Smrg    status = LispEvalFeature(feature);
19705dfecf96Smrg
19715dfecf96Smrg    if (with) {
19725dfecf96Smrg	if (status == T)
19735dfecf96Smrg	    return (LispDoRead(info));
19745dfecf96Smrg
19755dfecf96Smrg	/* need to use the field discard because the following expression
19765dfecf96Smrg	 * may be #.FORM or #,FORM or any other form that may generate
19775dfecf96Smrg	 * side effects */
19785dfecf96Smrg	info->discard = 1;
19795dfecf96Smrg	LispDoRead(info);
19805dfecf96Smrg	info->discard = 0;
19815dfecf96Smrg
19825dfecf96Smrg	return (LispDoRead(info));
19835dfecf96Smrg    }
19845dfecf96Smrg
19855dfecf96Smrg    if (status == NIL)
19865dfecf96Smrg	return (LispDoRead(info));
19875dfecf96Smrg
19885dfecf96Smrg    info->discard = 1;
19895dfecf96Smrg    LispDoRead(info);
19905dfecf96Smrg    info->discard = 0;
19915dfecf96Smrg
19925dfecf96Smrg    return (LispDoRead(info));
19935dfecf96Smrg}
19945dfecf96Smrg
19955dfecf96Smrg/*
19965dfecf96Smrg * A very simple eval loop with AND, NOT, and OR functions for testing
19975dfecf96Smrg * the available features.
19985dfecf96Smrg */
19995dfecf96Smrgstatic LispObj *
20005dfecf96SmrgLispEvalFeature(LispObj *feature)
20015dfecf96Smrg{
20025dfecf96Smrg    READ_ENTER();
20035dfecf96Smrg    Atom_id test;
20045dfecf96Smrg    LispObj *object;
20055dfecf96Smrg
20065dfecf96Smrg    if (CONSP(feature)) {
20075dfecf96Smrg	LispObj *function = CAR(feature), *arguments = CDR(feature);
20085dfecf96Smrg
20095dfecf96Smrg	if (!SYMBOLP(function))
20105dfecf96Smrg	    READ_ERROR1("bad feature test function %s", STROBJ(function));
20115dfecf96Smrg	if (!CONSP(arguments))
20125dfecf96Smrg	    READ_ERROR1("bad feature test arguments %s", STROBJ(arguments));
20135dfecf96Smrg	test = ATOMID(function);
20145dfecf96Smrg	if (test == Sand) {
20155dfecf96Smrg	    for (; CONSP(arguments); arguments = CDR(arguments)) {
20165dfecf96Smrg		if (LispEvalFeature(CAR(arguments)) == NIL)
20175dfecf96Smrg		    return (NIL);
20185dfecf96Smrg	    }
20195dfecf96Smrg	    return (T);
20205dfecf96Smrg	}
20215dfecf96Smrg	else if (test == Sor) {
20225dfecf96Smrg	    for (; CONSP(arguments); arguments = CDR(arguments)) {
20235dfecf96Smrg		if (LispEvalFeature(CAR(arguments)) == T)
20245dfecf96Smrg		    return (T);
20255dfecf96Smrg	    }
20265dfecf96Smrg	    return (NIL);
20275dfecf96Smrg	}
20285dfecf96Smrg	else if (test == Snot) {
20295dfecf96Smrg	    if (CONSP(CDR(arguments)))
20305dfecf96Smrg		READ_ERROR0("too many arguments to NOT");
20315dfecf96Smrg
20325dfecf96Smrg	    return (LispEvalFeature(CAR(arguments)) == NIL ? T : NIL);
20335dfecf96Smrg	}
20345dfecf96Smrg	else
20355dfecf96Smrg	    READ_ERROR1("unimplemented feature test function %s", test);
20365dfecf96Smrg    }
20375dfecf96Smrg
20385dfecf96Smrg    if (KEYWORDP(feature))
20395dfecf96Smrg	feature = feature->data.quote;
20405dfecf96Smrg    else if (!SYMBOLP(feature))
20415dfecf96Smrg	READ_ERROR1("bad feature specification %s", STROBJ(feature));
20425dfecf96Smrg
20435dfecf96Smrg    test = ATOMID(feature);
20445dfecf96Smrg
20455dfecf96Smrg    for (object = FEATURES; CONSP(object); object = CDR(object)) {
20465dfecf96Smrg	/* paranoia check, elements in the feature list must ge keywords */
20475dfecf96Smrg	if (!KEYWORDP(CAR(object)))
20485dfecf96Smrg	    READ_ERROR1("%s is not a keyword", STROBJ(CAR(object)));
20495dfecf96Smrg	if (ATOMID(CAR(object)) == test)
20505dfecf96Smrg	    return (T);
20515dfecf96Smrg    }
20525dfecf96Smrg
20535dfecf96Smrg    /* unknown feature */
20545dfecf96Smrg    return (NIL);
20555dfecf96Smrg}
2056