|The Agar object system provides object-oriented programming functionality (e.g., inheritance, virtual functions) to applications written in different languages (currently C, C++, Objective C, Perl and Ada). Agar objects can be organized into a virtual filesystem (VFS), and the process of archiving (serialization) is tightly integrated in the object system.|
The AG_ObjectNew() function allocates and initializes a new object instance of the given class. The object is attached to parent, unless the argument is NULL. If name is NULL, a unique name of the form <class-name> #<number> is automatically generated. If both parent and name are specified and the parent object already has a child of the given name, AG_ObjectNew() fails and returns NULL.
The AG_ObjectInit() function initializes an object of the specified class. This involves invoking the init() operation associated with every class in the inheritance hierarchy The name argument specifies a name for the object instance relative to its parent (maximum AG_OBJECT_NAME_MAX bytes and must not contain " / " characters). classInfo should point to an initialized AG_ObjectClass structure (see CLASSES section). The flags argument specifies a default set of flags (see FLAGS section).
The AG_ObjectInitStatic() variant of AG_ObjectInit() implicitely sets the AG_OBJECT_STATIC flag (see FLAGS). The AG_ObjectInitNamed() variant either implicitely calls AG_ObjectSetNameS() if the name argument is non-NULL, or it sets the AG_OBJECT_NAME_ONATTACH flag if the name is NULL (see FLAGS section for details).
The function AG_ObjectAttach() attaches an object to a new parent and AG_ObjectDetach() detaches an object from its current parent. These operations raise attached and detached events. Prior to detaching the object, AG_ObjectDetach() cancels any scheduled AG_Timer(3) callback (unless the timer has the AG_TIMER_SURVIVE_DETACH flag). If parent is NULL, AG_ObjectAttach() is a no-op.
The AG_ObjectMoveUp(), AG_ObjectMoveDown(), AG_ObjectMoveToHead() and AG_ObjectMoveToTail() functions move the object in the parent object's list of child objects. These functions are useful when the ordering is important - when the child objects represent a stack, for instance.
The AG_ObjectDelete() routine invokes AG_ObjectDetach() if the object is attached to a parent, followed by AG_ObjectDestroy().
AG_ObjectAttachToNamed() is a variant of AG_ObjectAttach() which looks up the parent inside the specified VFS using the pathname path.
AG_ObjectRoot() returns a pointer to the root of the VFS which the given object is attached to. AG_ObjectParent() returns the immediate parent of the given object.
The AG_ObjectFind() function returns the object corresponding to the specified path name. If there is no such object, NULL is returned.
AG_ObjectFindParent() returns the first ancestor of the object matching either the name or type string (whichever is non-NULL).
AG_ObjectFindChild() performs a name lookup on the immediate children of the specified object. The function returns the matching object if it was found, otherwise NULL.
AG_ObjectGetName() returns a newly-allocated string containing the full pathname of an object. The function returns NULL if insufficient memory is available. The AG_ObjectCopyName() function copies the object's pathname to a fixed-size buffer.
AG_ObjectLock() and AG_ObjectUnlock() acquire or release the locking device associated with the given object. This is a mutex protecting all read/write members of the AG_Object structure, except parent, root and the list of child objects cobjs which are all considered part of the virtual filesystem and are instead protected by AG_LockVFS(). In most cases, it is best to use the AG_ObjectLock() mutex as a general-purpose locking device for subclasses of AG_Object, because it is guaranteed to be held during processing of events posted to the object, or object operations such as load() and save().
The AG_LockVFS() and AG_UnlockVFS() functions acquire or release the lock protecting the layout of the entire virtual system which the given object is part of.
Note that all lock/unlock functions are turned to no-ops if Agar is compiled without threads support.
AG_ObjectSetName() changes the name of the given object. If the object is attached to a VFS, it is assumed to be locked.
AG_ObjectGenName() generates an object name string unique to the specified parent object obj. The class name is used as prefix, followed by a number. The name is written to the fixed-size buffer name of the given size len. In a multithreaded context, the name is only guaranteed to remain unique as long as the parent object's VFS is locked. Similarly, AG_ObjectGenNamePfx() generates a name using the specified prefix instead of the class name.
AG_ObjectSetAttachFn() and AG_ObjectSetDetachFn() allow custom "attach" and "detach" hooks to be registered. These hooks are used where it is necessary to control the order of the child objects (for example, in the AG_Window(3) system of Agar-GUI, the ordering of window objects is important as it determines the order of rendering). The hook function is expected to insert the child object somewhere into the parent's children list.
The AGOBJECT_FOREACH_CHILD() macro iterates child over every child object of parent. The child pointer is cast to the given structure type, without type checking. Example:
The AG_RegisterClass() function registers a new object class. The classInfo argument should point to an AG_ObjectClass structure, with the following members initialized:
The AG_ObjectClass structure also contains read-only members which are initialized internally by the object system (see STRUCTURE DATA).
Traditionally, in C, the source file for an Agar object will contain a static initializer for AG_ObjectClass at the end of the file, like so:
Note that it is customary to "overload" AG_ObjectClass structure. For example, the AG_WidgetClass structure of the Agar-GUI library augments AG_ObjectClass with widget-specific operations, and the AG_ObjectClass initializer for a typical Agar widget will look like:
The hier member of AG_ObjectClass specifies the full class name, in the form AG_Superclass:AG_Subclass, or alternatively, Namespace(Superclass:Subclass) or Namespace(Superclass:Subclass)@modules. If the optional @modules string exists, it specifies a comma-separated list of dynamically-linked library (modules) accessible from AG_DSO(3). It is implied that AG_Object is the "root class", so there is no need to specify it in the string.
The size member specifies the size in bytes of the object instance structure. The ver member specifies an optional datafile version number (see AG_Version(3)).
The init() operation is responsible for initializing a new AG_Object instance.
The optional reinit() function is expected to free any data that was dynamically allocated by the load() routine. The reinit() operation is automatically invoked prior to load(), and before destroy().
The destroy() operation is called from AG_ObjectDestroy() to release any resources which are not handled by reinit() (typically, resources that were allocated in init()). Note that destroy() must not free the AG_Object structure itself as this is already done in AG_ObjectDestroy().
The load() and save() operations are responsible for archiving the dataset (see the ARCHIVING section for more information).
When defined, the edit() operation generates user interface elements allowing the user to edit the object's dataset. It is a generic operation, not dependent on any particular GUI library. If using the Agar-GUI for example, edit() is expected to create a AG_Window(3) or a container widget such as AG_Box(3).
Note that whenever the init(), reinit(), load(), save() and destroy() operations are used, they are invoked for every class in the inheritance hierarchy of the given object.
AG_UnregisterClass() removes the specified object class.
AG_RegisterNamespace() registers a new namespace with the specified name, prefix and informational URL. For example, Agar registers its own namespace using:
Once the namespace is registered, it is possible to specify inheritance hierarchies using the namespace format:
or the equivalent expanded format:
The AG_UnregisterNamespace() function removes all information about the specified namespace.
The AG_LookupClass() function looks up the AG_ObjectClass structure describing the specified class (in namespace or expanded format). If there is no currently registered class matching the specification, AG_LookupClass() returns NULL.
AG_LoadClass() ensures that the object class specified in classSpec (see AG_RegisterClass() for details on the format) is registered, possibly loading one or more dynamic library files if they are specified in the string. Dynamic library dependencies are given in the form of a terminating @lib1,lib2,... string. AG_LoadClass() scans the registered module directories (see AG_RegisterModuleDirectory()) for the libraries specified in the string. Bare library names are given (the actual filenames are platform-dependent). Libraries that are found (and not already in memory) are loaded via AG_DSO(3). The first library must define a myFooClass symbol (where myFoo is the name of the class transformed from MY_Foo), for an AG_ObjectClass structure describing the class (i.e., the same structure that is passed to AG_RegisterClass()).
AG_UnloadClass() unregisters the specified class and also decrements the reference count of any dynamically-located module associated with it. If this reference count reaches zero, the module is removed from the current process's address space.
The AG_RegisterModuleDirectory() function adds the specified directory to the module search path. AG_UnregisterModuleDirectory() removes the specified directory from the search path.
The AG_OfClass() function evaluates whether the given object is an instance of the specified class. The pattern string may contain wildcards such as MyClass:* or MyClass:*:MySubclass:*. AG_OfClass() returns 1 if the object's class matches the given pattern.
The AG_ObjectSuperclass() function returns a pointer to the AG_ObjectClass structure for the superclass of an object. Exceptionally, if the object is an instance of the base class (AG_Object), a pointer to the AG_Object class is returned.
The AG_ObjectGetInheritHier() function returns into pHier an array of AG_ObjectClass pointers describing the inheritance hierarchy of an object. The size of the array is returned into nHier. If the returned item count is > 0, the returned array should be freed when no longer in use. AG_ObjectGetInheritHier() returns 0 on success or -1 if there is insufficient memory.
The AG_ObjectGetInheritHierString() function returns into buf a string (of the form "MyClass:MySubclass:...") representing the inheritance hierarchy of an object. It is equivalent to copying the hier string of the AG_ObjectClass structure.
The AGOBJECT_FOREACH_CLASS() macro iterates child over every child object of parent which is an instance of the class specified by pattern. child is cast to the given structure type. Example:
The AG_ObjectFreeDataset() function frees any dynamically allocated resources by invoking the reinit() of every class in the inheritance hierachy. Contrary to the destroy() operation, reinit() must leave the data structures in a consistent state (e.g., for a subsequent load() operation).
The AG_ObjectDestroy() function frees all resources reserved by the given object (and any of its children that is not being referenced). AG_ObjectDestroy() invokes the reinit() and destroy() operations of every class in the inheritance hierarchy. Note that AG_ObjectDestroy() also cancels any AG_Timeout(3) event scheduled for future execution. Unless the AG_OBJECT_STATIC flag is set, AG_ObjectDestroy() invokes free(3) on the structure.
Internally, AG_ObjectDestroy() invokes AG_ObjectFreeEvents(), AG_ObjectFreeVariables(), AG_ObjectFreeDeps() and AG_ObjectFreeChildren(), but these functions may be called directly in order to destroy and reinitialize the event handler list, the AG_Variable(3) table and destroy the child objects, respectively.
In addition to reinitializing the event handler table, AG_ObjectFreeEvents() also cancels scheduled events.
AG_ObjectFreeChildren() releases all resources allocated by child objects, under the specified parent object. The function assumes that none of the child objects are currently in use.
AG_ObjectFreeDummyDeps() removes entries in the dependency table where the reference count is zero (which occur in objects that have the AG_OBJECT_PRESERVE_DEPS flag set).
The AG_ObjectRemain() function specifies the behavior of AG_ObjectPageOut() once a dataset is no longer in use. The default behavior is to free the dataset. If an argument of AG_OBJECT_REMAIN_DATA is passed, the dataset will be kept in memory.
These functions implement archiving (or "serialization") of the state of an AG_Object instance to machine-independent binary format.
The AG_ObjectLoad*() family of functions load the state of an Agar object from some binary data source. The generic AG_Object state is loaded first, followed by the object's dataset (which is read by invoking the load() operation for every class in the object's inheritance hierarchy). The AG_ObjectLoad(), AG_ObjectLoadGeneric() and AG_ObjectLoadData() functions look for an archive file in the default search path (using the load-path setting of AG_Config(3)). The AG_ObjectLoadFromFile(), AG_ObjectLoadGenericFromFile() and AG_ObjectLoadDataFromFile() variants attempt to load the object state from a specific file. The AG_ObjectLoadFromDB() variant loads the object state from the given AG_Db(3) database entry.
The AG_ObjectSave*() family of functions serialize and save the state of the given object. The generic AG_Object state is written first, followed by the object's dataset (which is written by invoking the save() operation for every class in the object's inheritance hierarchy). The AG_ObjectSave() function creates an archive of the given object in the default location (i.e., the save-path setting of AG_Config(3)). The AG_ObjectSaveAll() variant saves the object's children as well as the object itself. AG_ObjectSaveToFile() archives the object to the specified file. AG_ObjectSaveToDB() archives the object to the given AG_Db(3) entry.
The AG_ObjectSerialize() function writes an archive of the given object to the specified AG_DataSource(3), and AG_ObjectUnserialize() reads an archive of the given object.
The AG_ObjectReadHeader() routine decodes a standard Agar object archive header. On success, it returns 0 and writes the information to the header structure:
The AG_ObjectPageIn() function loads an object's dataset into memory and sets the AG_OBJECT_RESIDENT flag. AG_ObjectPageOut() checks whether an object is referenced by another object and if that is not the case, the dataset is archived to storage, freed from memory and the AG_OBJECT_RESIDENT flag is cleared. Both functions return 0 on success or -1 if an error occured.
The AG_ObjectSetArchivePath() and AG_ObjectGetArchivePath() functions respectively set or retrieve the object's application-specific archive path. In an editor application, for example, the archive path would be useful in remembering the last successful save location for a "Save" function.
The following public
AG_Object flags are defined:
AG_Object mechanism generates the following events:
AG_ObjectClass structure (see the
For the AG_Object structure:
|See tests/objsystem.c in the Agar source distribution.|
|AG_Intro(3), AG_Event(3), AG_Variable(3), AG_Timeout(3)|
|The AG_Object interface appeared in Agar 1.0|