/* * Copyright (c) 2001 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the XFree86 Project shall * not be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from the * XFree86 Project. * * Author: Paulo César Pereira de Andrade */ /* $XFree86$ */ #include "lisp/struct.h" /* * Prototypes */ static LispObj *LispStructAccessOrStore(LispBuiltin*, int); /* * Initialization */ LispObj *Omake_struct, *Ostruct_access, *Ostruct_store, *Ostruct_type; Atom_id Smake_struct, Sstruct_access, Sstruct_store, Sstruct_type; /* * Implementation */ LispObj * Lisp_Defstruct(LispBuiltin *builtin) /* defstruct name &rest description */ { int intern; LispAtom *atom; int i, size, length, slength; char *name, *strname, *sname; LispObj *list, *cons, *object, *definition, *documentation; LispObj *oname, *description; description = ARGUMENT(1); oname = ARGUMENT(0); CHECK_SYMBOL(oname); strname = ATOMID(oname); length = strlen(strname); /* MAKE- */ size = length + 6; name = LispMalloc(size); sprintf(name, "MAKE-%s", strname); atom = (object = ATOM(name))->data.atom; if (atom->a_builtin) LispDestroy("%s: %s cannot be a structure name", STRFUN(builtin), STROBJ(oname)); intern = !atom->ext; if (CONSP(description) && STRINGP(CAR(description))) { documentation = CAR(description); description = CDR(description); } else documentation = NIL; /* get structure fields and default values */ for (list = description; CONSP(list); list = CDR(list)) { object = CAR(list); cons = list; if (CONSP(object)) { if ((CONSP(CDR(object)) && CDR(CDR(object)) != NIL) || (!CONSP(CDR(object)) && CDR(object) != NIL)) LispDestroy("%s: bad initialization %s", STRFUN(builtin), STROBJ(object)); cons = object; object = CAR(object); } if (!SYMBOLP(object) || strcmp(ATOMID(object), "P") == 0) /* p is invalid as a field name due to `type'-p */ LispDestroy("%s: %s cannot be a field for %s", STRFUN(builtin), STROBJ(object), ATOMID(oname)); if (!KEYWORDP(object)) CAR(cons) = KEYWORD(ATOMID(object)); /* check for repeated field names */ for (object = description; object != list; object = CDR(object)) { LispObj *left = CAR(object), *right = CAR(list); if (CONSP(left)) left = CAR(left); if (CONSP(right)) right = CAR(right); if (ATOMID(left) == ATOMID(right)) LispDestroy("%s: only one slot named %s allowed", STRFUN(builtin), STROBJ(left)); } } /* atom should not have been modified */ definition = CONS(oname, description); LispSetAtomStructProperty(atom, definition, STRUCT_CONSTRUCTOR); if (!intern) LispExportSymbol(object); atom = oname->data.atom; if (atom->a_defstruct) LispWarning("%s: structure %s is being redefined", STRFUN(builtin), strname); LispSetAtomStructProperty(atom, definition, STRUCT_NAME); sprintf(name, "%s-P", strname); atom = (object = ATOM(name))->data.atom; LispSetAtomStructProperty(atom, definition, STRUCT_CHECK); if (!intern) LispExportSymbol(object); for (i = 0, list = description; CONSP(list); i++, list = CDR(list)) { if (CONSP(CAR(list))) sname = ATOMID(CAR(CAR(list))); else sname = ATOMID(CAR(list)); slength = strlen(sname); if (length + slength + 2 > size) { size = length + slength + 2; name = LispRealloc(name, size); } sprintf(name, "%s-%s", strname, sname); atom = (object = ATOM(name))->data.atom; LispSetAtomStructProperty(atom, definition, i); if (!intern) LispExportSymbol(object); } LispFree(name); if (documentation != NIL) LispAddDocumentation(oname, documentation, LispDocStructure); return (oname); } /* helper functions * DONT explicitly call them. Non standard functions. */ LispObj * Lisp_XeditMakeStruct(LispBuiltin *builtin) /* lisp::make-struct atom &rest init */ { int nfld, ncvt, length = lisp__data.protect.length; LispAtom *atom = NULL; LispObj *definition, *object, *field, *fields, *value = NIL, *cons, *list; LispObj *struc, *init; init = ARGUMENT(1); struc = ARGUMENT(0); field = cons = NIL; if (!POINTERP(struc) || !(XSYMBOLP(struc) || XFUNCTIONP(struc)) || (atom = struc->data.atom)->a_defstruct == 0 || atom->property->structure.function != STRUCT_CONSTRUCTOR) LispDestroy("%s: invalid constructor %s", STRFUN(builtin), STROBJ(struc)); definition = atom->property->structure.definition; ncvt = nfld = 0; fields = NIL; /* check for errors in argument list */ for (list = init, nfld = 0; CONSP(list); list = CDR(list)) { CHECK_KEYWORD(CAR(list)); if (!CONSP(CDR(list))) LispDestroy("%s: values must be provided as pairs", ATOMID(struc)); nfld++; list = CDR(list); } /* create structure, CAR(definition) is structure name */ for (list = CDR(definition); CONSP(list); list = CDR(list)) { Atom_id id; LispObj *defvalue = NIL; ++nfld; field = CAR(list); if (CONSP(field)) { /* if default value provided */ if (CONSP(CDR(field))) defvalue = CAR(CDR(field)); field = CAR(field); } id = ATOMID(field); for (object = init; CONSP(object); object = CDR(object)) { /* field is a keyword, test above checked it */ field = CAR(object); if (id == ATOMID(field)) { /* value provided */ value = CAR(CDR(object)); ncvt++; break; } object = CDR(object); } /* if no initialization given */ if (!CONSP(object)) { /* if default value in structure definition */ if (defvalue != NIL) value = EVAL(defvalue); else value = NIL; } if (fields == NIL) { fields = cons = CONS(value, NIL); if (length + 1 >= lisp__data.protect.space) LispMoreProtects(); lisp__data.protect.objects[lisp__data.protect.length++] = fields; } else { RPLACD(cons, CONS(value, NIL)); cons = CDR(cons); } } /* if not enough arguments were converted, need to check because * it is acceptable to set a field more than once, but in that case, * only the first value will be used. */ if (nfld > ncvt) { for (list = init; CONSP(list); list = CDR(list)) { Atom_id id = ATOMID(CAR(list)); for (object = CDR(definition); CONSP(object); object = CDR(object)) { field = CAR(object); if (CONSP(field)) field = CAR(field); if (ATOMID(field) == id) break; } if (!CONSP(object)) LispDestroy("%s: %s is not a field for %s", ATOMID(struc), STROBJ(CAR(list)), ATOMID(CAR(definition))); list = CDR(list); } } lisp__data.protect.length = length; return (STRUCT(fields, definition)); } static LispObj * LispStructAccessOrStore(LispBuiltin *builtin, int store) /* lisp::struct-access atom struct lisp::struct-store atom struct value */ { long offset; LispAtom *atom; LispObj *definition, *list; LispObj *name, *struc, *value = NIL; if (store) value = ARGUMENT(2); struc = ARGUMENT(1); name = ARGUMENT(0); if (!POINTERP(name) || !(XSYMBOLP(name) || XFUNCTIONP(name)) || (atom = name->data.atom)->a_defstruct == 0 || (offset = atom->property->structure.function) < 0) { LispDestroy("%s: invalid argument %s", STRFUN(builtin), STROBJ(name)); /*NOTREACHED*/ offset = 0; atom = NULL; } definition = atom->property->structure.definition; /* check if the object is of the required type */ if (!STRUCTP(struc) || struc->data.struc.def != definition) LispDestroy("%s: %s is not a %s", ATOMID(name), STROBJ(struc), ATOMID(CAR(definition))); for (list = struc->data.struc.fields; offset; list = CDR(list), offset--) ; return (store ? RPLACA(list, value) : CAR(list)); } LispObj * Lisp_XeditStructAccess(LispBuiltin *builtin) /* lisp::struct-access atom struct */ { return (LispStructAccessOrStore(builtin, 0)); } LispObj * Lisp_XeditStructStore(LispBuiltin *builtin) /* lisp::struct-store atom struct value */ { return (LispStructAccessOrStore(builtin, 1)); } LispObj * Lisp_XeditStructType(LispBuiltin *builtin) /* lisp::struct-type atom struct */ { LispAtom *atom = NULL; LispObj *definition, *struc, *name; struc = ARGUMENT(1); name = ARGUMENT(0); if (!POINTERP(name) || !(XSYMBOLP(name) || XFUNCTIONP(name)) || (atom = name->data.atom)->a_defstruct == 0 || (atom->property->structure.function != STRUCT_CHECK)) LispDestroy("%s: invalid argument %s", STRFUN(builtin), STROBJ(name)); definition = atom->property->structure.definition; /* check if the object is of the required type */ if (STRUCTP(struc) && struc->data.struc.def == definition) return (T); return (NIL); }