/* Copyright 1989-93 GROUPE BULL -- See license conditions in file COPYRIGHT */ /***********\ * * * KL_STRUCT * * BODY * * * \***********/ #include "EXTERN.h" #include "klone.h" #include "kl_number.h" #include "kl_atom.h" #include "kl_string.h" #include "kl_list.h" #include "kl_hash.h" #include "kl_stream.h" #include "INTERN.h" #include "kl_struct.h" #ifndef USE_STANDARD_MALLOC extern char *KlMallocZoneBegin, *KlMallocZoneEnd; #endif /*****************************************************************************\ * KlStructClass * \*****************************************************************************/ KlStructClass KlStructClassMake(name, size, nslots) char *name; /* name of class */ int size; /* sizeof of the whole struct */ int nslots; /* room for nslots slots */ { KlStructClass obj = (KlStructClass) KlOMake(KlStructClassType); KlHash slots = KlHashAlloc(nslots); KlOZero(obj, sizeof(struct _KlStructClass)); KlIncRef(obj->name = KlIntern(name)); KlIncRef(obj->slots = slots); slots->ref_counted = 0; obj->size = size; KlSend_setq(obj->name, obj); /* setqs name to structclass */ /* default system methods 0 by default*/ return obj; } void KlDeclareStructClassSlot(structclass, name, func, offset, data) KlStructClass structclass; char *name; KlMethod func; int offset; AnyPtr data; { KlCAccessor accessor = (KlCAccessor) Malloc(sizeof(struct _KlCAccessor)); accessor->offset = offset; accessor->access = func; accessor->data = data; KlHashPut(structclass->slots, KlIntern(name), accessor); } KlO KlStructClassFree(obj) KlStructClass obj; { KlDecRef(obj->name); KlDecRef(obj->slots); Free(obj); return (KlO) obj; } KlO KlStructClassPrint(obj, stream) KlStructClass obj; KlStream stream; { KlSPrintf(stream, "{^ StructClass 0x%x ", obj); KlSPrint(obj->name, stream); KlSPuts("}", stream); return (KlO) obj; } /* get on a structclass: * 'name --> the name (atom) * 'slots --> the list of slot names * 'size --> ths size (in bytes, not used yet) */ KlO KlStructClassGet(obj, key, def) KlStructClass obj; KlAtom key; KlO def; { if (key == KlA_name) { return (KlO) obj->name; } else if (key == KlA_slots) { KlList slotnameslist = KlListNMake(obj->slots->size); KlListStoreDReset(slotnameslist); KlHashFORBEGIN(obj->slots, cell) { KlListStoreAdd(cell->key); } KlHashFOREND; return (KlO) slotnameslist; } else if (key == KlA_size) { return (KlO) KlNumberMake(obj->size); } else { return KlExecuteGetDefault(obj, key, def); } } /* executing a structclass creates a struct. quotes args */ KlO KlStructClassApply(structclass, list) KlStructClass structclass; KlList list; { int argc = list->size - 1; KlO *argv = list->list + 1; if (structclass->parse) { return (KlO) CFAPPLY((structclass->parse), (structclass, argc, argv)); } else { return (KlO) KlError(KlE_UNDEFINED_FUNCTION, structclass); } } /*****************************************************************************\ * KlStruct * \*****************************************************************************/ /* methods */ KlStruct KlStructMake(structclass, Cobject) KlStructClass structclass; char * Cobject; { if (structclass->make) { return (KlStruct) CFAPPLY((structclass->make), (Cobject)); } else { KlStruct obj = (KlStruct) KlOMake(KlStructType); KlIncRef(obj->structclass = structclass); obj->ptr = Cobject; return obj; } } KlO KlStructFree(obj) KlStruct obj; { KlDecRef(obj->structclass); if (obj->structclass->free) { CFAPPLY((obj->structclass->free), (obj)); } Free(obj); return (KlO) obj; } KlO KlStructGet(obj, key, def) KlStruct obj; KlO key; KlO def; { KlCAccessor accessor; if ((accessor = (KlCAccessor) KlHashGet(obj->structclass->slots, key, 0))) { return CFAPPLY((accessor->access), (obj->ptr + accessor->offset, 0, accessor->data, obj)); } else { /* slot not found */ if (obj->structclass->defget) { return CFAPPLY((obj->structclass->defget), (obj, key, def)); } else { return KlExecuteGetDefault(obj, key, def); } } } KlO KlStructPut(obj, key, val) KlStruct obj; KlO key; KlO val; { KlCAccessor accessor; if ((accessor = (KlCAccessor) KlHashGet(obj->structclass->slots, key, 0))) { return CFAPPLY((accessor->access), (obj->ptr + accessor->offset, val, accessor->data, obj)); } else { /* slot not found */ if (obj->structclass->defput) { return CFAPPLY((obj->structclass->defput), (obj, key, val)); } else { return KlError2(KlE_NO_ELEMENT, key, obj->structclass->name); } } } KlO KlStructPrint(obj, stream) KlStruct obj; KlStream stream; { if (obj->structclass->print) { CFAPPLY((obj->structclass->print), (obj, stream)); } else { KlSPrintf(stream, "{^ Struct 0x%x ", obj); KlSPrint(obj->structclass->name, stream); KlSPuts("}", stream); } return (KlO) obj; } /* functions */ /* (struct-of struct [new-structclass]) * gets or sets (cast for unions) the class of the struct * returns (or take as argument) a structclass object, of which you can get the * name by (get structclass 'name) * WARNING: of course, setting the structclass is *EXTREMELY* dangerous, * and can lead to bus errors */ KlO KlStructOf(argc, argv) int argc; KlStruct *argv; { KlNumberOfArgumentsCheck(argc < 1, argc); KlMustBeStruct(argv[0], 0); switch (argc) { case 1: /* get the struct name */ return (KlO) argv[0]->structclass; case 2: /* casts into another struct */ KlMustBeStructClass(argv[1], 1); KlDecRef(argv[0]->structclass); KlIncRef(argv[0]->structclass = (KlStructClass) argv[1]); return (KlO) argv[1]; default: return KlBadNumberOfArguments((char *) argc); } } /*****************************************************************************\ * default class methods * \*****************************************************************************/ KlO KlStructClassFreeDefault(obj) KlStruct obj; { free(obj->ptr); } KlO KlStructClassPrintDefault(obj, stream) KlStruct obj; KlStream stream; { KlSPutc('{', stream); if (KlPrintReadably) { KlCAccessor accessor; KlO value; KlSPrint(obj->structclass->name, stream); KlHashFORBEGIN(((KlHash) obj->structclass->slots), cell) { KlSPutc(' ', stream); KlSPrint(cell->key, stream); /* slot name */ KlSPutc(' ', stream); accessor = (KlCAccessor) cell->object; /* get val */ value = CFAPPLY((accessor->access), (obj->ptr + accessor->offset, 0, accessor->data, obj)); KlSPrint(value, stream); } KlHashFOREND; } else { KlSPrintf(stream, "^ Struct 0x%x ", obj); KlSPrint(obj->structclass->name, stream); } KlSPuts("}", stream); return (KlO) obj; } KlO KlStructClassParseDefault(structclass, argc, argv) KlStructClass structclass; int argc; KlO *argv; { KlStruct obj; int i; char *ptr = (char *) malloc(structclass->size); obj = KlStructMake(structclass, ptr); for (i = 0; i < argc-1; i+= 2) { KlStructPut(obj, argv[i], argv[i+1]); } return (KlO) obj; } /*****************************************************************************\ * forcing class * \*****************************************************************************/ /* routines to access to a C structure knowing whose Structclass it is. * useful to avoid creating and de-referncing KlStructs on-the-fly ony to * do get and puts */ KlO KlStructGetWithClass(structclass, ptr, key, def) KlStructClass structclass; char * ptr; KlO key; KlO def; { KlCAccessor accessor; if ((accessor = (KlCAccessor) KlHashGet(structclass->slots, key, 0))) { return CFAPPLY((accessor->access), (ptr + accessor->offset, 0, accessor->data, ptr)); } else { /* slot not found, build a full KlStruct to call default routines */ KlStruct obj = KlStructMake(structclass, ptr); if (structclass->defget) { return CFAPPLY((structclass->defget), (obj, key, def)); } else { return KlExecuteGetDefault(obj, key, def); } } } KlO KlStructPutWithClass(structclass, ptr, key, val) KlStructClass structclass; char * ptr; KlO key; KlO val; { KlCAccessor accessor; if ((accessor = (KlCAccessor) KlHashGet(structclass->slots, key, 0))) { return CFAPPLY((accessor->access), (ptr + accessor->offset, val, accessor->data, ptr)); } else { /* slot not found, build a full KlStruct to call default routines */ KlStruct obj = KlStructMake(structclass, ptr); if (structclass->defput) { return CFAPPLY((structclass->defput), (obj, key, val)); } else { return KlError2(KlE_NO_ELEMENT, key, structclass->name); } } } /*****************************************************************************\ * KlStructArray * \*****************************************************************************/ KlStructArray KlStructArrayMake(array, elt_size, access, max_size, free, data) char * array; int elt_size; KlMethod access; int max_size; KlMethod free; /* 0 = no freeing done */ AnyPtr data; { KlStructArray obj = (KlStructArray) KlOMake(KlStructArrayType); obj->ptr = array; obj->elt_size = elt_size; obj->access = access; obj->max_size = max_size; obj->free = free; obj->data = data; return (KlStructArray) obj; } KlO KlStructArrayClone(obj, ptr) KlStructArray obj; char * ptr; { KlStructArray newobj = (KlStructArray) KlOMake(KlStructArrayType); bcopy(obj, newobj, sizeof(struct _KlStructArray)); KlZrtPut(newobj); newobj->ptr = ptr; return (KlO) newobj; } KlO KlStructArrayFree(obj) KlStructArray obj; { if (obj->free) CFAPPLY((obj->free), (obj->ptr)); Free(obj); return (KlO) obj; } KlO KlStructArrayLength(obj) KlStructArray obj; { return (KlO) KlNumberMake(obj->max_size); } KlO KlStructArrayGet(obj, key, def) KlStructArray obj; KlNumber key; KlO def; { KlMustBeNumber(key, 1); if (key->number >= obj->max_size || key->number < 0) { return KlExecuteGetDefault(obj, key, def); } return CFAPPLY((obj->access), (obj->ptr + (obj->elt_size * key->number), 0, obj->data, obj)); } KlO KlStructArrayPut(obj, key, value) KlStructArray obj; KlNumber key; KlO value; { KlMustBeNumber(key, 1); if (key->number >= obj->max_size || key->number < 0) { return KlError2(KlE_NO_ELEMENT, key, obj); } return CFAPPLY((obj->access), (obj->ptr + (obj->elt_size * key->number), value, obj->data, obj)); } KlStructArrayDolist(obj, var, argc, argv) KlStructArray obj; KlO var; int argc; KlO *argv; { char *p = obj->ptr; char *last = obj->max_size ? (p + (obj->elt_size * obj->max_size)) : p-1; KlGCMark(); for ( ; p < last; p += obj->elt_size) { KlSend_setq(var, CFAPPLY((obj->access), (p, 0, obj->data, obj))); KlProgn(argc, argv); KlGC(); } } /*****************************************************************************\ * standard C accessor functions * \*****************************************************************************/ /*********************************************************** scalar numerics */ /* very simple. * data field unused */ KlO KlStructAccessorChar(address, value, data, obj) unsigned char *address; KlNumber value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = value->number; return (KlO) value; } else { return (KlO) KlNumberMake(*address); } } KlO KlStructAccessorShort(address, value, data, obj) short *address; KlNumber value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = value->number; return (KlO) value; } else { return (KlO) KlNumberMake(*address); } } KlO KlStructAccessorInt(address, value, data, obj) int *address; KlNumber value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = value->number; return (KlO) value; } else { return (KlO) KlNumberMake(*address); } } KlO KlStructAccessorLong(address, value, data, obj) long *address; KlNumber value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = value->number; return (KlO) value; } else { return (KlO) KlNumberMake(*address); } } /****************************************************************** floating */ KlO KlStructAccessorFloat(address, value, data, obj) float *address; KlReal value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = KlNumberRealValue(value); return (KlO) value; } else { return (KlO) KlRealMake(((double) (*address))); } } KlO KlStructAccessorDouble(address, value, data, obj) double *address; KlReal value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = KlNumberRealValue(value); return (KlO) value; } else { return (KlO) KlRealMake(*address); } } /******************************************************************* pointer */ KlO KlStructAccessorPtr(address, value, data, obj) char **address; KlNumber value; char *data; KlStruct obj; { if (value) { KlMustBeNumber(value, 2); *address = (char *) value->number; return (KlO) value; } else { return (KlO) KlNumberMake(*address); } } /**************************************************************** struct ptr */ /* for structs pointed to, the data field of the accessor is a structclass * giving the type of the the sub-struct */ KlO KlStructAccessorStructPtr(address, value, data, obj) char **address; KlO value; KlStructClass data; KlStruct obj; { if (value) { return KlError0(KlE_BAD_ACCESS); /* we do not know what to do, storage allocation problems */ } else { return (KlO) KlStructMake(data, (*address)); } } /******************************************************* Useful: klone object */ KlO KlStructAccessorKlone(adress, value, data, obj) KlO *adress; KlO value; char *data; KlStruct obj; { if (value) { KlDecRefNonNull(*adress) ; KlIncRef(*adress = value) ; } return *adress; } /********************************************************************* union */ /* what to provide as a default? * best way now is just to do a casting by struct-of */ /******************************************************************** arrays */ /* for an array, the data field contains the array structure * that has been created by * KlStructArrayMake(0, , , * , 0, 0) * this for field of type: struct foo { int field[N];}; */ KlO KlStructAccessorArray(address, value, data, obj) char **address; KlO value; KlStructArray data; KlStructArray obj; { if (value) { return KlError0(KlE_BAD_ACCESS); } else { return KlStructArrayClone(data, address); } } /* for a pointer to an array, the data field contains the array structure * that has been created by * KlStructArrayMake(0, , , * , 0, 0) * this for field of type: struct foo { int *field}; */ KlO KlStructAccessorArrayPtr(address, value, data, obj) char **address; KlO value; KlStructArray data; KlStructArray obj; { if (value) { return KlError0(KlE_BAD_ACCESS); } else { return KlStructArrayClone(data, *address); } } /******************************************************************* strings */ /* string is not a primitive C type, but it is so common... * WARNING: this do not do the put, as the problem of freeing the list is not * solvable in the general case * a special-purpose function should be made for each case... */ KlO KlStructAccessorString(address, value, data, obj) char **address; KlString value; char *data; KlStruct obj; { if (value) { return KlError0(KlE_BAD_ACCESS); } else { return (KlO) KlStringMake(*address); } } /******************************************************************* scalars */ KlMethod KlStructAccessorScalarOfAux(size) int size; { if (size > sizeof(long)) { return (KlMethod) (*KlFatalError)(12, size); } else { return KlStructAccessorScalar[size]; } } /*****************************************************************************\ * Klone interface * \*****************************************************************************/ /* C objects: * pointer 0 * char 1 * short 2 * int 3 * long 4 * float 5 * double 6 * string 7 */ #define KlStructAccessorsSize 8 static KlMethod KlStructAccessors[KlStructAccessorsSize] = { KlStructAccessorPtr, KlStructAccessorChar, KlStructAccessorShort, KlStructAccessorInt, KlStructAccessorLong, KlStructAccessorFloat, KlStructAccessorDouble, KlStructAccessorString }; /* (*:make-struct structclass address) * creates a struct at some address to access an element of some type */ KlO KlStructMakeKl(structclass, addr) KlStructClass structclass; KlNumber addr; { KlMustBeStructClass(structclass, 0); KlMustBeNumber(addr, 1); return (KlO) KlStructMake(structclass, addr->number); } /* (*:make-structclass name size) */ KlO KlStructClassMakeKl(name, size) KlString name; KlNumber size; { KlMustBeString(name, 0); KlMustBeNumber(size, 1); return (KlO) KlStructClassMake(KlIntern(name->string), size->number, 0); } KlO KlDeclareStructClassSlotKl(structclass, name, what, offset) KlStructClass structclass; KlString name; KlNumber what; KlNumber offset; { KlMethod access; KlO data = 0; KlMustBeStructClass(structclass, 0); KlMustBeString(name, 1); KlMustBeNumber(offset, 3); if (KlIsANumber(what)) { if (what->number >=0 && what->number < KlStructAccessorsSize) { access = KlStructAccessors[what->number]; } else { access = KlStructAccessors[0]; } } else if (KlIsAStructClass(what)) { access = KlStructAccessorStructPtr; data = (KlO) what; } else if (KlIsAList(what)) { /* list type, size */ access = KlStructAccessorArray; /* data = (KlO) KlStructArrayMake( ... TODO ... ); */ } } /*****************************************************************************\ * peekpoke * \*****************************************************************************/ /* obsolete calls */ /* (C:* address) * returns object at address, otherwise nil */ KlO KlStructCPeek(address) KlNumber address; { KlO obj = (KlO) address->number; if (KlObjectIsValid(obj)) { return (KlO) obj; } else { return NIL; } } /* (C:*-int address) * returns value at address as integer */ KlO KlStructCPeekAsInt(address) KlNumber address; { KlO obj = (KlO) address->number; return (KlO) KlNumberMake(*((Int *) obj)); } /* (C:*-byte address) * returns value at address as byte */ KlO KlStructCPeekAsByte(address) KlNumber address; { KlO obj = (KlO) address->number; return (KlO) KlNumberMake(*((unsigned char *) obj)); } /* (C:*= address value) * pokes value at address */ KlO KlStructCPoke(address, value) KlNumber address; KlNumber value; { Int *obj = (Int *) address->number; *obj = value->number; return (KlO) value; } /* (C:*=-byte address value) * pokes value (byte) at address */ KlO KlStructCPokeAsByte(address, value) KlNumber address; KlNumber value; { unsigned char *obj = (unsigned char *) address->number; *obj = value->number; return (KlO) value; } /* (C:& object) * KlStructCAddressOf * returns address of an object = "peek" */ KlO KlStructCAddressOf(obj) KlO obj; { return (KlO) KlNumberMake(obj); } #ifndef USE_STANDARD_MALLOC /* (C:memory-used address) * return number of bytes malloced */ KlO KlMallocedSizeKl(adr) KlNumber adr; { KlMustBeNumber(adr, 0); return (KlO) KlNumberMake(KlMallocedSizeAndCheck(adr->number)); } #endif /* !USE_STANDARD_MALLOC */ /*****************************************************************************\ * TYPE INIT * \*****************************************************************************/ KlStructInit() { KlDeclareType(&KlStructType, "Struct", sizeof(struct _KlStruct)); KlDeclareMethod1(KlStructType, KlSelPrint, KlStructPrint); KlDeclareMethod1(KlStructType, KlSelFree, KlStructFree); KlDeclareMethod1(KlStructType, KlSelGet, KlStructGet); KlDeclareMethod1(KlStructType, KlSelPut, KlStructPut); KlDeclareType(&KlStructClassType, "StructClass", sizeof(struct _KlStructClass)); KlDeclareMethod1(KlStructClassType, KlSelPrint, KlStructClassPrint); KlDeclareMethod1(KlStructClassType, KlSelGet, KlStructClassGet); KlDeclareMethod1(KlStructClassType, KlSelExecute, KlStructClassApply); KlDeclareMethod1(KlStructClassType, KlSelApply, KlStructClassApply); KlDeclareType(&KlStructArrayType, "StructArray", sizeof(struct _KlStructArray)); KlDeclareMethod1(KlStructArrayType, KlSelGet, KlStructArrayGet); KlDeclareMethod1(KlStructArrayType, KlSelPut, KlStructArrayPut); KlDeclareMethod1(KlStructArrayType, KlSelFree, KlStructArrayFree); KlDeclareMethod1(KlStructArrayType, KlSelLength, KlStructArrayLength); KlDeclareMethod1(KlStructArrayType, KlSelDolist, (KlMethod) KlStructArrayDolist); /* initialize array of access to number by the value of sizeof */ bzero(KlStructAccessorScalar, sizeof(long) * sizeof(KlMethod)); KlStructAccessorScalar[sizeof(char)] = KlStructAccessorChar; KlStructAccessorScalar[sizeof(short)] = KlStructAccessorShort; KlStructAccessorScalar[sizeof(int)] = KlStructAccessorInt; KlStructAccessorScalar[sizeof(long)] = KlStructAccessorLong; /* functions */ KlDeclareSubr(KlStructOf, "struct-of", NARY); /* old calls, should be emulated by something else */ KlConstantMake("C:ptr-size", KlNumberMake(KLSO)); KlDeclareSubr(KlStructCAddressOf, "C:&", 1); KlDeclareSubr(KlStructCPeek, "C:*", 1); KlDeclareSubr(KlStructCPeekAsInt, "C:*-int", 1); KlDeclareSubr(KlStructCPeekAsByte, "C:*-byte", 1); KlDeclareSubr(KlStructCPoke, "C:*=-int", 2); KlDeclareSubr(KlStructCPokeAsByte, "C:*=-byte", 2); #ifndef USE_STANDARD_MALLOC KlDeclareSubr(KlMallocedSizeKl, "C:memory-used", 1); #endif /* !USE_STANDARD_MALLOC */ KlDeclareSubr(KlStructMakeKl, "*:make-struct", 2); }