#ifndef ACELIB_H #define ACELIB_H /* %W% %G% */ #ifdef _CPLUSPLUS extern "C" { #endif #define BLOCKING /* indicates routines which may be blocking */ #include "acetypes.h" /************************************************************************** *************************** Basic manipulations*************************** * * acelib is meant to be used in two ways: * -to link an application against an xace or tace kernel, * -or to be part of a distant client code connecting via the network * * The implementation of acelib differs for these situations, but * the way acelib is used by the application is the same. First call * aceInit() to connect to the database, possibly launching the server * if it was not running before, then call aceOpen() to identify * your session, finally aceQuit() to terminate the connection. * * Bool aceInit(char* ACEDB) * * ACEDB identifies the server. * -server side implementation, * The ACEDB parameter is the usual $ACEDB of xace, it consists of * a colon concatenated file path, for example "/home/worm:/usr/local/acedb" * the first member should contain the subdirectories database and wspec * the other directories like wquery will be searched for in the whole path. * -client side implementation * The client side implementation must handle the network. It will * use the ACEDB parameter to locate the server on the network. If we * write a CORBA implementation, we may connect to the actual server * using the CORBA service broadcasting mechanism, but we may also write * a socket implemetation and find the server port by a hard coded * look up table. It is up to the implementation whether it wants to * transfer the data in larger chunks and buffer them, or in little * pieces. The only required behaviour is to deliver the data as * specified in the present API. * The network handler will shake hand with the server and return * true to the client if the server was found. The server side of the * network handler will only itself need to call aceInit(FILE_PATH) * if the database is not yet running. * * Ace* aceOpen(char* client_signature) * * must be called by every application before getting any data from * acelib. The context, see below for details, is used by the server * to stamp data modifications and to manage memory allocation for * the client. When the client calls aceClose(), the memory is * garbage collected.However, it is polite to call aceFree() as soon * as possible on any pointer received from acelib. * * Bool aceQuit(void) * * terminates all operations. ************************************************************************* */ /************************************************************************* *********************** Working example ********************************* * * Save the following code as test.c and complile it by the command * cc -o test test.c -lace * If your compiler is non-ANSI and complains about prototypes, try gcc * in place of cc, or ask your system administrator. * * To compile you need header files * acelib.h acetypes.h array.h keyset.h regular.h * in your include path (set by -I) and libace.a in your library path * (set by -L). If all these files are in the current directory a * pedantic command would be * cc -o test -I. test.c -L. -lace * * This program should connect to the acedb database indicated on its * command line (default is the current directory) and return the list * and size of all the data classes. #include "acelib.h" void main(int argc, char **argv) { int n, i ; char *cp ; AceStringSet s ; if (aceInit(argc > 1 ? argv[1] : 0)) { aceOpen("test") ; s = aceClasses(0) ; for (i = 0 ; i < aceStringSetMax(s) ; i++) if (aceClassSize (aceStringSet(s,i), &n)) printf ("Number of items in class %s = %d\n", aceStringSet(s,i), n) ; aceQuit() ; } else fprintf (stderr, "Sorry, no connection\n") ; } /************************************************************************* ************************** Error reports ******************************** * * All routines return NULL or 0 if and only if they fail. In such a case * and error number and a message are available. Errors are enumerated in * aceerror.h. */ extern int aceErrno; /* error number, see aceerror.h */ char* aceErrorMessage(int* bufsize); /* hopefully, a short explanation */ /************************************************************************* ************************** Session managment **************************** * * Always call aceInit() at the top of your application and aceQuit() at * the end. The commit parameter of aceQuit applies to all context which * are still active and have not call commit themselves. * * ????????????????????????????????????????? *. There is no roll * back after you call commit on a context, or is there ? * who calls acedb:sessionSave() ? * ????????????????????????????????????????? * */ Bool aceInit(char* ace_path); /* initialise network or disk access */ Bool aceGetWriteAccess(Bool get); /* if get=true, get it, if get=false: would it be possible */ Bool aceForbidWriteAccess(void); /* final, none of your context will have it */ Bool aceCommit(BOOL releaseLock ); /* saves everything to disk */ Bool aceQuit(Bool commit) ; /* terminates server connection or closes disk */ /************************************************************************* ************************** Context managment **************************** * * A context is the way to identify the client from the server side. All * data operations raise an error if the current context is invalid, and all * data editions will be individually time stamped with the client_signature. * * From the client point of view, The context is the real owner of the * data. It owns the memory, the read and write locks and allows roll * backs. A client can open several contexts in parallel but can only * open a given AceInstance once per context. * * The context is established by Open and remains implicitelly valid * untill closed or reset by a second Open or Set call. Get returns the * current context . * * Each context has a private handle, and all data allocated in a * context is hooked on that handle and garbage collected when the * context is closed. To reuse a pointer after closing the context is * an access violation. In the present implementation this error would * not be detected but would possibly crash the acedb kernel and * provoke a core dump. */ Ace* aceOpenContext(char *client_signature); Bool aceSetContext(Ace*); Ace* aceGetContext(void); Bool aceCloseContext(Bool commit) ; /************************************************************************** ************************** Memory managment ****************************** * * All memory allocated by acelib uses the ACeDB memory management * system. To explicitly free ANY pointer received from acelib, be it a set * an instance or simply a character string, you MUST call aceFree(). Any * direct call to the standard C library free() would irrevocably crash the * acedb kernel. * * Memory is allocated on a handle. Calling aceFree(handle) garbage * collects the handle and everything that was allocated on that * handle. However, you do not have to wait and you can aceFree any * individual item, which is then automatically detached from its * handle. Since handles are recursive, you can easilly tame your * memory requirements. Handles are also used in acelib for bulk data * managment, e.g. aceCommitHandle() described, providing a form of * multiple parallel micro transaction control. * * The Ace* context will create a handle of its own, so all structures * generated in a context will be aceFree() on aceClose(). And of * course all contexts are destroyed on aceQuit(). */ AceHandle aceHandleCreate(AceHandle h); /* get a handle (possibly recursively) */ Bool aceFree(void*); /* (recursively) free any acelib pointer */ /************************************************************************* *************************** Naming ************************************** * * In acedb, every instance has a key. Every key belongs to a unique * class, and has a name unique in that class.When a full object name * is required, it should have the format className:name where * * classsName: * a string without blanks or punctuation of the form [a-zA-Z][a-zA-Z0-9_]* * should be the name of an existing acedb data class, which may be * listed by the function aceClasses(); * * name: * should be the name of an instance of the class, known or new, A * name is either of the same form or any non blank printable string * between double quotes "". Ace will actually remove the leading and * trailing spaces of names. * * The function aceComposeName() can be used to compose a valid name. */ char* aceName(AceKey key, AceHandle h); /* name of the key */ char* aceClassName(AceKey key, AceHandle h); /* class name of the key */ char* aceComposeName(char* classname, char* instancename, AceHandle h); /* These 2 functions return 0, if the name is unknown and create = false. *. An error is raised if the name is unknown, create is true, and * you do not have write access */ AceTag aceTag(char* name, Bool create); AceKey aceKey(char* fullname, Bool create); AceKeySet aceKeys(AceStringSet fullnames, Bool create); /*************************************************************************** ********************* Database Administration ***************************** * * The following operations work in the server context, outside of the * user context created by aceOpen. They can only be aborted and * rolled back by aborting the server session. This does not make * sense in a server client environment, but is ok when you run a * stand-alone. */ /* Public operations */ /* reads-commit a file, possible if you have write access */ AceKeySet aceParseFile(FILE* f,AceHandle h); /* usupported operations */ Bool aceAllowBlocking(Bool canBlock); /* always fail */ /* Priviledged operations */ Bool aceReadModels(void); /* Reads models and other configuration files */ Bool aceAddUpdate (Bool all) ; /* read acedb sequential update files */ /************************************************************************** ***************************** Data Access ******************************** * * An AceInstance is a developped acedb object. It is identified by * its key and must be accessed via its key, by the Open operations. * * A given key can only be opened ONCE in a given context. To gain * write access in an object, you must write-lock the corresponding * key, and this operation will fail if another user, or another of * your contexts has the lock. To prevent dead locks, you can gain * locks on sets in a single call. can be done must have * * The handle operations act on the instances and the members of the * instance sets allocated on the handle. * * All these operations return the intance locator to the root of the * instance. * */ Bool aceReadLockKey(AceInstance k) ; Bool aceReadLockKeySet(AceKeySet ks) ; Bool aceReadLockHandle(AceHandle h) ; Bool aceReadLockInstance(AceInstance a) ; Bool aceReadLockInstanceSet(AceInstanceSet as) ; Bool aceWriteLockKey(AceInstance k) ; Bool aceWriteLockKeySet(AceKeySet ks) ; Bool aceWriteLockHandle(AceHandle h) ; Bool aceWriteLockInstance(AceInstance a) ; Bool aceWriteLockInstanceSet(AceInstanceSet as) ; AceInstance aceOpenKey(AceInstance k, AceHandle h) ; AceInstanceSet aceOpenKeySet(AceKeySet ks, AceHandle h) ; Bool aceRefreshHandle(AceHandle h) ; Bool aceRefreshInstance(AceInstance a) ; Bool aceRefreshInstanceSet(AceInstanceSet as) ; Bool aceCommitHandle(AceHandle h) ; Bool aceCommitInstance(AceInstance a) ; Bool aceCommitInstanceSet(AceInstanceSet as) ; /******************* General data ******************************/ AceStringSet aceClasses(AceHandle h); /* lists all class names */ Bool aceClassSize(char* classname, int* count) ; /* number of instances in class */ AceInstance aceModel(char* classname,AceHandle h); /* sends back a model */ /******************** Editions *******************************/ /* editing objects */ /* new unique objects */ AceKey aceMakeKeyFromFormat(char* classname, char* format); /* -- unsupported, always fails */ int aceEditInstances(AceInstanceSet ks, char* command); Bool aceEditAceKeyset(AceKeySet ks, char* command); /* killing objects */ Bool aceKillName(char* instancename); Bool aceKillKey(AceKey key); Bool aceKillAceKeyset(AceKeySet ks); /******************* Grep and Queries ******************************/ /* grep. Optionally, do LongGrep. */ AceKeySet aceGrep(char* pattern, Bool doLong, AceHandle h); AceKeySet aceGrepFrom(AceKeySet, char* pattern, Bool doLong,AceHandle h); /* old style ace queries return a keyset */ AceKeySet aceQuery(char *, AceHandle h) ; AceKeySet aceFilterKeys(AceKeySet src, char* predicate,AceHandle h); Bool aceQueryInstance(AceInstance, char* queryString) ; /* filtering a set of keys/instances */ AceInstanceSet aceFilterInstances(char* predicate, AceInstanceSet src,AceHandle h); /* new style Ace Query Language, returns a table */ AceTable aceAql(char *aql) ; /* Object constructor, not yet supported */ AceTable aceMakeInstanceTable(AceInstance, int depth, AceHandle ); /************************8** Table methods ****************************/ Bool aceTableCell(AceTable table, int i, int j); AceTable aceTableByName(char* tablename, AceHandle ); /* output */ /* %a = ace %h = human %j = java %p = perl, etc. * a '*' following the format specifier indicates that either an * entire AceKeySet or an entire AceInstanceSet should be dumped. * a 'i' following the format specifier indicates that we are working * with an INSTANCE (or AceInstanceSet) instead of a AceKey or AceKeySet. */ Bool acefprintf(FILE*,char* format, ...); Bool acesprintf(char*,char* format, size_t buflen); /**********************************************************************/ /******************** Tree Manipulations *******************************/ /**********************************************************************/ KEY aceKeyOfInstance(AceInstance ins) ; /* tree manipulation */ Bool aceTestInstance(AceInstance, char* predicate, Bool moveCurrent); /* mark/goto */ AceMark aceMark( AceInstance, AceHandle ); /* create the AceMark for the caller */ Bool aceGotoMark( AceInstance, AceMark target ); /* search object */ Bool aceGotoTag( AceInstance, AceKey target ); Bool aceHasTag( AceInstance, AceKey target ); /* navigate object */ Bool aceNextChild( AceInstance ); Bool aceGotoChild( AceInstance ); /* verify the current type */ Bool aceCheckType( AceInstance , AceType ); AceType aceGetType( AceInstance ); /* verify the presence of a type in the current follow set */ Bool aceFollowedBy( AceInstance , AceType ); AceDateType aceGetDateType( AceInstance ); char* aceGetText( AceInstance, AceHandle ); int aceGetInteger( AceInstance ); float aceGetFloat( AceInstance ); AceKey aceGetKey( AceInstance ); AceTag aceGetTag( AceInstance ); /* in place modifications of the object */ Bool aceReplAceKey( AceInstance, AceKey ); Bool aceReplAceTag( AceInstance, AceTag ); Bool aceReplaceInteger( AceInstance, int ); Bool aceReplaceText( AceInstance, char* ); Bool aceReplaceFloat( AceInstance, float ); /* modify the position immediately to the right */ Bool aceAddKey( AceInstance, AceKey ); Bool aceAddTag( AceInstance, AceTag ); Bool aceAddInteger( AceInstance, int ); Bool aceAddText( AceInstance, char* ); Bool aceAddFloat( AceInstance, float ); /* attach comments to the current position */ /* comments will no longer be inserted into the structure of the * object itself, but will be added along a third dimension. */ Bool aceAddComment( AceInstance, char* ); char* aceGetComment( AceInstance, AceHandle ); /* remove everything to the right of the current position, * as well as the current node. */ Bool acePrune( AceInstance ); #ifdef _CPLUSPLUS } #endif #endif