15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2001 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/struct.c,v 1.22tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "lisp/struct.h"
335dfecf96Smrg
345dfecf96Smrg/*
355dfecf96Smrg * Prototypes
365dfecf96Smrg */
375dfecf96Smrgstatic LispObj *LispStructAccessOrStore(LispBuiltin*, int);
385dfecf96Smrg
395dfecf96Smrg/*
405dfecf96Smrg * Initialization
415dfecf96Smrg */
425dfecf96SmrgLispObj *Omake_struct, *Ostruct_access, *Ostruct_store, *Ostruct_type;
435dfecf96Smrg
445dfecf96SmrgAtom_id Smake_struct, Sstruct_access, Sstruct_store, Sstruct_type;
455dfecf96Smrg
465dfecf96Smrg/*
475dfecf96Smrg * Implementation
485dfecf96Smrg */
495dfecf96SmrgLispObj *
505dfecf96SmrgLisp_Defstruct(LispBuiltin *builtin)
515dfecf96Smrg/*
525dfecf96Smrg defstruct name &rest description
535dfecf96Smrg */
545dfecf96Smrg{
555dfecf96Smrg    int intern;
565dfecf96Smrg    LispAtom *atom;
575dfecf96Smrg    int i, size, length, slength;
58f14f4646Smrg    char *name, *strname;
595dfecf96Smrg    LispObj *list, *cons, *object, *definition, *documentation;
605dfecf96Smrg
615dfecf96Smrg    LispObj *oname, *description;
625dfecf96Smrg
635dfecf96Smrg    description = ARGUMENT(1);
645dfecf96Smrg    oname = ARGUMENT(0);
655dfecf96Smrg
665dfecf96Smrg    CHECK_SYMBOL(oname);
675dfecf96Smrg
68f14f4646Smrg    strname = ATOMID(oname)->value;
69f14f4646Smrg    length  = ATOMID(oname)->length;
705dfecf96Smrg
715dfecf96Smrg	    /* MAKE- */
725dfecf96Smrg    size = length + 6;
735dfecf96Smrg    name = LispMalloc(size);
745dfecf96Smrg
755dfecf96Smrg    sprintf(name, "MAKE-%s", strname);
765dfecf96Smrg    atom = (object = ATOM(name))->data.atom;
775dfecf96Smrg
785dfecf96Smrg    if (atom->a_builtin)
795dfecf96Smrg	LispDestroy("%s: %s cannot be a structure name",
805dfecf96Smrg		    STRFUN(builtin), STROBJ(oname));
815dfecf96Smrg
825dfecf96Smrg    intern = !atom->ext;
835dfecf96Smrg
845dfecf96Smrg    if (CONSP(description) && STRINGP(CAR(description))) {
855dfecf96Smrg	documentation = CAR(description);
865dfecf96Smrg	description = CDR(description);
875dfecf96Smrg    }
885dfecf96Smrg    else
895dfecf96Smrg	documentation = NIL;
905dfecf96Smrg
915dfecf96Smrg    /* get structure fields and default values */
925dfecf96Smrg    for (list = description; CONSP(list); list = CDR(list)) {
935dfecf96Smrg	object = CAR(list);
945dfecf96Smrg
955dfecf96Smrg	cons = list;
965dfecf96Smrg	if (CONSP(object)) {
975dfecf96Smrg	    if ((CONSP(CDR(object)) && CDR(CDR(object)) != NIL) ||
985dfecf96Smrg		(!CONSP(CDR(object)) && CDR(object) != NIL))
995dfecf96Smrg	    LispDestroy("%s: bad initialization %s",
1005dfecf96Smrg			STRFUN(builtin), STROBJ(object));
1015dfecf96Smrg	    cons = object;
1025dfecf96Smrg	    object = CAR(object);
1035dfecf96Smrg	}
104f14f4646Smrg	if (!SYMBOLP(object) || strcmp(ATOMID(object)->value, "P") == 0)
1055dfecf96Smrg	    /* p is invalid as a field name due to `type'-p */
1065dfecf96Smrg	    LispDestroy("%s: %s cannot be a field for %s",
107f14f4646Smrg			STRFUN(builtin), STROBJ(object), ATOMID(oname)->value);
1085dfecf96Smrg
1095dfecf96Smrg	if (!KEYWORDP(object))
110f14f4646Smrg	    CAR(cons) = KEYWORD(ATOMID(object)->value);
1115dfecf96Smrg
1125dfecf96Smrg	/* check for repeated field names */
1135dfecf96Smrg	for (object = description; object != list; object = CDR(object)) {
1145dfecf96Smrg	    LispObj *left = CAR(object), *right = CAR(list);
1155dfecf96Smrg
1165dfecf96Smrg	    if (CONSP(left))
1175dfecf96Smrg		left = CAR(left);
1185dfecf96Smrg	    if (CONSP(right))
1195dfecf96Smrg		right = CAR(right);
1205dfecf96Smrg
1215dfecf96Smrg	    if (ATOMID(left) == ATOMID(right))
1225dfecf96Smrg		LispDestroy("%s: only one slot named %s allowed",
1235dfecf96Smrg			    STRFUN(builtin), STROBJ(left));
1245dfecf96Smrg	}
1255dfecf96Smrg    }
1265dfecf96Smrg
1275dfecf96Smrg    /* atom should not have been modified */
1285dfecf96Smrg    definition = CONS(oname, description);
1295dfecf96Smrg    LispSetAtomStructProperty(atom, definition, STRUCT_CONSTRUCTOR);
1305dfecf96Smrg    if (!intern)
1315dfecf96Smrg	LispExportSymbol(object);
1325dfecf96Smrg
1335dfecf96Smrg    atom = oname->data.atom;
1345dfecf96Smrg    if (atom->a_defstruct)
1355dfecf96Smrg	LispWarning("%s: structure %s is being redefined",
1365dfecf96Smrg		    STRFUN(builtin), strname);
1375dfecf96Smrg    LispSetAtomStructProperty(atom, definition, STRUCT_NAME);
1385dfecf96Smrg
1395dfecf96Smrg    sprintf(name, "%s-P", strname);
1405dfecf96Smrg    atom = (object = ATOM(name))->data.atom;
1415dfecf96Smrg    LispSetAtomStructProperty(atom, definition, STRUCT_CHECK);
1425dfecf96Smrg    if (!intern)
1435dfecf96Smrg	LispExportSymbol(object);
1445dfecf96Smrg
1455dfecf96Smrg    for (i = 0, list = description; CONSP(list); i++, list = CDR(list)) {
146f14f4646Smrg	Atom_id id;
147f14f4646Smrg
1485dfecf96Smrg	if (CONSP(CAR(list)))
149f14f4646Smrg	    id = ATOMID(CAR(CAR(list)));
1505dfecf96Smrg	else
151f14f4646Smrg	    id = ATOMID(CAR(list));
152f14f4646Smrg	slength = id->length;
1535dfecf96Smrg	if (length + slength + 2 > size) {
1545dfecf96Smrg	    size = length + slength + 2;
1555dfecf96Smrg	    name = LispRealloc(name, size);
1565dfecf96Smrg	}
157f14f4646Smrg	sprintf(name, "%s-%s", strname, id->value);
1585dfecf96Smrg	atom = (object = ATOM(name))->data.atom;
1595dfecf96Smrg	LispSetAtomStructProperty(atom, definition, i);
1605dfecf96Smrg	if (!intern)
1615dfecf96Smrg	    LispExportSymbol(object);
1625dfecf96Smrg    }
1635dfecf96Smrg
1645dfecf96Smrg    LispFree(name);
1655dfecf96Smrg
1665dfecf96Smrg    if (documentation != NIL)
1675dfecf96Smrg	LispAddDocumentation(oname, documentation, LispDocStructure);
1685dfecf96Smrg
1695dfecf96Smrg    return (oname);
1705dfecf96Smrg}
1715dfecf96Smrg
1725dfecf96Smrg/* helper functions
1735dfecf96Smrg *	DONT explicitly call them. Non standard functions.
1745dfecf96Smrg */
1755dfecf96SmrgLispObj *
1765dfecf96SmrgLisp_XeditMakeStruct(LispBuiltin *builtin)
1775dfecf96Smrg/*
1785dfecf96Smrg lisp::make-struct atom &rest init
1795dfecf96Smrg */
1805dfecf96Smrg{
1815dfecf96Smrg    int nfld, ncvt, length = lisp__data.protect.length;
1825dfecf96Smrg    LispAtom *atom = NULL;
1835dfecf96Smrg
1845dfecf96Smrg    LispObj *definition, *object, *field, *fields, *value = NIL, *cons, *list;
1855dfecf96Smrg    LispObj *struc, *init;
1865dfecf96Smrg
1875dfecf96Smrg    init = ARGUMENT(1);
1885dfecf96Smrg    struc = ARGUMENT(0);
1895dfecf96Smrg
1905dfecf96Smrg    field = cons = NIL;
1915dfecf96Smrg    if (!POINTERP(struc) ||
1925dfecf96Smrg	!(XSYMBOLP(struc) || XFUNCTIONP(struc)) ||
1935dfecf96Smrg	(atom = struc->data.atom)->a_defstruct == 0 ||
1945dfecf96Smrg	 atom->property->structure.function != STRUCT_CONSTRUCTOR)
1955dfecf96Smrg	LispDestroy("%s: invalid constructor %s",
1965dfecf96Smrg		    STRFUN(builtin), STROBJ(struc));
1975dfecf96Smrg    definition = atom->property->structure.definition;
1985dfecf96Smrg
1995dfecf96Smrg    ncvt = nfld = 0;
2005dfecf96Smrg    fields = NIL;
2015dfecf96Smrg
2025dfecf96Smrg    /* check for errors in argument list */
2035dfecf96Smrg    for (list = init, nfld = 0; CONSP(list); list = CDR(list)) {
2045dfecf96Smrg	CHECK_KEYWORD(CAR(list));
2055dfecf96Smrg	if (!CONSP(CDR(list)))
2065dfecf96Smrg	    LispDestroy("%s: values must be provided as pairs",
207f14f4646Smrg			ATOMID(struc)->value);
2085dfecf96Smrg	nfld++;
2095dfecf96Smrg	list = CDR(list);
2105dfecf96Smrg    }
2115dfecf96Smrg
2125dfecf96Smrg    /* create structure, CAR(definition) is structure name */
2135dfecf96Smrg    for (list = CDR(definition); CONSP(list); list = CDR(list)) {
2145dfecf96Smrg	Atom_id id;
2155dfecf96Smrg	LispObj *defvalue = NIL;
2165dfecf96Smrg
2175dfecf96Smrg	++nfld;
2185dfecf96Smrg	field = CAR(list);
2195dfecf96Smrg	if (CONSP(field)) {
2205dfecf96Smrg	    /* if default value provided */
2215dfecf96Smrg	    if (CONSP(CDR(field)))
2225dfecf96Smrg		defvalue = CAR(CDR(field));
2235dfecf96Smrg	    field = CAR(field);
2245dfecf96Smrg	}
2255dfecf96Smrg	id = ATOMID(field);
2265dfecf96Smrg
2275dfecf96Smrg	for (object = init; CONSP(object); object = CDR(object)) {
2285dfecf96Smrg	    /* field is a keyword, test above checked it */
2295dfecf96Smrg	    field = CAR(object);
2305dfecf96Smrg	    if (id == ATOMID(field)) {
2315dfecf96Smrg		/* value provided */
2325dfecf96Smrg		value = CAR(CDR(object));
2335dfecf96Smrg		ncvt++;
2345dfecf96Smrg		break;
2355dfecf96Smrg	    }
2365dfecf96Smrg	    object = CDR(object);
2375dfecf96Smrg	}
2385dfecf96Smrg
2395dfecf96Smrg	/* if no initialization given */
2405dfecf96Smrg	if (!CONSP(object)) {
2415dfecf96Smrg	    /* if default value in structure definition */
2425dfecf96Smrg	    if (defvalue != NIL)
2435dfecf96Smrg		value = EVAL(defvalue);
2445dfecf96Smrg	    else
2455dfecf96Smrg		value = NIL;
2465dfecf96Smrg	}
2475dfecf96Smrg
2485dfecf96Smrg	if (fields == NIL) {
2495dfecf96Smrg	    fields = cons = CONS(value, NIL);
2505dfecf96Smrg	    if (length + 1 >= lisp__data.protect.space)
2515dfecf96Smrg		LispMoreProtects();
2525dfecf96Smrg	    lisp__data.protect.objects[lisp__data.protect.length++] = fields;
2535dfecf96Smrg	}
2545dfecf96Smrg	else {
2555dfecf96Smrg	    RPLACD(cons, CONS(value, NIL));
2565dfecf96Smrg	    cons = CDR(cons);
2575dfecf96Smrg	}
2585dfecf96Smrg    }
2595dfecf96Smrg
2605dfecf96Smrg    /* if not enough arguments were converted, need to check because
2615dfecf96Smrg     * it is acceptable to set a field more than once, but in that case,
2625dfecf96Smrg     * only the first value will be used. */
2635dfecf96Smrg    if (nfld > ncvt) {
2645dfecf96Smrg	for (list = init; CONSP(list); list = CDR(list)) {
2655dfecf96Smrg	    Atom_id id = ATOMID(CAR(list));
2665dfecf96Smrg
2675dfecf96Smrg	    for (object = CDR(definition); CONSP(object);
2685dfecf96Smrg		 object = CDR(object)) {
2695dfecf96Smrg		field = CAR(object);
2705dfecf96Smrg		if (CONSP(field))
2715dfecf96Smrg		    field = CAR(field);
2725dfecf96Smrg		if (ATOMID(field) == id)
2735dfecf96Smrg		    break;
2745dfecf96Smrg	    }
2755dfecf96Smrg	    if (!CONSP(object))
2765dfecf96Smrg		LispDestroy("%s: %s is not a field for %s",
277f14f4646Smrg			    ATOMID(struc)->value, STROBJ(CAR(list)),
278f14f4646Smrg			    ATOMID(CAR(definition))->value);
2795dfecf96Smrg	    list = CDR(list);
2805dfecf96Smrg	}
2815dfecf96Smrg    }
2825dfecf96Smrg
2835dfecf96Smrg    lisp__data.protect.length = length;
2845dfecf96Smrg
2855dfecf96Smrg    return (STRUCT(fields, definition));
2865dfecf96Smrg}
2875dfecf96Smrg
2885dfecf96Smrgstatic LispObj *
2895dfecf96SmrgLispStructAccessOrStore(LispBuiltin *builtin, int store)
2905dfecf96Smrg/*
2915dfecf96Smrg lisp::struct-access atom struct
2925dfecf96Smrg lisp::struct-store atom struct value
2935dfecf96Smrg */
2945dfecf96Smrg{
2955dfecf96Smrg    long offset;
2965dfecf96Smrg    LispAtom *atom;
2975dfecf96Smrg    LispObj *definition, *list;
2985dfecf96Smrg
2995dfecf96Smrg    LispObj *name, *struc, *value = NIL;
3005dfecf96Smrg
3015dfecf96Smrg    if (store)
3025dfecf96Smrg	value = ARGUMENT(2);
3035dfecf96Smrg    struc = ARGUMENT(1);
3045dfecf96Smrg    name = ARGUMENT(0);
3055dfecf96Smrg
3065dfecf96Smrg    if (!POINTERP(name) ||
3075dfecf96Smrg	!(XSYMBOLP(name) || XFUNCTIONP(name)) ||
3085dfecf96Smrg	(atom = name->data.atom)->a_defstruct == 0 ||
3095dfecf96Smrg	(offset = atom->property->structure.function) < 0) {
3105dfecf96Smrg	LispDestroy("%s: invalid argument %s",
3115dfecf96Smrg		    STRFUN(builtin), STROBJ(name));
3125dfecf96Smrg	/*NOTREACHED*/
3135dfecf96Smrg	offset = 0;
3145dfecf96Smrg	atom = NULL;
3155dfecf96Smrg    }
3165dfecf96Smrg    definition = atom->property->structure.definition;
3175dfecf96Smrg
3185dfecf96Smrg    /* check if the object is of the required type */
3195dfecf96Smrg    if (!STRUCTP(struc) || struc->data.struc.def != definition)
3205dfecf96Smrg	LispDestroy("%s: %s is not a %s",
321f14f4646Smrg		    ATOMID(name)->value, STROBJ(struc), ATOMID(CAR(definition))->value);
3225dfecf96Smrg
3235dfecf96Smrg    for (list = struc->data.struc.fields; offset; list = CDR(list), offset--)
3245dfecf96Smrg	;
3255dfecf96Smrg
3265dfecf96Smrg    return (store ? RPLACA(list, value) : CAR(list));
3275dfecf96Smrg}
3285dfecf96Smrg
3295dfecf96SmrgLispObj *
3305dfecf96SmrgLisp_XeditStructAccess(LispBuiltin *builtin)
3315dfecf96Smrg/*
3325dfecf96Smrg lisp::struct-access atom struct
3335dfecf96Smrg */
3345dfecf96Smrg{
3355dfecf96Smrg    return (LispStructAccessOrStore(builtin, 0));
3365dfecf96Smrg}
3375dfecf96Smrg
3385dfecf96SmrgLispObj *
3395dfecf96SmrgLisp_XeditStructStore(LispBuiltin *builtin)
3405dfecf96Smrg/*
3415dfecf96Smrg lisp::struct-store atom struct value
3425dfecf96Smrg */
3435dfecf96Smrg{
3445dfecf96Smrg    return (LispStructAccessOrStore(builtin, 1));
3455dfecf96Smrg}
3465dfecf96Smrg
3475dfecf96SmrgLispObj *
3485dfecf96SmrgLisp_XeditStructType(LispBuiltin *builtin)
3495dfecf96Smrg/*
3505dfecf96Smrg lisp::struct-type atom struct
3515dfecf96Smrg */
3525dfecf96Smrg{
3535dfecf96Smrg    LispAtom *atom = NULL;
3545dfecf96Smrg
3555dfecf96Smrg    LispObj *definition, *struc, *name;
3565dfecf96Smrg
3575dfecf96Smrg    struc = ARGUMENT(1);
3585dfecf96Smrg    name = ARGUMENT(0);
3595dfecf96Smrg
3605dfecf96Smrg    if (!POINTERP(name) ||
3615dfecf96Smrg	!(XSYMBOLP(name) || XFUNCTIONP(name)) ||
3625dfecf96Smrg	(atom = name->data.atom)->a_defstruct == 0 ||
3635dfecf96Smrg	(atom->property->structure.function != STRUCT_CHECK))
3645dfecf96Smrg	LispDestroy("%s: invalid argument %s",
3655dfecf96Smrg		    STRFUN(builtin), STROBJ(name));
3665dfecf96Smrg    definition = atom->property->structure.definition;
3675dfecf96Smrg
3685dfecf96Smrg    /* check if the object is of the required type */
3695dfecf96Smrg    if (STRUCTP(struc) && struc->data.struc.def == definition)
3705dfecf96Smrg	return (T);
3715dfecf96Smrg
3725dfecf96Smrg    return (NIL);
3735dfecf96Smrg}
374