Home | History | Annotate | Line # | Download | only in lisp
      1 /*
      2  * Copyright (c) 2001 by The XFree86 Project, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  *
     22  * Except as contained in this notice, the name of the XFree86 Project shall
     23  * not be used in advertising or otherwise to promote the sale, use or other
     24  * dealings in this Software without prior written authorization from the
     25  * XFree86 Project.
     26  *
     27  * Author: Paulo Csar Pereira de Andrade
     28  */
     29 
     30 /* $XFree86: xc/programs/xedit/lisp/struct.c,v 1.22tsi Exp $ */
     31 
     32 #include "lisp/struct.h"
     33 
     34 /*
     35  * Prototypes
     36  */
     37 static LispObj *LispStructAccessOrStore(LispBuiltin*, int);
     38 
     39 /*
     40  * Initialization
     41  */
     42 LispObj *Omake_struct, *Ostruct_access, *Ostruct_store, *Ostruct_type;
     43 
     44 Atom_id Smake_struct, Sstruct_access, Sstruct_store, Sstruct_type;
     45 
     46 /*
     47  * Implementation
     48  */
     49 LispObj *
     50 Lisp_Defstruct(LispBuiltin *builtin)
     51 /*
     52  defstruct name &rest description
     53  */
     54 {
     55     int intern;
     56     LispAtom *atom;
     57     int i, size, length, slength;
     58     char *name, *strname;
     59     LispObj *list, *cons, *object, *definition, *documentation;
     60 
     61     LispObj *oname, *description;
     62 
     63     description = ARGUMENT(1);
     64     oname = ARGUMENT(0);
     65 
     66     CHECK_SYMBOL(oname);
     67 
     68     strname = ATOMID(oname)->value;
     69     length  = ATOMID(oname)->length;
     70 
     71 	    /* MAKE- */
     72     size = length + 6;
     73     name = LispMalloc(size);
     74 
     75     sprintf(name, "MAKE-%s", strname);
     76     atom = (object = ATOM(name))->data.atom;
     77 
     78     if (atom->a_builtin)
     79 	LispDestroy("%s: %s cannot be a structure name",
     80 		    STRFUN(builtin), STROBJ(oname));
     81 
     82     intern = !atom->ext;
     83 
     84     if (CONSP(description) && STRINGP(CAR(description))) {
     85 	documentation = CAR(description);
     86 	description = CDR(description);
     87     }
     88     else
     89 	documentation = NIL;
     90 
     91     /* get structure fields and default values */
     92     for (list = description; CONSP(list); list = CDR(list)) {
     93 	object = CAR(list);
     94 
     95 	cons = list;
     96 	if (CONSP(object)) {
     97 	    if ((CONSP(CDR(object)) && CDR(CDR(object)) != NIL) ||
     98 		(!CONSP(CDR(object)) && CDR(object) != NIL))
     99 	    LispDestroy("%s: bad initialization %s",
    100 			STRFUN(builtin), STROBJ(object));
    101 	    cons = object;
    102 	    object = CAR(object);
    103 	}
    104 	if (!SYMBOLP(object) || strcmp(ATOMID(object)->value, "P") == 0)
    105 	    /* p is invalid as a field name due to `type'-p */
    106 	    LispDestroy("%s: %s cannot be a field for %s",
    107 			STRFUN(builtin), STROBJ(object), ATOMID(oname)->value);
    108 
    109 	if (!KEYWORDP(object))
    110 	    CAR(cons) = KEYWORD(ATOMID(object)->value);
    111 
    112 	/* check for repeated field names */
    113 	for (object = description; object != list; object = CDR(object)) {
    114 	    LispObj *left = CAR(object), *right = CAR(list);
    115 
    116 	    if (CONSP(left))
    117 		left = CAR(left);
    118 	    if (CONSP(right))
    119 		right = CAR(right);
    120 
    121 	    if (ATOMID(left) == ATOMID(right))
    122 		LispDestroy("%s: only one slot named %s allowed",
    123 			    STRFUN(builtin), STROBJ(left));
    124 	}
    125     }
    126 
    127     /* atom should not have been modified */
    128     definition = CONS(oname, description);
    129     LispSetAtomStructProperty(atom, definition, STRUCT_CONSTRUCTOR);
    130     if (!intern)
    131 	LispExportSymbol(object);
    132 
    133     atom = oname->data.atom;
    134     if (atom->a_defstruct)
    135 	LispWarning("%s: structure %s is being redefined",
    136 		    STRFUN(builtin), strname);
    137     LispSetAtomStructProperty(atom, definition, STRUCT_NAME);
    138 
    139     sprintf(name, "%s-P", strname);
    140     atom = (object = ATOM(name))->data.atom;
    141     LispSetAtomStructProperty(atom, definition, STRUCT_CHECK);
    142     if (!intern)
    143 	LispExportSymbol(object);
    144 
    145     for (i = 0, list = description; CONSP(list); i++, list = CDR(list)) {
    146 	Atom_id id;
    147 
    148 	if (CONSP(CAR(list)))
    149 	    id = ATOMID(CAR(CAR(list)));
    150 	else
    151 	    id = ATOMID(CAR(list));
    152 	slength = id->length;
    153 	if (length + slength + 2 > size) {
    154 	    size = length + slength + 2;
    155 	    name = LispRealloc(name, size);
    156 	}
    157 	sprintf(name, "%s-%s", strname, id->value);
    158 	atom = (object = ATOM(name))->data.atom;
    159 	LispSetAtomStructProperty(atom, definition, i);
    160 	if (!intern)
    161 	    LispExportSymbol(object);
    162     }
    163 
    164     LispFree(name);
    165 
    166     if (documentation != NIL)
    167 	LispAddDocumentation(oname, documentation, LispDocStructure);
    168 
    169     return (oname);
    170 }
    171 
    172 /* helper functions
    173  *	DONT explicitly call them. Non standard functions.
    174  */
    175 LispObj *
    176 Lisp_XeditMakeStruct(LispBuiltin *builtin)
    177 /*
    178  lisp::make-struct atom &rest init
    179  */
    180 {
    181     int nfld, ncvt, length = lisp__data.protect.length;
    182     LispAtom *atom = NULL;
    183 
    184     LispObj *definition, *object, *field, *fields, *value = NIL, *cons, *list;
    185     LispObj *struc, *init;
    186 
    187     init = ARGUMENT(1);
    188     struc = ARGUMENT(0);
    189 
    190     field = cons = NIL;
    191     if (!POINTERP(struc) ||
    192 	!(XSYMBOLP(struc) || XFUNCTIONP(struc)) ||
    193 	(atom = struc->data.atom)->a_defstruct == 0 ||
    194 	 atom->property->structure.function != STRUCT_CONSTRUCTOR)
    195 	LispDestroy("%s: invalid constructor %s",
    196 		    STRFUN(builtin), STROBJ(struc));
    197     definition = atom->property->structure.definition;
    198 
    199     ncvt = nfld = 0;
    200     fields = NIL;
    201 
    202     /* check for errors in argument list */
    203     for (list = init, nfld = 0; CONSP(list); list = CDR(list)) {
    204 	CHECK_KEYWORD(CAR(list));
    205 	if (!CONSP(CDR(list)))
    206 	    LispDestroy("%s: values must be provided as pairs",
    207 			ATOMID(struc)->value);
    208 	nfld++;
    209 	list = CDR(list);
    210     }
    211 
    212     /* create structure, CAR(definition) is structure name */
    213     for (list = CDR(definition); CONSP(list); list = CDR(list)) {
    214 	Atom_id id;
    215 	LispObj *defvalue = NIL;
    216 
    217 	++nfld;
    218 	field = CAR(list);
    219 	if (CONSP(field)) {
    220 	    /* if default value provided */
    221 	    if (CONSP(CDR(field)))
    222 		defvalue = CAR(CDR(field));
    223 	    field = CAR(field);
    224 	}
    225 	id = ATOMID(field);
    226 
    227 	for (object = init; CONSP(object); object = CDR(object)) {
    228 	    /* field is a keyword, test above checked it */
    229 	    field = CAR(object);
    230 	    if (id == ATOMID(field)) {
    231 		/* value provided */
    232 		value = CAR(CDR(object));
    233 		ncvt++;
    234 		break;
    235 	    }
    236 	    object = CDR(object);
    237 	}
    238 
    239 	/* if no initialization given */
    240 	if (!CONSP(object)) {
    241 	    /* if default value in structure definition */
    242 	    if (defvalue != NIL)
    243 		value = EVAL(defvalue);
    244 	    else
    245 		value = NIL;
    246 	}
    247 
    248 	if (fields == NIL) {
    249 	    fields = cons = CONS(value, NIL);
    250 	    if (length + 1 >= lisp__data.protect.space)
    251 		LispMoreProtects();
    252 	    lisp__data.protect.objects[lisp__data.protect.length++] = fields;
    253 	}
    254 	else {
    255 	    RPLACD(cons, CONS(value, NIL));
    256 	    cons = CDR(cons);
    257 	}
    258     }
    259 
    260     /* if not enough arguments were converted, need to check because
    261      * it is acceptable to set a field more than once, but in that case,
    262      * only the first value will be used. */
    263     if (nfld > ncvt) {
    264 	for (list = init; CONSP(list); list = CDR(list)) {
    265 	    Atom_id id = ATOMID(CAR(list));
    266 
    267 	    for (object = CDR(definition); CONSP(object);
    268 		 object = CDR(object)) {
    269 		field = CAR(object);
    270 		if (CONSP(field))
    271 		    field = CAR(field);
    272 		if (ATOMID(field) == id)
    273 		    break;
    274 	    }
    275 	    if (!CONSP(object))
    276 		LispDestroy("%s: %s is not a field for %s",
    277 			    ATOMID(struc)->value, STROBJ(CAR(list)),
    278 			    ATOMID(CAR(definition))->value);
    279 	    list = CDR(list);
    280 	}
    281     }
    282 
    283     lisp__data.protect.length = length;
    284 
    285     return (STRUCT(fields, definition));
    286 }
    287 
    288 static LispObj *
    289 LispStructAccessOrStore(LispBuiltin *builtin, int store)
    290 /*
    291  lisp::struct-access atom struct
    292  lisp::struct-store atom struct value
    293  */
    294 {
    295     long offset;
    296     LispAtom *atom;
    297     LispObj *definition, *list;
    298 
    299     LispObj *name, *struc, *value = NIL;
    300 
    301     if (store)
    302 	value = ARGUMENT(2);
    303     struc = ARGUMENT(1);
    304     name = ARGUMENT(0);
    305 
    306     if (!POINTERP(name) ||
    307 	!(XSYMBOLP(name) || XFUNCTIONP(name)) ||
    308 	(atom = name->data.atom)->a_defstruct == 0 ||
    309 	(offset = atom->property->structure.function) < 0) {
    310 	LispDestroy("%s: invalid argument %s",
    311 		    STRFUN(builtin), STROBJ(name));
    312 	/*NOTREACHED*/
    313 	offset = 0;
    314 	atom = NULL;
    315     }
    316     definition = atom->property->structure.definition;
    317 
    318     /* check if the object is of the required type */
    319     if (!STRUCTP(struc) || struc->data.struc.def != definition)
    320 	LispDestroy("%s: %s is not a %s",
    321 		    ATOMID(name)->value, STROBJ(struc), ATOMID(CAR(definition))->value);
    322 
    323     for (list = struc->data.struc.fields; offset; list = CDR(list), offset--)
    324 	;
    325 
    326     return (store ? RPLACA(list, value) : CAR(list));
    327 }
    328 
    329 LispObj *
    330 Lisp_XeditStructAccess(LispBuiltin *builtin)
    331 /*
    332  lisp::struct-access atom struct
    333  */
    334 {
    335     return (LispStructAccessOrStore(builtin, 0));
    336 }
    337 
    338 LispObj *
    339 Lisp_XeditStructStore(LispBuiltin *builtin)
    340 /*
    341  lisp::struct-store atom struct value
    342  */
    343 {
    344     return (LispStructAccessOrStore(builtin, 1));
    345 }
    346 
    347 LispObj *
    348 Lisp_XeditStructType(LispBuiltin *builtin)
    349 /*
    350  lisp::struct-type atom struct
    351  */
    352 {
    353     LispAtom *atom = NULL;
    354 
    355     LispObj *definition, *struc, *name;
    356 
    357     struc = ARGUMENT(1);
    358     name = ARGUMENT(0);
    359 
    360     if (!POINTERP(name) ||
    361 	!(XSYMBOLP(name) || XFUNCTIONP(name)) ||
    362 	(atom = name->data.atom)->a_defstruct == 0 ||
    363 	(atom->property->structure.function != STRUCT_CHECK))
    364 	LispDestroy("%s: invalid argument %s",
    365 		    STRFUN(builtin), STROBJ(name));
    366     definition = atom->property->structure.definition;
    367 
    368     /* check if the object is of the required type */
    369     if (STRUCTP(struc) && struc->data.struc.def == definition)
    370 	return (T);
    371 
    372     return (NIL);
    373 }
    374