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