Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
AG_OBJECT(3)		     Library Functions Manual		    AG_OBJECT(3)

NAME
     AG_Object -- agar object system

SYNOPSIS
     #include <agar/core.h>

DESCRIPTION
     The  Agar	object	system provides object-oriented programming capabilities
     (inheritance and virtual  functions)  as  well  as  serialization,  managed
     timers, abstracted data types and a virtual filesystem (VFS).

     Agar  objects  are  organized in a tree structure, which we refer to as the
     VFS.  Any AG_Object can become the root of a VFS.	A VFS can be  made  per-
     sistent to the degree required by the application.  Agar objects can be se-
     rialized to a machine-independent binary format with AG_DataSource(3).

OBJECT INTERFACE
     AG_Object	*  AG_ObjectNew(AG_Object  *parent, const char *name, AG_Object-
     Class *classInfo)

     void AG_ObjectInit(AG_Object *obj, AG_ObjectClass *classInfo)

     void AG_ObjectAttach(AG_Object *newParent, AG_Object *child)

     void AG_ObjectDetach(AG_Object *child)

     void AG_ObjectMoveToHead(AG_Object *obj)

     void AG_ObjectMoveToTail(AG_Object *obj)

     void AG_ObjectMoveUp(AG_Object *obj)

     void AG_ObjectMoveDown(AG_Object *obj)

     void AG_ObjectDelete(AG_Object *obj)

     AG_Object * AG_ObjectRoot(AG_Object *obj)

     AG_Object * AG_ObjectParent(AG_Object *obj)

     AG_Object * AG_ObjectFind(AG_Object *vfsRoot, const char *format, ...)

     AG_Object * AG_ObjectFindS(AG_Object *vfsRoot, const char *name)

     AG_Object * AG_ObjectFindParent(AG_Object *obj,  const  char  *name,  const
     char *type)

     AG_Object * AG_ObjectFindChild(AG_Object *obj, const char *name)

     char * AG_ObjectGetName(AG_Object *obj)

     int AG_ObjectCopyName(AG_Object *obj, char *buf, AG_Size bufSize)

     void AG_ObjectSetName(AG_Object *obj, const char *fmt, ...)

     void AG_ObjectSetNameS(AG_Object *obj, const char *name)

     void   AG_ObjectGenName(AG_Object	*obj,  AG_ObjectClass  *classInfo,  char
     *name, AG_Size nameSize)

     void AG_ObjectGenNamePfx(AG_Object *obj, const char  *prefix,  char  *name,
     AG_Size nameSize)

     AGOBJECT_FOREACH_CHILD(AG_Object *child, AG_Object *parent, TYPE type)

     The AG_ObjectNew() function allocates and initializes a new object instance
     of the class described by classInfo.  The object is attached to parent (un-
     less  parent  is NULL).  If insufficient memory is available, or parent and
     name are both specified and a child object of the given name already exists
     then AG_ObjectNew() fails and return NULL.

     AG_ObjectInit() initializes an already-allocated instance of the class  de-
     scribed  by classInfo.  It invokes the init() method over each class in the
     inheritance hierarchy.

     The name argument to AG_ObjectNew() and AG_ObjectInit()  may  be  NULL,  in
     which case a unique name (e.g., "object0") will be generated.  name may not
     exceed  AG_OBJECT_NAME_MAX  characters  and  must	not  contain  `/'.   The
     classInfo argument must point to an  initialized  AG_ObjectClass  structure
     (see "OBJECT CLASSES").

     AG_ObjectAttach()	attaches  an  object  child to another object newParent,
     raising an `attached' event.  It's a no-op if newParent is NULL.

     AG_ObjectDetach() removes an object child from its parent	(if  any),  can-
     celling scheduled AG_Timer(3) expirations before raising `detached'.

     AG_ObjectMoveUp(),  AG_ObjectMoveDown(),  AG_ObjectMoveToHead()  and AG_Ob-
     jectMoveToTail() move the object in the parent object's list of  child  ob-
     jects.  This is useful when the ordering of objects is important.

     AG_ObjectDelete() calls AG_ObjectDetach() followed by AG_ObjectDestroy().

     AG_ObjectRoot()  returns  a  pointer to the root of the VFS which the given
     object is attached to.  AG_ObjectParent() returns the object's parent.

     The AG_ObjectFind() function returns the object corresponding to the speci-
     fied path name.  If there is no such object it returns NULL.

     AG_ObjectFindParent() returns the first ancestor of the object matching ei-
     ther the name of the object (if name is non-NULL) or the class of	the  ob-
     ject (if type is non-NULL).

     AG_ObjectFindChild()  searches  the child objects directly under obj for an
     object called name.  It returns a pointer to the object if found or NULL.

     AG_ObjectGetName() returns an  autoallocated  string  containing  the  full
     pathname  of  an object (relative to the root of its VFS).  If insufficient
     memory is available to construct the path, it fails and returns NULL.

     AG_ObjectCopyName() copies the object's full pathname (relative to its  VFS
     root)  to	a fixed-size buffer buf of size bufSize in bytes.  Components of
     the path are separated by the path separator AG_PATHSEP ("/" or "\").   The
     returned  pathname  is guaranteed to begin and to end with the path separa-
     tor.  AG_ObjectCopyName() returns 0 on success or -1 if buf is too small to
     contain the complete path.

     AG_ObjectSetName() updates the name of the given object.  If the object  is
     attached to a VFS then the VFS must be locked.

     AG_ObjectGenName()  generates a unique name for a child object of obj.  The
     class name (converted to lowercase) is used as prefix followed by an  inte-
     ger  (starting  from 0 and counting up).  The generated string is copied to
     the fixed-size buffer name of size nameSize in  bytes.   The  AG_ObjectGen-
     NamePfx()	variant  generates  a name using the specified prefix instead of
     the class name.

     The AGOBJECT_FOREACH_CHILD() macro iterates child over every  child  object
     of  parent.  The child pointer is cast to type.  In Debug builds, an object
     validity and class-membership test is performed.

OBJECT CLASSES
     void AG_RegisterClass(AG_ObjectClass *classInfo)

     void AG_UnregisterClass(AG_ObjectClass *classInfo)

     AG_ObjectClass * AG_CreateClass(const char *classSpec, AG_Size  objectSize,
     AG_Size classSize, Uint major, Uint minor)

     AG_ObjectInitFn AG_ClassSetInit(AG_ObjectClass *cl, AG_ObjectInitFn fn)

     AG_ObjectResetFn AG_ClassSetReset(AG_ObjectClass *cl, AG_ObjectResetFn fn)

     AG_ObjectDestroyFn   AG_ClassSetDestroy(AG_ObjectClass   *cl,  AG_ObjectDe-
     stroyFn fn)

     AG_ObjectLoadFn AG_ClassSetLoad(AG_ObjectClass *cl, AG_ObjectLoadFn fn)

     AG_ObjectSaveFn AG_ClassSetSave(AG_ObjectClass *cl, AG_ObjectSaveFn fn)

     AG_ObjectEditFn AG_ClassSetEdit(AG_ObjectClass *cl, AG_ObjectEditFn fn)

     void AG_DestroyClass(AG_ObjectClass *cl)

     void AG_RegisterNamespace(const char *name, const char *prefix, const  char
     *url)

     void AG_UnregisterNamespace(const char *name)

     AG_ObjectClass * AG_LookupClass(const char *classSpec)

     AG_ObjectClass * AG_LoadClass(const char *classSpec)

     void AG_RegisterModuleDirectory(const char *path)

     void AG_UnregisterModuleDirectory(const char *path)

     int AG_OfClass(AG_Object *obj, const char *pattern)

     char * AG_ObjectGetClassName(const AG_Object *obj, int full)

     AG_ObjectClass * AG_ObjectSuperclass(const AG_Object *obj)

     int  AG_ObjectGetInheritHier(AG_Object  *obj,  AG_ObjectClass  **pHier, int
     *nHier)

     AGOBJECT_FOREACH_CLASS(AG_Object  *child,	AG_Object  *parent,  TYPE  type,
     const char *pattern)

     The  AG_RegisterClass()  function	registers a new object class.  classInfo
     should be an initialized AG_ObjectClass structure:

     typedef struct ag_object_class {
	     char hier[AG_OBJECT_HIER_MAX];  /* Full inheritance hierarchy */
	     AG_Size size;		     /* Size of instance structure */
	     AG_Version ver;		     /* Version numbers */
	     void (*init)(void *obj);
	     void (*reset)(void *obj);
	     void (*destroy)(void *obj);
	     int  (*load)(void *obj, AG_DataSource *ds, const AG_Version *ver);
	     int  (*save)(void *obj, AG_DataSource *ds);
	     void *(*edit)(void *obj);
     } AG_ObjectClass;

     New methods (and other class-specific data) can  be  added  by  overloading
     AG_ObjectClass.  For example, AG_WidgetClass adds GUI-specific methods:

     typedef struct ag_widget_class {
	     struct ag_object_class _inherit;

	     void (*draw)(void *);
	     void (*size_request)(void *, AG_SizeReq *);
	     /* ... */
     } AG_WidgetClass;

     The  first field hier describes the full inheritance hierarchy.  The string
     "Agar(Widget:Button)" (or "AG_Widget:AG_Button") says that AG_Button  is  a
     direct subclass of AG_Widget.

     If  a class requires dynamically loadable modules (see AG_DSO(3)), the list
     of modules can be indicated in the hier  string  by  appending  "@"  and  a
     comma-separated list of library names.  For example:

	   "AG_Widget:MY_Widget@myLib,myOtherLib"

     The  size	member specifies the size in bytes of the object instance struc-
     ture.  ver is an optional datafile version number (see AG_Version(3)).

     The init() method initializes a new object instance.  It's called by AG_Ob-
     jectInit() (and AG_ObjectNew() after a successful allocation).

     The reset() method is an optional cleanup routine.  It's called  by  AG_Ob-
     jectLoad() before load() and by AG_ObjectDestroy() before destroy().

     The destroy() method frees all resources allocated by the object.

     The load() method reads the serialized state of object obj from data source
     ds.   save()  saves  the state of obj to data source ds.  load() and save()
     must both return 0 on success or -1 on failure.  See  AG_DataSource(3)  and
     the "SERIALIZATION" section.

     edit()  is  an application-specific method.  In a typical Agar GUI applica-
     tion edit() may generate and return an AG_Window(3) or an AG_Box(3).

     AG_UnregisterClass() removes the specified object class.

     AG_CreateClass() provides an alternative interface to the passing of a sta-
     tically-initialized   AG_ObjectClass   structure	to   AG_RegisterClass().
     AG_CreateClass()  allocates and initializes an AG_ObjectClass structure (or
     derivative thereof).  AG_ClassSetInit(), AG_ClassSetReset(), AG_ClassSetDe-
     stroy(), AG_ClassSetLoad(), AG_ClassSetSave() and AG_ClassSetEdit() set the
     function pointer for the respective method (returning the previous one).

     AG_DestroyClass() unregisters and frees  an  auto-allocated  AG_ObjectClass
     (or derivative thereof).

     AG_RegisterNamespace()  registers	a new namespace with the specified name,
     prefix and informational URL.  For example, Agar registers its own using:

	   AG_RegisterNamespace("Agar", "AG_", "https://libagar.org/");

     Once the namespace is registered, it is possible to specify inheritance hi-
     erarchies using the partitioned namespace format:

	   Agar(Widget:Button):MyLib(MyButton)

     which is equivalent to the conventional format:

	   AG_Widget:AG_Button:MY_Button

     AG_UnregisterNamespace() deletes the specified namespace.

     The AG_LookupClass() function searches  for  the  AG_ObjectClass  structure
     corresponding  to	the  given  class The classSpec string can be in conven-
     tional or partitioned namespace format  (see  AG_RegisterNamespace()).   If
     the search is unsuccessful, it returns NULL.

     AG_LoadClass()  ensures that the class specified by the classSpec string is
     registered, possibly loading dynamic libraries if needed.	If the class de-
     scription string includes libraries (e.g., "@lib1,lib2")  then  the  regis-
     tered   modules  directories  (see  AG_RegisterModuleDirectory())	will  be
     scanned and the needed modules loaded automatically.

     Library names in class description strings should be bare,  without  prefix
     or  suffix  (the  actual filename on disk being platform-dependent).  Valid
     libraries 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'), which should be a pointer to the AG_ObjectClass  describing
     the object class.

     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 speci-
     fied directory from the search path.

     The AG_OfClass() function tests whether obj is an instance of the class de-
     scribed by pattern and returns 1 if  the  object  belongs	to  that  class.
     pattern is a class description string which may include "*" wildcards.  For
     example,  "AG_Widget:AG_Button:*"	would match the "AG_Button" class or any
     subclass thereof.	The pattern "AG_Widget:AG_Button" would match  only  the
     "AG_Button" class but not its subclasses.	Fast paths are provided for pat-
     terns  such  as "Super:Sub:*" and "Super:Sub", but general patterns such as
     "Super:*:Sub:*" are also supported.

     AG_ObjectGetClassName() returns a	newly-allocated  string  containing  the
     name  of the class of an object obj.  If full is 1, return the complete in-
     heritance hierarchy (e.g., "AG_Widget:AG_Button").  Otherwise, return  only
     the subclass (e.g., "AG_Button").

     AG_ObjectSuperclass()  returns a pointer to the class description structure
     of the superclass of obj.	If obj is an  instance	of  the  base  AG_Object
     class then the base class (i.e., agObjectClass 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_Ob-
     jectGetInheritHier()  returns  0  on success or -1 if there is insufficient
     memory.

     The AGOBJECT_FOREACH_CLASS() macro iterates child over every  child  object
     of  parent  which	is  an	instance of the class specified in pattern.  The
     pattern argument is a class description string (that may include "*").  The
     child variable is cast to type with type checking in Debug builds	(and  no
     checking in Release builds).

SERIALIZATION
     int AG_ObjectLoad(AG_Object *obj)

     int AG_ObjectLoadFromFile(AG_Object *obj, const char *file)

     int AG_ObjectLoadFromDB(AG_Object *obj, AG_Db *db, const AG_Dbt *key)

     int AG_ObjectLoadData(AG_Object *obj)

     int AG_ObjectLoadDataFromFile(AG_Object *obj, const char *file)

     int AG_ObjectLoadGeneric(AG_Object *obj)

     int AG_ObjectLoadGenericFromFile(AG_Object *obj, const char *file)

     int AG_ObjectSave(AG_Object *obj)

     int AG_ObjectSaveAll(AG_Object *obj)

     int AG_ObjectSaveToFile(AG_Object *obj, const char *path)

     int AG_ObjectSaveToDB(AG_Object *obj, AG_Db *db, const AG_Dbt *key)

     int AG_ObjectSerialize(AG_Object *obj, AG_DataSource *ds)

     int AG_ObjectUnserialize(AG_Object *obj, AG_DataSource *ds)

     int AG_ObjectReadHeader(AG_DataSource *ds, AG_ObjectHeader *header)

     These  functions  implement  serialization, or archiving of the state of an
     AG_Object to a flat, 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 part of the object is
     loaded first, followed by any class-specific serialized data (which is read
     by invoking the load() function over every class in the inheritance hierar-
     chy).

     The AG_ObjectLoad(), AG_ObjectLoadGeneric() and  AG_ObjectLoadData()  func-
     tions  look  for  an  archive  file  in  the default search path (using the
     AG_CONFIG_PATH_DATA of AG_Config(3)).

     The AG_ObjectLoadFromFile(), AG_ObjectLoadGenericFromFile() and  AG_Object-
     LoadDataFromFile()  variants  attempt  to load the object state from a spe-
     cific 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	serialized data (which is written by invoking the save()
     function of every class in the inheritance hierarchy).

     AG_ObjectSave() creates an archive of the object in  the  default	location
     (the  AG_CONFIG_PATH_DATA of AG_Config(3)).  The AG_ObjectSaveAll() variant
     saves the object's children as  well  as  the  object  itself.   AG_Object-
     SaveToFile()  archives  the  object  to the specified file.  AG_ObjectSave-
     ToDB() 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 attempts to read the header of a serial-
     ized Agar object from a AG_DataSource(3) and returns 0 on success or -1  if
     no  valid header could be read.  On success, header information is returned
     into the header structure:

     typedef struct ag_object_header {
	     char hier[AG_OBJECT_HIER_MAX];	 /* Inheritance hierarchy */
	     char libs[AG_OBJECT_LIBS_MAX];	 /* Library list */
	     char classSpec[AG_OBJECT_HIER_MAX]; /* Full class string */
	     Uint32 dataOffs;			 /* Dataset offset */
	     AG_Version ver;			 /* AG_Object version */
	     Uint flags;			 /* Object flags */
     } AG_ObjectHeader;

FINALIZATION
     void AG_ObjectDestroy(AG_Object *obj)

     void AG_ObjectReset(AG_Object *obj)

     void AG_ObjectFreeEvents(AG_Object *obj)

     void AG_ObjectFreeVariables(AG_Object *obj)

     void AG_ObjectFreeChildren(AG_Object *obj)

     void AG_ObjectFreeChildrenOfType(AG_Object *obj, const char *pattern)

     void AG_ObjectFreeChildrenOfTypeLockless(AG_Object *obj, const  char  *pat-
     tern)

     AG_ObjectReset() restores the state of an object to some initial state.  It
     invokes  the  object's  reset(), which is expected to bring the object to a
     consistent state prior to deserialization (before load()).

     AG_ObjectDestroy() frees all resources allocated by an object.  It  invokes
     the  reset() and destroy() methods over each class in the inheritance hier-
     archy.  AG_ObjectDestroy() also cancels any scheduled  AG_Timer(3)  expira-
     tion.  AG_ObjectDestroy() implies AG_ObjectFreeEvents(), AG_ObjectFreeVari-
     ables()  and  AG_ObjectFreeChildren().   Unless  AG_OBJECT_STATIC	is  set,
     AG_ObjectDestroy() also implies free(3).

     AG_ObjectFreeEvents() clears all configured event handlers (also cancelling
     any scheduled timer expirations).

     AG_ObjectFreeVariables() clears the AG_Variable(3) table of the object.

     The AG_ObjectFreeChildren() routine invokes  AG_ObjectDetach()  and  AG_Ob-
     jectDestroy() over every child object under parent.

     AG_ObjectFreeChildrenOfType()  invokes  AG_ObjectDetach()	and AG_ObjectDe-
     stroy() on every child object under parent which  is  an  instance  of  the
     class  described  by  pattern  (see AG_OfClass(3)).  The AG_ObjectFreeChil-
     drenOfTypeLockless() variant assumes obj is locked.

THREADS
     void AG_ObjectLock(AG_Object *obj)

     void AG_ObjectUnlock(AG_Object *obj)

     void AG_LockVFS(AG_Object *obj)

     void AG_UnlockVFS(AG_Object *obj)

     void AG_ObjectDetachLockless(AG_Object *child)

     void AG_ObjectFreeChildrenLockless(AG_Object *obj)

     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().

     The  AG_ObjectLock()  mutex can be used as a general-purpose locking device
     which is guaranteed to be held during processing of all  events  posted  to
     the object as well as during object method such as load() and save().

     AG_LockVFS()  and AG_UnlockVFS() acquire or release the lock which protects
     the layout of the entire VFS which obj is a part of.

     Agar is compiled without threads support ("--disable-threads") then  AG_Ob-
     jectLock(), AG_ObjectUnlock(), AG_LockVFS() and AG_UnlockVFS() are no-ops.

     The  AG_ObjectDetachLockless() call is a variant of AG_ObjectDetach() which
     assumes that parent and child are locked.

     The AG_ObjectFreeChildrenLockless() call is a variant of AG_ObjectFreeChil-
     dren() which assumes that parent and child are locked.

FLAGS
     The following public AG_Object flags are defined:

     AG_OBJECT_INDESTRUCTIBLE	Application-specific advisory flag.

     AG_OBJECT_STATIC		Object is statically allocated (or allocated via
				a facility other than malloc(3)).   Disable  use
				of free(3) by AG_ObjectDestroy().

     AG_OBJECT_READONLY 	Application-specific advisory flag.

     AG_OBJECT_DEBUG		Application-specific debugging flag.

     AG_OBJECT_NAME_ONATTACH	Automatically generate a unique name for the ob-
				ject as soon as AG_ObjectAttach() occurs.

EVENTS
     The AG_Object mechanism generates the following events:

     attached(AG_Object *parent)
	 The object has been attached to a new parent.

     detached(AG_Object *parent)
	 The object has been detached from its parent.

     renamed(void)
	 The object's name has changed.

     object-post-load(const char *path)
	 Invoked  by  AG_ObjectLoadData(), on success.	If the object was loaded
	 from file, path is the pathname of the file.

     bound(AG_Variable *V)
	 A new variable binding has been created, or the value	of  an	existing
	 binding has been updated; see AG_Variable(3) for details.

STRUCTURE DATA
     For the AG_ObjectClass structure (see "OBJECT CLASSES" section):

     char *hier        Full inheritance hierarchy.
     AG_Size size      Size of instance structure (in bytes).
     AG_Version ver    Versioning information (see AG_Version(3)).
     void (*init)      Initialization routine.
     void (*reset)     Cleanup routine (for AG_ObjectReset()).
     void (*destroy)   Final cleanup routine.
     int (*load)       Deserialization routine.
     int (*save)       Serialization routine.
     void *(*edit)     Application-specific entry point.

     The following read-only members are initialized internally:

     char *name 		 The name for this class only.
     char *libs 		 Comma-separated list of DSO modules.
     AG_ObjectClass *super	 Pointer to the superclass.
     TAILQ(AG_ObjectClass) sub	 Direct subclasses of this class.

     For the AG_Object structure:

     char name[AG_OBJECT_NAME_MAX]   Unique  (in parent) identifier for this ob-
				     ject instance.  May not contain `/'.

     AG_ObjectClass *cls	     A pointer to the  AG_ObjectClass  for  this
				     object's class (see "OBJECT CLASSES").

     Uint flags 		     Option  flags for this object instance (see
				     "FLAGS" section).

     TAILQ(AG_Event) events	     Table of registered event handlers (set  by
				     AG_SetEvent(3))  and virtual functions (set
				     by AG_Set<Type>Fn()).

     TAILQ(AG_Timer) timers	     Active timers (see AG_Timer(3)).

     TAILQ(AG_Variable) vars	     Named variables (see AG_Variable(3)).

     TAILQ(AG_Object) children	     Child objects.

