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