#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<path>) and libace.a in your library path
 *  (set by -L<path>). 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


 