EXAMPLES
     The following code initializes a stack-allocated object, prints  a  message
     on the debug console and finally destroys the object:

	   AG_Object myObject;

	   AG_ObjectInit(&obj, "myObject", &agObjectClass);
	   Debug(&obj, "Hello, world!\n");
	   AG_ObjectDestroy(&obj);

     The  following  code creates a VFS representing a document, searches for an
     element by name and finally destroys the VFS:

	   AG_Object *doc, *head, *title, *body, *p;
	   AG_Object *result;

	   doc	 = AG_ObjectNew(NULL, "doc",   &agObjectClass);
	   head  = AG_ObjectNew(doc,  "head",  &agObjectClass);
	   title = AG_ObjectNew(head, "title", &agObjectClass);
	   body  = AG_ObjectNew(doc,  "body",  &agObjectClass);
	   p	 = AG_ObjectNew(body, "p",     &agObjectClass);

	   result = AG_ObjectFindS(doc, "/doc/head/title");
	   if (result != NULL) {
		   AG_Verbose("Title = %s\n", result->name);
	   }
	   AG_ObjectDestroy(doc);

     The following code transforms an object's name to upper-case:

	   void
	   ObjectNameToUpper(AG_Object *obj)
	   {
		   char name[AG_OBJECT_NAME_MAX], *c;

		   if (AG_ObjectCopyName(obj, name,
		       sizeof(name)) == -1) {
			   return;
		   }
		   for (c = name; *c != '\0'; c++) {
			   *c = toupper(*c);
		   }
		   AG_ObjectSetNameS(obj, name);
	   }

     The following code attaches an object to a parent,  detaches  it  and  then
     reattaches it to a different parent:

	   AG_Object parent1, parent2, child;

	   AG_ObjectInit(&parent1, NULL, &agObjectClass);
	   AG_ObjectInit(&parent2, NULL, &agObjectClass);
	   AG_ObjectInit(&child, NULL, &agObjectClass);

	   AG_ObjectAttach(&parent1, &child);
	   AG_ObjectDetach(&child);
	   AG_ObjectAttach(&parent2, &child);

     The  following code uses AGOBJECT_FOREACH_CLASS to iterate child over every
     child object of the parent object which is an instance of "MyClass":

	   struct my_class *chld;

	   AGOBJECT_FOREACH_CLASS(chld, parent, my_class, "MyClass") {
		   printf("Child %s is an instance of MyClass.\n",
		       AGOBJECT(chld)->name);
	   }

     The following code performs a class-membership test with a pattern:

	   AG_Button *btn = AG_ButtonNew(NULL, 0, NULL);

	   if (AG_OfClass(btn, "AG_Widget:AG_Button")) {
		   /*
		    * btn is an instance of AG_Button,
		    * and NOT a subclass thereof.
		    */
	   }
	   if (AG_OfClass(btn, "AG_Widget:AG_Button:*")) {
		   /*
		    * btn is an instance of AG_Button,
		    * OR a subclass thereof.
		    */
	   }

     The following code performs the same class-membership test using the numer-
     ical class identifier (as opposed to an AG_OfClass() pattern):

	   AG_Button *btn = AG_ButtonNew(NULL, 0, NULL);

	   if (OBJECT(btn)->cid == AGC_BUTTON) {
		   /*
		    * btn is an instance of AG_Button,
		    * and NOT a subclass thereof.
		    */
	   }
	   if (AG_BUTTON_ISA(btn)) {
		   /*
		    * btn is an instance of AG_Button
		    * OR a subclass thereof.
		    */
	   }

     The following code registers a new class "MyClass" and instantiates it:

	   AG_ObjectClass myClass = {
		   "MY_Class",
		   sizeof(AG_Object),
		   { 1,0, 1234, 0xE03A },
		   NULL,    /* init */
		   NULL,    /* reset */
		   NULL,    /* destroy */
		   NULL,    /* load */
		   NULL,    /* save */
		   NULL     /* edit */
	   };

	   AG_Object *obj;

	   AG_RegisterClass(&myClass);

	   obj = AG_ObjectNew(NULL, NULL, &myClass);
	   Debug(obj, "Hello, world!\n");

	   AG_ObjectDestroy(obj);

     The following code  implements  a	new  class  "MY_Dummy"	which  overloads
     AG_Object	with  new  structure members.  It also handles serialization and
     provides a public interface in C.	The public header file follows:

	   /*
	    * Public header file for MY_Dummy (my_dummy.h).
	    */
	   typedef struct my_dummy {
		   struct ag_object _inherit; /* AG_Object ->
						 MY_Dummy */
		   Uint flags;
	   #define MY_DUMMY_OPT1 0x01  /* Some option */
	   #define MY_DUMMY_OPT2 0x02  /* Another option */
		   int x,y;	       /* Some integers */
		   void *myData;       /* Allocated data */
	   } MY_Dummy;

	   extern AG_ObjectClass myDummyClass;
	   MY_Dummy *_Nullable MY_DummyNew(int, int, Uint);

     The implementation follows:

	   /*
	    * Implementation of MY_Dummy (my_dummy.c).
	    */
	   #define MYDATASIZE 1024

	   MY_Dummy *
	   MY_DummyNew(int x, int y, Uint flags)
	   {
		   MY_Dummy *d;

		   d = AG_TryMalloc(sizeof(MY_Dummy));
		   if (d == NULL) {
			   return (NULL);
		   }
		   AG_ObjectInit(d, &mdDummyClass);
		   d->x = x;
		   d->y = y;
		   d->flags = flags;
		   return (d);
	   }

	   static void
	   Init(void *_Nonnull obj)
	   {
		   MY_Dummy *d = obj;

		   d->flags = 0;
		   d->x = 0;
		   d->y = 0;
		   d->myData = Malloc(MYDATASIZE);
		   memset(d->myData, 0, MYDATASIZE);
	   }

	   static void
	   Destroy(void *_Nonnull obj)
	   {
		   MY_Dummy *d = obj;

		   free(d->myData);
	   }

	   static int
	   Load(void *_Nonnull obj, AG_DataSource *_Nonnull ds,
	       const AG_Version *_Nonnull ver)
	   {
		   MY_Dummy *d = obj;

		   d->flags = AG_ReadUint8(ds);
		   d->x = (int)AG_ReadUint16(ds);
		   d->y = (int)AG_ReadUint16(ds);
		   return AG_Read(ds, d->myData, MYDATASIZE);
	   }

	   static int
	   Save(void *_Nonnull obj, AG_DataSource *_Nonnull ds)
	   {
		   MY_Dummy *d = obj;

		   AG_WriteUint8(ds, (Uint8)(d->flags));
		   AG_WriteUint16(ds, (Uint16)d->x);
		   AG_WriteUint16(ds, (Uint16)d->y);
		   return AG_Write(ds, d->myData, MYDATASIZE);
	   }

	   AG_ObjectClass myDummyClass = {
		   "MY_Dummy",
		   sizeof(MY_Dummy),
		   { 1,0, 0,0 },
		   Init,
		   NULL,      /* reset */
		   Destroy,
		   Load,
		   Save,
		   NULL       /* edit */
	   };

     The following code maps the "MY_" prefix to a new namespace "MyPackage" and
     uses it in the class description string classSpec passed to the  AG_Lookup-
     Class() function:

	   AG_ObjectClass *C;

	   AG_RegisterNamespace("MyPackage", "MY_",
	       "https://example.com/");

	   AG_RegisterClass(&myImageViewerClass);

	   C = AG_LookupClass("Agar(Widget):"
			      "MyPackage(ImageViewer)");
	   if (C != NULL) {
		   AG_Verbose("Found class %s\n", C->name);
		   AG_Verbose("Structure size = %d\n", C->size);
	   }

     The following code prints the inheritance hierarchy of an object:

	   void
	   PrintInheritHier(AG_Object *obj)
	   {
		   AG_ObjectClass *hier;
		   int nHier, i;

		   if (AG_ObjectGetInheritHier(obj,
		       &hier, &nHier) != 0) {
			   AG_FatalError(NULL);
		   }
		   AG_Verbose("AG_Object");
		   for (i = 0; i < nHier; i++) {
			   AG_Verbose(" -> %s",
			       hier[i]->name);
		   }
		   AG_Verbose("\n");
		   AG_Free(hier);
	   }

     The  following  code  loads  an  object  from a file, increments a variable
     counter and writes back the object to the file:

	   AG_Object obj;
	   int counter;

	   AG_ObjectInit(&obj, NULL, &agObjectClass);
	   AG_SetInt(&obj, "counter", 0);

	   if (AG_ObjectLoadFromFile(&obj,
	       "test.obj") == -1)
		   AG_FatalError(NULL);

	   counter = AG_GetInt(&obj, "counter");
	   AG_Debug(&obj, "Counter: %d -> %d\n",
	       counter, counter+1);
	   AG_SetInt(&obj, "counter", counter+1);

	   AG_ObjectSaveToFile(obj, "test.obj");

     The Agar GUI represents user interfaces using a tree  of  AG_Widget(3)  ob-
     jects  attached  to  a parent AG_Window(3) which is itself attached to some
     parent AG_Driver(3).

     The SG(3) scene-graph structure of Agar-SG is a VFS of SG_Node(3)	objects.
     Non-visible nodes can be paged out to storage, saving memory.

     Edacious  (https://edacious.hypertriton.com/)  represents	circuits, compo-
     nents and simulation data using an in-memory VFS.	Circuits are saved to  a
     flat  binary  file  which embeds the circuit's serialized data with that of
     its sub-components (which may include third-party components, in which case
     AG_Object will autoload any required DSOs).

SEE ALSO
     AG_Event(3), AG_Intro(3), AG_Timer(3), AG_Variable(3)

HISTORY
     The AG_Object interface appeared in Agar 1.0.   AG_ObjectFreeDataset()  was
     renamed  AG_ObjectReset()	in  Agar 1.6.0.  The functions AG_CreateClass(),
     AG_ClassSetInit(), AG_ClassSetReset(),  AG_ClassSetDestroy(),  AG_ClassSet-
     Load(),  AG_ClassSetSave(), AG_ClassSetEdit(), AG_DestroyClass() and AG_Ob-
     jectGetClassName() appeared in Agar 1.6.0.

Agar 1.7			December 21, 2022		    AG_OBJECT(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=AG_Object&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help