/* $Id: cPersistence.c,v 1.15 1997/06/06 19:04:40 jim Exp $ C Persistence Module Copyright Copyright 1996 Digital Creations, L.C., 910 Princess Anne Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All rights reserved. Copyright in this software is owned by DCLC, unless otherwise indicated. Permission to use, copy and distribute this software is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear. Note that any product, process or technology described in this software may be the subject of other Intellectual Property rights reserved by Digital Creations, L.C. and are not licensed hereunder. Trademarks Digital Creations & DCLC, are trademarks of Digital Creations, L.C.. All other trademarks are owned by their respective companies. No Warranty The software is provided "as is" without warranty of any kind, either express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. This software could include technical inaccuracies or typographical errors. Changes are periodically made to the software; these changes will be incorporated in new editions of the software. DCLC may make improvements and/or changes in this software at any time without notice. Limitation Of Liability In no event will DCLC be liable for direct, indirect, special, incidental, economic, cover, or consequential damages arising out of the use of or inability to use this software even if advised of the possibility of such damages. Some states do not allow the exclusion or limitation of implied warranties or limitation of liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. If you have questions regarding this software, contact: Jim Fulton, jim@digicool.com Digital Creations L.C. (540) 371-6909 *****************************************************************************/ static char *what_string = "$Id: cPersistence.c,v 1.15 1997/06/06 19:04:40 jim Exp $"; #include <time.h> #include "cPersistence.h" #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define UNLESS(E) if(!(E)) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) static PyObject *py_store, *py_oops, *py_keys, *py_setstate, *py___changed__, *py___dict__, *py_mtime, *py_onearg, *py___getinitargs__, *py___init__; #ifdef DEBUG_LOG static PyObject *debug_log=0; static int idebug_log=0; static void * call_debug(char *event, cPersistentObject *self) { PyObject *r; /* printf("%s %p\n",event,self->ob_type->tp_name); */ r=PyObject_CallFunction(debug_log,"s(sii)",event, self->ob_type->tp_name, self->oid, self->state); Py_XDECREF(r); } #endif static void init_strings() { #define INIT_STRING(S) py_ ## S = PyString_FromString(#S) INIT_STRING(store); INIT_STRING(oops); INIT_STRING(keys); INIT_STRING(setstate); INIT_STRING(mtime); INIT_STRING(__changed__); INIT_STRING(__init__); INIT_STRING(__getinitargs__); INIT_STRING(__dict__); py_onearg=Py_BuildValue("(i)",1); #undef INIT_STRING } static PyObject * callmethod(PyObject *self, PyObject *name) { if(self=PyObject_GetAttr(self,name)) ASSIGN(self,PyObject_CallObject(self,NULL)); return self; } static PyObject * callmethod1(PyObject *self, PyObject *name, PyObject *arg) { if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(1))) { PyTuple_SET_ITEM(name, 0, arg); ASSIGN(self,PyObject_CallObject(self,name)); PyTuple_SET_ITEM(name, 0, NULL); Py_DECREF(name); } return self; } static PyObject * callmethod2(PyObject *self, PyObject *name, PyObject *arg, PyObject *arg2) { if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(2))) { PyTuple_SET_ITEM(name, 0, arg); PyTuple_SET_ITEM(name, 1, arg2); ASSIGN(self,PyObject_CallObject(self,name)); PyTuple_SET_ITEM(name, 0, NULL); PyTuple_SET_ITEM(name, 1, NULL); Py_DECREF(name); } return self; } static PyObject * callmethod3(PyObject *self, PyObject *name, PyObject *arg, PyObject *arg2, PyObject *arg3) { if((self=PyObject_GetAttr(self,name)) && (name=PyTuple_New(3))) { PyTuple_SET_ITEM(name, 0, arg); PyTuple_SET_ITEM(name, 1, arg2); PyTuple_SET_ITEM(name, 2, arg3); ASSIGN(self,PyObject_CallObject(self,name)); PyTuple_SET_ITEM(name, 0, NULL); PyTuple_SET_ITEM(name, 1, NULL); PyTuple_SET_ITEM(name, 2, NULL); Py_DECREF(name); } return self; } static PyObject * #ifdef HAVE_STDARG_PROTOTYPES /* VARARGS 2 */ PyString_BuildFormat(char *stringformat, char *format, ...) #else /* VARARGS */ PyString_BuildFormat(va_alist) va_dcl #endif { va_list va; PyObject *args=0, *retval=0, *v=0; #ifdef HAVE_STDARG_PROTOTYPES va_start(va, format); #else PyObject *ErrType; char *stringformat, *format; va_start(va); ErrType = va_arg(va, PyObject *); stringformat = va_arg(va, char *); format = va_arg(va, char *); #endif args = Py_VaBuildValue(format, va); va_end(va); if(! args) return NULL; if(!(retval=PyString_FromString(stringformat))) return NULL; v=PyString_Format(retval, args); Py_DECREF(retval); Py_DECREF(args); return v; } /****************************************************************************/ static void PATime_dealloc(PATimeobject *self) { /*printf("D");*/ Py_DECREF(self->object); PyMem_DEL(self);} static PyObject * PATime_repr(PATimeobject *self) { return PyString_BuildFormat("<access time: %d>","i",self->object->atime); } static PyTypeObject PATimeType = { PyObject_HEAD_INIT(NULL) 0, "PersistentATime", /*tp_name*/ sizeof(PATimeobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PATime_dealloc, /*tp_dealloc*/ 0L,0L,0L,0L, (reprfunc)PATime_repr, /*tp_repr*/ 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L, "Values for holding access times for persistent objects" }; /****************************************************************************/ /* Declarations for objects of type Persistent */ #define GHOST_STATE -1 #define UPTODATE_STATE 0 #define CHANGED_STATE 1 staticforward PyExtensionClass Pertype; staticforward PyExtensionClass TPertype; static char Per___changed____doc__[] = "__changed__([flag]) -- Flag or determine whether an object has changed\n" " \n" "If a value is specified, then it should indicate whether an\n" "object has or has not been changed. If no value is specified,\n" "then the return value will indicate whether the object has\n" "changed.\n" ; static PyObject *changed_args=(PyObject*)Per___changed____doc__; static PyObject * Per___changed__(self, args) cPersistentObject *self; PyObject *args; { PyObject *o; if(args) { UNLESS(PyArg_Parse(args, "O", &o)) return NULL; if(self->state != GHOST_STATE) self->state=PyObject_IsTrue(o); Py_INCREF(Py_None); return Py_None; } else return PyInt_FromLong(self->state == CHANGED_STATE); } static PyObject * T___changed__(cPersistentObject *self, PyObject *args) { static PyObject *builtins=0, *get_transaction=0, *py_register=0; PyObject *o, *T; if(PyArg_Parse(args, "O", &o)) { int t; t=PyObject_IsTrue(o); if(t && self->state != cPersistent_CHANGED_STATE && self->jar) { UNLESS(get_transaction) { UNLESS(builtins) { UNLESS(T=PyImport_ImportModule("__main__")) return NULL; ASSIGN(T,PyObject_GetAttrString(T,"__builtins__")); UNLESS(T) return NULL; UNLESS(py_register=PyString_FromString("register")) goto err; builtins=T; } UNLESS(get_transaction=PyObject_GetAttrString(builtins, "get_transaction")) PyErr_Clear(); } if(get_transaction) { UNLESS(T=PyObject_CallObject(get_transaction,NULL)) return NULL; UNLESS_ASSIGN(T,PyObject_GetAttr(T,py_register)) return NULL; UNLESS(o=PyTuple_New(1)) goto err; Py_INCREF(self); PyTuple_SET_ITEM(o,0,(PyObject*)self); ASSIGN(o,PyObject_CallObject(T,o)); Py_DECREF(T); UNLESS(o) return NULL; Py_DECREF(o); } } if(self->state != cPersistent_GHOST_STATE) self->state=t; Py_INCREF(Py_None); return Py_None; } else { PyErr_Clear(); UNLESS(PyArg_Parse(args, "")) return NULL; return PyInt_FromLong(self->state==cPersistent_CHANGED_STATE); } err: Py_DECREF(T); return NULL; } static char Per___save____doc__[] = "__save__() -- Update the object in a persistent database." ; static PyObject * Per___save__(self, args) cPersistentObject *self; PyObject *args; { if(self->oid && self->jar && self->state == CHANGED_STATE) return callmethod1(self->jar,py_store,(PyObject*)self); Py_INCREF(Py_None); return Py_None; } static char Per___inform_commit____doc__[] = "__inform_commit__(transaction,start_time) -- Commit object changes" ; static PyObject * Per___inform_commit__(self, args) cPersistentObject *self; PyObject *args; { PyObject *T=0, *t=0; UNLESS(PyArg_ParseTuple(args, "OO", &T, &t)) return NULL; if(self->oid && self->jar && self->state == CHANGED_STATE) return callmethod2(self->jar,py_store,(PyObject*)self,T); Py_INCREF(Py_None); return Py_None; } static char Per___inform_abort____doc__[] = "__inform_abort__(transaction,start_time) -- Abort object changes" ; static PyObject * Per___inform_abort__(self, args) cPersistentObject *self; PyObject *args; { PyObject *T, *t; UNLESS(PyArg_ParseTuple(args, "OO", &T, &t)) return NULL; if(self->oid && self->jar && self->state != GHOST_STATE) { args=callmethod3(self->jar,py_oops,(PyObject*)self,t,T); if(args) Py_DECREF(args); else PyErr_Clear(); } Py_INCREF(Py_None); return Py_None; } static char Per__p___init____doc__[] = "_p___init__(oid,jar) -- Initialize persistence management data" ; static PyObject * Per__p___init__(self, args) cPersistentObject *self; PyObject *args; { int oid; PyObject *jar; UNLESS(PyArg_Parse(args, "(iO)", &oid, &jar)) return NULL; #ifdef DEBUG_LOG if(idebug_log < 0) call_debug("init",self); #endif Py_INCREF(jar); self->oid=oid; ASSIGN(self->jar, jar); self->state=GHOST_STATE; Py_INCREF(Py_None); return Py_None; } static PyObject * Per__p___reinit__(cPersistentObject *self, PyObject *args) { int oid; PyObject *init=0, *copy, *dict; #ifdef DEBUG_LOG if(idebug_log < 0) call_debug("reinit",self); #endif if(PyArg_Parse(args,"")) { if(self->state==cPersistent_UPTODATE_STATE) if(init=PyObject_GetAttr((PyObject*)self,py___init__)) { if(copy=PyObject_GetAttr((PyObject*)self,py___getinitargs__)) { ASSIGN(copy,PyObject_CallObject(copy,NULL)); UNLESS(copy) goto err; UNLESS(PyTuple_Check(copy)) { ASSIGN(copy,PySequence_Tuple(copy)); UNLESS(copy) goto err; } } else { copy=NULL; PyErr_Clear(); } if(HasInstDict(self) && (dict=INSTANCE_DICT(self))) PyDict_Clear(dict); dict=self->jar; self->jar=NULL; /* Grasping at straws :-( */ ASSIGN(copy,PyObject_CallObject(init,copy)); self->state=cPersistent_GHOST_STATE; self->jar=dict; UNLESS(copy) goto err; Py_DECREF(copy); Py_DECREF(init); } else if(HasInstDict(self) && (dict=INSTANCE_DICT(self))) { PyDict_Clear(dict); self->state=cPersistent_GHOST_STATE; } } else { PyErr_Clear(); UNLESS(PyArg_Parse(args, "O", ©)) return NULL; if(HasInstDict(self) && self->state==cPersistent_UPTODATE_STATE) { UNLESS(args=PyObject_GetAttr(copy,py___dict__)) return NULL; ASSIGN(INSTANCE_DICT(self),args); self->state=GHOST_STATE; } } Py_INCREF(Py_None); return Py_None; err: Py_XDECREF(init); return NULL; } static int Per_setstate(self) cPersistentObject *self; { self->atime=(time_t)1; /* Mark this object as sticky */ if(self->state==GHOST_STATE && self->jar) { PyObject *r; self->state=UPTODATE_STATE; UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) { self->state=GHOST_STATE; self->atime=time(NULL); /* Unmark as sticky */ return -1; } Py_DECREF(r); } return 0; } static PyObject * Per__getstate__(self,args) cPersistentObject *self; PyObject *args; { PyObject *__dict__, *d=0; UNLESS(PyArg_Parse(args, "")) return NULL; #ifdef DEBUG_LOG if(idebug_log < 0) call_debug("get",self); #endif /* Update state, if necessary */ if(self->state==GHOST_STATE && self->jar) { PyObject *r; self->state=UPTODATE_STATE; UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) { self->state=GHOST_STATE; return NULL; } Py_DECREF(r); } if(HasInstDict(self) && (__dict__=INSTANCE_DICT(self))) { PyObject *k, *v; int pos; char *ck; for(pos=0; PyDict_Next(__dict__, &pos, &k, &v); ) { if(PyString_Check(k) && (ck=PyString_AsString(k)) && (*ck=='_' && ck[1]=='v' && ck[2]=='_')) { UNLESS(d=PyDict_New()) goto err; for(pos=0; PyDict_Next(__dict__, &pos, &k, &v); ) UNLESS(PyString_Check(k) && (ck=PyString_AsString(k)) && (*ck=='_' && ck[1]=='v' && ck[2]=='_')) if(PyDict_SetItem(d,k,v) < 0) goto err; return d; } } } else __dict__=Py_None; Py_INCREF(__dict__); return __dict__; err: Py_DECREF(__dict__); Py_XDECREF(d); } static PyObject * Per__setstate__(self,args) cPersistentObject *self; PyObject *args; { PyObject *__dict__, *v, *keys=0, *key=0, *e=0; int l, i; /*printf("%s(%d) ", self->ob_type->tp_name,self->oid);*/ if(HasInstDict(self)) { UNLESS(PyArg_Parse(args, "O", &v)) return NULL; #ifdef DEBUG_LOG if(idebug_log < 0) call_debug("set",self); #endif self->state=UPTODATE_STATE; if(v!=Py_None) { __dict__=INSTANCE_DICT(self); if(PyDict_Check(v)) { for(i=0; PyDict_Next(v,&i,&key,&e);) if(PyObject_SetItem(__dict__,key,e) < 0) { self->state=GHOST_STATE; return NULL; } } else { UNLESS(keys=callmethod(v,py_keys)) goto err; UNLESS(-1 != (l=PyObject_Length(keys))) goto err; for(i=0; i < l; i++) { UNLESS_ASSIGN(key,PySequence_GetItem(keys,i)) goto err; UNLESS_ASSIGN(e,PyObject_GetItem(v,key)) goto err; UNLESS(-1 != PyObject_SetItem(__dict__,key,e)) goto err; } Py_XDECREF(key); Py_XDECREF(e); Py_DECREF(keys); } } } Py_INCREF(Py_None); return Py_None; err: self->state=GHOST_STATE; Py_XDECREF(key); Py_XDECREF(e); Py_XDECREF(keys); return NULL; } static struct PyMethodDef Per_methods[] = { {"__changed__", (PyCFunction)T___changed__, 0, Per___changed____doc__}, {"__save__", (PyCFunction)Per___save__, 1, Per___save____doc__}, {"__inform_commit__", (PyCFunction)Per___inform_commit__, 1, Per___inform_commit____doc__}, {"__inform_abort__", (PyCFunction)Per___inform_abort__, 1, Per___inform_abort____doc__}, {"_p___init__", (PyCFunction)Per__p___init__, 0, Per__p___init____doc__}, {"_p___reinit__", (PyCFunction)Per__p___reinit__, 0, "_p___reinit__(oid,jar,copy) -- Reinitialize from a newly created copy"}, {"__getstate__", (PyCFunction)Per__getstate__, 0, "__getstate__() -- Return the state of the object" }, {"__setstate__", (PyCFunction)Per__setstate__, 0, "__setstate__(v) -- Restore the saved state of the object from v" }, {NULL, NULL} /* sentinel */ }; /* ---------- */ static void Per_dealloc(self) cPersistentObject *self; { #ifdef DEBUG_LOG if(idebug_log < 0) call_debug("del",self); #endif Py_XDECREF(self->jar); /*Py_XDECREF(self->atime);*/ PyMem_DEL(self); } static void Per_set_atime(cPersistentObject *self) { if(self->atime == (time_t)1) return; self->atime = time(NULL); } static PyObject * Per_atime(cPersistentObject *self) { PATimeobject *r; UNLESS(r=PyObject_NEW(PATimeobject,&PATimeType)) return NULL; Py_INCREF(self); r->object=self; return (PyObject*)r; } static PyObject * Per_getattr(cPersistentObject *self, PyObject *oname, char *name, PyObject *(*getattrf)(PyObject *, PyObject*)) { char *n=name; if(*n++=='_') if(*n++=='p' && *n++=='_') { switch(*n++) { case 'o': if(*n++=='i' && *n++=='d' && ! *n) { if(self->oid) { return PyInt_FromLong(self->oid); } else { Py_INCREF(Py_None); return Py_None; } } break; case 'j': if(*n++=='a' && *n++=='r' && ! *n) { if(self->jar) { Py_INCREF(self->jar); return self->jar; } else { Py_INCREF(Py_None); return Py_None; } } break; case 'c': if(strcmp(n,"hanged")==0) return PyInt_FromLong(self->state == CHANGED_STATE); break; case 'a': if(strcmp(n,"time")==0) { if(self->state != UPTODATE_STATE) Per_set_atime(self); return Per_atime(self); } break; case 'm': if(strcmp(n,"time")==0) { if(self->jar) return callmethod1(self->jar,py_mtime,(PyObject*)self); Py_INCREF(Py_None); return Py_None; } break; } } if(! (*name++=='_' && *name++=='_' && strcmp(name,"dict__")==0)) { /* Update state, if necessary */ if(self->state==GHOST_STATE && self->jar) { PyObject *r; self->state=UPTODATE_STATE; UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) { self->state=GHOST_STATE; return NULL; } Py_DECREF(r); } Per_set_atime(self); } return getattrf((PyObject *)self, oname); } static PyObject* Per_getattro(cPersistentObject *self, PyObject *name) { char *s; UNLESS(s=PyString_AsString(name)) return NULL; return Per_getattr(self,name,s, PyExtensionClassCAPI->getattro); } static int changed(PyObject *self) { PyObject *c; UNLESS(c=PyObject_GetAttr(self,py___changed__)) return -1; UNLESS_ASSIGN(c,PyObject_CallObject(c,py_onearg)) return -1; Py_DECREF(c); return 0; } static int _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, int (*setattrf)(PyObject *, PyObject*, PyObject*)) { char *name=""; UNLESS(oname) return -1; if(PyString_Check(oname)) UNLESS(name=PyString_AsString(oname)) return -1; if(*name=='_' && name[1]=='p' && name[2]=='_') { if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6]) { if(PyInt_Check(v)) self->oid=PyInt_AsLong(v); else self->oid=0; return 0; } if(name[3]=='j' && name[4]=='a' && name[5]=='r' && ! name[6]) { ASSIGN(self->jar, v); Py_INCREF(self->jar); return 0; } if(strcmp(name+3,"changed")==0) { self->state=PyObject_IsTrue(v); return 0; } if(strcmp(name+3,"atime")==0) { self->atime=(time_t)1; return 0; } } else { PyObject *r; /* Update state, if necessary */ if(self->state==GHOST_STATE && self->jar) { self->state=UPTODATE_STATE; UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) { self->state=GHOST_STATE; return -1; } Py_DECREF(r); } /* Record access times */ Per_set_atime(self); if(! (*name=='_' && name[1]=='v' && name[2]=='_') && self->state != CHANGED_STATE && self->jar) if(changed((PyObject*)self) < 0) return -1; } return setattrf((PyObject*)self,oname,v); } static int Per_setattro(cPersistentObject *self, PyObject *oname, PyObject *v) { return _setattro(self,oname, v, PyExtensionClassCAPI->setattro); } static char Pertype__doc__[] = "Persistent object support mix-in class\n" "\n" "When a persistent object is loaded from a database, the object's\n" "data is not immediately loaded. Loading of the objects data is\n" "defered until an attempt is made to access an attribute of the\n" "object. \n" "\n" "The object also tries to keep track of whether it has changed. It\n" "is easy for this to be done incorrectly. For this reason, methods\n" "of subclasses that change state other than by setting attributes\n" "should: 'self.__changed__(1)' to flag instances as changed.\n" "\n" "Data are not saved automatically. To save an object's state, call\n" "the object's '__save__' method.\n" "\n" "You must not override the object's '__getattr__' and '__setattr__'\n" "methods. If you override the objects '__getstate__' method, then\n" "you must be careful not to include any attributes with names\n" "starting with '_p_' in the state.\n" ; static PyExtensionClass Pertype = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "Persistent", /*tp_name*/ sizeof(cPersistentObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Per_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)0, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ (getattrofunc)Per_getattro, /*tp_getattr with object key*/ (setattrofunc)Per_setattro, /*tp_setattr with object key*/ /* Space for future expansion */ 0L,0L, Pertype__doc__, /* Documentation string */ METHOD_CHAIN(Per_methods) }; /* End of code for Persistent objects */ /* -------------------------------------------------------- */ /* List of methods defined in the module */ #ifdef DEBUG_LOG static PyObject * set_debug_log(PyObject *ignored, PyObject *args) { Py_INCREF(args); ASSIGN(debug_log, args); if(debug_log) idebug_log=-1; else idebug_log=0; Py_INCREF(Py_None); return Py_None; } #endif static struct PyMethodDef cP_methods[] = { #ifdef DEBUG_LOG {"set_debug_log", (PyCFunction)set_debug_log, 0, "set_debug_log(callable) -- Provide a function to log events\n" "\n" "The function will be called with an event name and a persistent object.\n" }, #endif {NULL, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called initcPersistence) */ typedef int (*intfunctionwithpythonarg)(PyObject*); static cPersistenceCAPIstruct truecPersistenceCAPI = { &(Pertype.methods), (getattrofunc)Per_getattro, /*tp_getattr with object key*/ (setattrofunc)Per_setattro, /*tp_setattr with object key*/ changed, (intfunctionwithpythonarg)Per_setstate, (pergetattr)Per_getattr, (persetattr)_setattro, }; void initcPersistence() { PyObject *m, *d; char *rev="$Revision: 1.15 $"; PATimeType.ob_type=&PyType_Type; m = Py_InitModule4("cPersistence", cP_methods, "", (PyObject*)NULL,PYTHON_API_VERSION); init_strings(); d = PyModule_GetDict(m); PyDict_SetItemString(d,"__version__", PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); PyExtensionClass_Export(d,"Persistent",Pertype); PyDict_SetItemString(d,"atimeType",(PyObject*)&PATimeType); cPersistenceCAPI=&truecPersistenceCAPI; PyDict_SetItemString(d, "CAPI", PyCObject_FromVoidPtr(cPersistenceCAPI,NULL)); CHECK_FOR_ERRORS("can't initialize module dt"); } /**************************************************************************** $Log: cPersistence.c,v $ Revision 1.15 1997/06/06 19:04:40 jim Modified so that C API setstate makes object temporarily undeactivatable. Revision 1.14 1997/05/01 20:33:58 jim I made (and restored) some optimizations. The effect is probably minor, but who knows. Revision 1.13 1997/04/27 09:18:01 jim Added to the CAPI to support subtypes (like Record) that want to extend attr functions. Revision 1.12 1997/04/24 12:48:48 jim Fixed bug in reinit Revision 1.11 1997/04/22 02:46:50 jim Took out debugging info. Revision 1.10 1997/04/22 02:40:03 jim Changed object header layout and added sticky feature. Revision 1.9 1997/04/03 17:34:14 jim Changed to pass transaction to jar store method during commit. Revision 1.8 1997/03/28 20:24:52 jim Added login to really minimice cache size and to make cache attributes changeable. Revision 1.7 1997/03/25 20:43:21 jim Changed to make all persistent objects transactional. Revision 1.6 1997/03/20 20:58:25 jim Fixed bug in reinit. Revision 1.5 1997/03/14 22:59:34 jim Changed the way Per_setstate was exported to get rid of compilation error. Revision 1.4 1997/03/14 22:51:40 jim Added exported C interface, so that other C classes could subclass from it. Added _p_mtime attribute, which returns the persistent modification time. Revision 1.3 1997/03/11 20:53:07 jim Added access-time tracking and special type for efficient access time management. Revision 1.2 1997/02/21 20:49:09 jim Added logic to treat attributes starting with _v_ as volatile. Changes in these attributes to not make the object thing it's been saved and these attributes are not saved by the default __getstate__ method. Revision 1.1 1997/02/14 20:24:55 jim *** empty log message *** ****************************************************************************/