Shadow.library Documentation Library Version 4.6 By David Navas Updated: 05 Feb 1992 Copyright © 1992 by David Navas All Rights Reserved NAME AddAttributes -- Create the attribute table for a class. SYNOPSIS result = AddAttributes( class, tags, num, offset ) d0 a0 a1 d0 d1 FUNCTION This function creates the array of Attribute structures that are described both by the tags and by the superclass of the passed class. Note that the array of Attributes, as stored in the class' AttributeTable, includes all of the attributes, both as described in the tags, AND as described in the superclass. If you're looking for an attribute description, you don't need to look at any superclass to find it. It is unfortunate that, unlike METHODs, attributes defined in the superclass have to copied to all subclasses. In reality, only the WATCHED attributes NEED to be copied, however this involves an increased level of complexity which has yet to be implemented, and so it remains -- 16bytes per attribute.... sigh. There are some benefits, however. Multiple inheritence of attributes is easy. It's unimplemented, but it's a hop-skip-jump away.... After forming the AttibuteTable, the attributes are qsort'ed by the attribute name, for fast attribute lookup. Note that this is a sorting by the System String's address, not by the string's value. INPUTS META class; - the new class for which to build an AttributeTable. Function returns NULL if NULL class is passed. ATTRIBUTE_TAG tags[]; - the (optional) new atributes to include. long num; - the number of additional attributes from the class' superClass -- as returned by PrepareAttrTags(). ULONG offset; - the offset at which the next attribute will reside. This is usually the size of the class' superClass. OUTPUTS long result; - result code (should be a BOOL, oh well.) Specifies whether the AttributeTable was successfully built. NULL indicates an error. RESULT The specified class' AttributeTable is initialized. BUGS none known. NOTES Attributes are guaranteed to be arranged according to the order in which they are specified in the tags[]. This allows you to build a fixed structure over several attributes, or even over the whole object definition. [Internally this is done for all of the classes, with the possible exception of the DIRECTORCLASS.] SEE ALSO PrepareAttrTags() CopyDefaultAttributes() FreeAttributes() FindAttribute() FindAttrDefn() NAME AddAutoResource -- Adds an automatically freed resource to a process. SYNOPSIS result = AddAutoResource( task, resource, key) d0 a0 d0 a1 FUNCTION This function adds the specified resource to the optionally specified task (defaults to current task) using the specified key. These resources are kept on the PROCESSCLASS' ATTR_RESOURCETREE, and are automatically freed (via a METHOD_META_REMOVE, and a DropObject() when the Tree itself is freed) whenever: a) The process receives a METHOD_META_REMOVE b) The process receives a METHOD_META_DESTROY c) A program inside of RemoveCurrentProgram() receives a ^C. d) RemoveThread() is about to return. It is important to note that the resource is TRANSFERRED to the ATTR_RESOURCETREE. So you no longer own an object pointer to the resource you passed to AddAutoResource(). Ff this is a problem you can do: AddAutoResource(NULL, UseObject(resource), MYNAME) . . . . DropObject(resource) . . INPUTS OBJECT task; - The optional task object that performs the auto-tracking. If not specified, assumes current taskObject. OBJECT resource; - The object to auto-track. char *key; - The name of the resource. Resources without names (key == NULL) are stored by their addresses. Name addresses of 0-255 are reserved for priority freeing. Resources are freed in INCREASING key order. Obviously, you can't use AddAutoResource() to add a resource at priority zero, as then the resource would be added at the address of the resource (NULL == 0). OUTPUTS BOOL result; - result code Specifies whether the resource was added correctly. If it was not, the resource is sent a METHOD_META_REMOVE, is dropped, and a FALSE value is returned to indicate an error. If the resource was NULL, then this function returns FALSE Otherwise returns TRUE RESULT The resource is now auto-tracked by the indicated process. BUGS none known. NOTES SEE ALSO RemoveAutoResource() DropObject() UseObject() NAME AddClassWatcher -- Adds a watcher to the given class. SYNOPSIS result = AddClassWatcher( watchName, director, pri, name, class ) d0 a0 a1 d2 d0 d1 FUNCTION This function will add the director to the class' attribute's watching SList at the given priority with the given name. This is a low-level function. You should use the provided DIRECTORCLASS methods instead and ask specifically for a class watcher. Example is in browser.c -- GlobalDirector.... Or see the inluded ShadowLibMethods.doc for more details INPUTS char *watchName; - the attribute name to watch OBJECT director; - the director to add to the attribute watching SList. long pri; - the priority to add the watcher as. char *name; - the name of the watcher. META class; - the class to add the watcher to. OUTPUTS BOOL result; - result code The result code is a boolean indicating the success or failure of the function call. A zero value indicates that an error occured. RESULT The director is added to the class' watch list. BUGS none known. NOTES SEE ALSO AddWatcherNode() RemoveWatcherNode() RemoveClassWatcher() NAME AddMethods -- initializes a class' method table SYNOPSIS result = AddMethods( class, tags ) d0 a0 a1 FUNCTION This function creates the array of MethodHandler structures that are described both by the tags. Note that the array of MethodHandlers, as stored in the class' MethodTable, includes only those methods described in the tags field. Unlike attributes, the superclass' methods are NOT copied down to the newly defined class. While creating the MethodHandlers, the passed procObject and defnObject are UseObject()'d, ensuring that the destination process and the defining process hang around until the class referencing the methods goes away. After forming the MethodTable, the methods are qsort'ed by the method name, for fast method lookup. Note that this is a sorting by the System String's address, not by the string's value. INPUTS META class; - required class to add the methods to. METHOD_TAG tags[]; - the (optional and NULL-terminated) array of MethodTag elements. OUTPUTS int result; - result code The result code is an integer indicating the success or failure of the function call. A zero value indicates that an error occured. RESULT The class' verbs field is initialized. BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() DestroyMethodTable() FindMethodHandle() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME AddNodeBinTree -- adds an object into binary tree. SYNOPSIS result = AddNodeBinTree( bt, object, key) d0 a0 a1 d0 FUNCTION This function will add the object into the binary tree sorted on the key provided. The object is Used() by the UseObject() call when successfully placed in the binary tree. Any number of objects may exist in any number of binary trees. There is no restriction on how many trees an object can be placed, nor in how many times an object can reside in a binary tree (as there is on Exec lists). In addition, unlike many AVLTree implementation, objects inserted with the same key are handled correctly. INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. OBJECT object; - the object to add into the tree. ULONG key; - the key value to insert on. OUTPUTS BOOL result; - result code zero on failure. (Couldn't allocate binary node) RESULT Object is added into binary tree. BUGS NOne known. NOTES Uses AVL trees. Do not depend on order of insertion on duplicate keys. (Duplicate keys do work, though.) Remember that the keys are sorted unsigned, not signed. SEE ALSO UseObject() AddNodeStringBinTree() AddNodeWatchedBinTree() FindBinNode() AddNodeStringWatchedBinTree() FreeAllNodesBinTree() RemoveWatchedBinNode() RecurseBinTree() RemoveStringWatchedBinNode() RemoveBinNode() RemoveStringBinNode() NAME AddNodeStringBinTree -- add an object to an AVLTREE keyed on a string. SYNOPSIS result = AddNodeStringBinTree( bt, object, name ) d0 a0 a1 d1 FUNCTION This function will add the object into the binary tree sorted on the name provided. The object is Used by the UseObject() call when successfully placed in the binary tree. The name uses the UseString and DropString conventions for system strings. The address of that string then determines the order the binary tree is sorted in. It is NOT sorted by the string itself, sorry. INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. OBJECT object; - the object to add into the tree. char *name; - the name to insert on. OUTPUTS BOOL result; - result code zero on failure. (Couldn't allocate binary node, or system string) RESULT The object is added into the binary tree sorted on the address of the system string that is uniquely created on the passed name. BUGS none known. NOTES Yes, the third parameter is d1, not d0 No, the binary tree is not sorted on the actual string, but on the address of the associated system string. SEE ALSO UseObject() DropString()/UseString() AddNodeBinTree() AddNodeWatchedBinTree() FindBinNode() AddNodeStringWatchedBinTree() FreeAllNodesBinTree() RemoveWatchedBinNode() RecurseBinTree() RemoveStringWatchedBinNode() RemoveBinNode() RemoveStringBinNode() NAME AddNodeStringWatchedBinTree -- add an object to a watched AVLTREE, keyed on a string. SYNOPSIS result = AddNodeStringWatchedBinTree( bt, object, name ) d0 a0 a1 d0 FUNCTION This function will add the object into the watched binary tree sorted on the name provided. The object is Used by the UseObject() call when successfully placed in the binary tree. The name uses the UseString and DropString conventions for system strings. The address of that string then determines the order the binary tree is sorted in. It is NOT sorted by the string itself, sorry. If any parties are interested, WatcherDispatch is called with W_INSERT_NODE for the flag parameter. INPUTS W_AVLTREE bt; - a pointer to the root of the watched binary tree. OBJECT object; - the object to add into the tree. char *name; - the name to insert on. OUTPUTS BOOL result; - result code zero on failure. (Couldn't allocate binary node, or system string) RESULT The object is added into the binary tree sorted on the address of the system string that is uniquely created on the passed name. BUGS none known. NOTES No, the binary tree is not sorted on the actual string, but on the address of the associated system string. SEE ALSO UseObject() DropString()/UseString() AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringWatchedBinTree() FindBinNode() FreeAllNodesBinTree() RecurseBinTree() RemoveBinNode() RemoveWatchedBinNode() RemoveStringBinNode() RemoveStringWatchedBinNode() NAME AddNodeWatchedBinTree -- adds an object into watched binary tree SYNOPSIS result = AddNodeWatchedBinTree( bt, object, key) d0 a0 a1 d0 FUNCTION This function will add the object into the watched binary tree sorted on the key provided. The object is Used() by the UseObject() call when successfully placed in the binary tree. Any number of objects may exist in any number of binary trees. There is no restriction on how many trees an object can be placed (as there is on Exec lists). If any parties are interested, WatcherDispatch is called with W_INSERT_NODE for the flag parameter. INPUTS W_AVLTREE bt; - a pointer to the root of the watched binary tree. OBJECT object; - the object to add into the tree. ULONG key; - the key value to insert on. OUTPUTS BOOL result; - result code zero on failure. (Couldn't allocate binary node) RESULT Object is added into binary tree. BUGS none known. NOTES Uses AVL trees. Do not depend on order of insertion on duplicate keys. (Duplicate keys do work, though.) Remember that the keys are sorted unsigned, not signed. SEE ALSO UseObject() AddNodeBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() FreeAllNodesBinTree() RecurseBinTree() RemoveBinNode() RemoveWatchedBinNode() RemoveStringBinNode() RemoveStringWatchedBinNode() NAME AddSListNode -- Adds a node to a prioritized singly linked list. SYNOPSIS result = AddSListNode( list, object, pri, name ) d0 a0 a1 d0 d1 FUNCTION This function adds an object into a singly linked list with the given name at the given priority (list is ordered by priority). INPUTS SList *list; - a pointer to the list to which to add the object. OBJECT object; - the object to add. long pri; - the priority char *name; - the name to add it as. OUTPUTS BOOL result; - result code The result code is an integer indicating the success or failure of the function call. A zero value indicates that an error occured. Lists of equal priorities are treated as LIFOs. RESULT The list has one more node on it -- the passed object. BUGS none known. NOTES SEE ALSO FindNodePriInSList() AddWatchedSListNode() RemoveSListNode() RemoveWatchedSListNode() NAME AddWatchedSListNode -- Adds a node to a watched, prioritized singly- linked list. SYNOPSIS result = AddWatchedSListNode( list, object, pri, name ) d0 a0 a1 d0 d1 FUNCTION This function adds an object into a watched, singly-linked list with the given name at the given priority (list is ordered by priority). If any parties are interested, WatcherDispatch is called with W_INSERT_NODE for the flag paramter. INPUTS W_SLIST list; - a pointer to the list to which to add the object. OBJECT object; - the object to add. long pri; - the priority char *name; - the name to add it as. OUTPUTS BOOL result; - result code The result code is an integer indicating the success or failure of the function call. A zero value indicates that an error occured. RESULT The list has one more node on it -- the passed object. BUGS none known. NOTES SEE ALSO AddSListNode() FindNodePriInSList() RemoveSListNode() RemoveWatchedSListNode() NAME AddWatcherNode -- Adds a watcher to the watched variable SYNOPSIS result = AddWatcherNode( wv, node, pri, name ) d0 a0 a1 d0 d1 FUNCTION This function will add a watcher object (sometimes referred to as a 'director') into the WatchedVariable wv. This is a low-level routine. You should use the provided DIRECTORCLASS method. See browser.c for some examples, or the included ShadowLibMethods.doc for more details. INPUTS W_VALUE wv; - the watched variable to watch OBJECT node; - the director to add to the watch list. long pri; - the priority to add the watcher as. char *name; - the name of the watcher. OUTPUTS BOOL result; - result code The result code is a boolean indicating the success or failure of the function call. A zero value indicates that an error occured. RESULT The director is added to the watch list. BUGS none known. NOTES SEE ALSO RemoveWatcherNode() AddClassWatcher() RemoveClassWatcher() NAME AllocateItem -- Allocates an item from a MemoryList SYNOPSIS element = AllocateItem( list ) d0 a0 FUNCTION Allocates an element from the list. The element will NOT be zeroed out, and may contain data from the last time that element was used. Elements are allocated 32 at a time via the allocfunc() that was passed to the InitTable() function. AllocateItem() doles out these elements one by one, automatically calling allocfunc() when necessary. INPUTS SEMLIST list; - the list to allocate from. OUTPUTS void *element; - element that is allocated. As with any allocation function, this function can return NULL for a failure to allocate memory. RESULT One item is allocated on the Memorylist BUGS none known. NOTES SEE ALSO InitTable() FreeTable() FreeItem() NAME BindSuperWatchers -- copies all watchers on the superClass' watched attributes to the subclass. SYNOPSIS result = BindSuperWatchers( class ) d0 a0 FUNCTION This function is called internally during METHOD_META_INIT of all classes and metas. A search is done on the immediate superClass' attributes. Any watchers found on the class' attribute list are copied to the passed class' attribute. Thus, if a new class subclassed off of WindowClass was created while running browser, the watcher that was watching all of the window classes will watch that new window class as well. INPUTS META class; - the (sub)class to bind the watchers. OUTPUTS BOOL result; - the result code. FALSE indicates failure to copy all the watchers. Probably ran out of memory allocating list nodes. RESULT The class' watched variables can now send out notification to the old class watchers for any new objects that are created and stored there, or for any changes in value made to the watched variable. BUGS none known. NOTES SEE ALSO BindWatchers() AddWatcherNode() AddClassWatcher() WatcherDispatch() NAME BindWatchers -- binds all object's attributes' watched wv_firstClass to the appropriate spot in the object's class. SYNOPSIS BindWatchers( object ) a0 FUNCTION This function is called internally during METHOD_META_INIT of all objects. It sets all watched variables in the object to have their wv_firstClass pointer pointing to the class' attributes' SList, like it is supposed to. This allows notification of any changes to the watched variable to be sent out on a class basis -- any object of the class will attempt to send notification to both the specific object, and the associated class. An example is in browser.c which is notified whenever any object is added to the ATTR_GUICHILDREN of any object whose class is a descendent of WindowClass. INPUTS OBJECT object; - the object to bind the watchers. OUTPUTS RESULT The object's watched variables can now send out notification to the class watchers. BUGS none known. NOTES SEE ALSO BindSuperWatchers() AddWatcherNode() AddClassWatcher() WatcherDispatch() NAME BlockMethod -- [un]blocks via a METHOD_FLAG_PREBLOCK, the method in a given class. SYNOPSIS BlockMethod( class, name, pri, block ) a0 a1 d0 d1 FUNCTION This function will search the class for a method of the given name. If pri is non-zero, the patched verbs list of the class is searched for a method patch of the given name and priority. This handle is then either PRE_BLOCK'd or un-PRE_BLOCK'd, according to the block flag. INPUTS META class; - the class where the method is found. char *name; - the name of the method to [un]block. WORD pri; - the priority (or nearest priority) of where the block should take effect. If pri is non-zero, a patch of that pri must exist. WORD block; - whether to block (TRUE) or to unblock (FALSE) OUTPUTS none RESULT A method may be [un]blocked. BUGS none known. Not yet tested! (31 Jan 1992) NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() DestroyMethodTable() FindMethodHandle() RemoveAllPatches() SetupMethodTags() NAME ChangeWatchedValue -- Changes a watched variable's value. SYNOPSIS ChangeWatchedValue( wv, new ) a0 d0 FUNCTION Changes the watched variable to the passed new value. If any parties are interested, WatcherDispatch is called with either W_CHANGE_ZERO or W_CHANGE_NON_ZEROin the flag parameter. INPUTS W_VALUE wv; - a watched variable to change. long new; - the value to change to. OUTPUTS RESULT The value is changed, and all parties notified. BUGS none known. NOTES SEE ALSO WatcherDispatch() NAME CopyDefaultAttributes -- Copy the default attrs into the instance SYNOPSIS CopyDefaultAttributes( object ) a0 FUNCTION This function will copy the default values, specified in the object's class, into the object. It is executed by both MetaClass and MetaCluster, and by both rootClass and rootCluster in the METHOD_META_CREATE method. It assumes the object is already filled with ZEROs. INPUTS OBJECT object; - The object whose attributes should be initialized. OUTPUTS none RESULT The object's attributes are initialized to the attribute default values stored in the object's class. Object is assumed to have already been initialized to ZEROs. BUGS none known. NOTES object is a required parameter. SEE ALSO PrepareAttrTags() AddAttributes() FreeAttributes() FindAttribute() FindAttrDefn() NAME CreateMeta -- Creates a self-referencing class description. SYNOPSIS meta = CreateMeta( description ) d0 a0 FUNCTION This function creates a Meta. A Meta is a class whose class is itself. It is useful for describing Classes and such. The current system creates two Metas: MetaClass and MetaCluster. The description is used to create the Meta using the attributes and superClass pointers. The superClass field, the attribute table and the method table are all filled in. The name is NOT, nor is any other information in the description touched. The description's object and class pointers are set up as 'meta', the method is initialized either to METHOD_META_INIT (if passed as NULL) or left as passed (if not NULL). CreateMeta then returns "DJM(description, SHADOW_MSG_FINDMETHOD)". This implies several things: You can create meta structures that need initialization by passing the appropriate arguments in the InitMeta structure. See the InitMeta structure for more details. Your METHOD_META_INIT methods should now -do-the-right-thing- when passed its own meta, rather than a proper instance of that meta. The correct method for checking for such an event is to compare 'object' with 'object->cob_class' as in: MyMethod(METHOD_ARGS, MYMETHODARGS) { if (object == object->cob_class) { /* * we were passed a meta, so * do what we needed to do with that. */ } else { /* * We were passed a proper instance, so do * what is necessary here. */ } } Specifically, you should NOT do a comparison between 'object' and 'class'. Class can change if called as a superclass method. The object might still be a meta, just not THAT method's meta.... As always, the following methods should also handle being sent a Meta: METHOD_META_DESTROY, METHOD_META_REMOVE. METHOD_META_SUB should also handle Metas by filling in the superClass pointer and passing the arguments to CreateMeta. The following code segment may be useful: MethodMetaSub(METHOD_ARGS, name, superClass, attrList, verbList) { if (!superClass) superClass = object; if (object == object->cob_class) { struct InitMeta *im; im = (struct InitMeta *)&object; im->im_object = im->im_class = NULL; im->im_method = NULL; im->im_super = superClass; /* Sigh... */ return CreateMeta(im); } . . . } A consequence of using METHOD_META_SUB to create new Metas is that the initialization parameters are truncated to match the METHOD_META_SUB parameter description, which might not pass all the required parameters into the InitMeta structure sent to CreateMeta! Please remember what you are doing. The description structure that is passed is a fixed length header with a variable length number of additional arguments (which should match the initialization routine CreateMeta calls: either the contents of description->im_method OR METHOD_META_INIT if that is NULL). As a result, this argument list MUST be terminated by a METHOD_END. Your initialization routine is responsible for setting the Meta's name and adding the meta to ShadowBase->sb_metaTree. The instances of Metas have, likewise, the same attributes as the Meta (as part of their instance, where the Metas have those attributes in both the INSTANCE and in their attribute description table). Reminder: the METHOD_META_REMOVE of the meta must distinguish between the case where the passed object != meta (meaning the object is an instance of Meta, and so should be removed from the ATTR_OBJECTLIST of the object->cob_class) and the case where object == meta (meaning the object *is* the meta, and should be removed from the system's metaTree -- &ShadowBase->sb_metaTree). Similarly for METHOD_META_DESTROY -- don't drop the object's cob_class when you destroy the meta (ie: object == object->cob_class), and do transfer the class if (object == class) :: (IpcARGTransfer(msg, 1). INPUTS struct InitMeta *im; - the initialization description. See includes OUTPUTS META meta; - the meta that was created. NULL if error. RESULT BUGS none known. NOTES SEE ALSO UseObject() DropObject() FindInstanceInMeta() NAME CreateObject -- creates an object with the same data as the ptr. SYNOPSIS object = CreateObject( ptr, size ) d0 a0 d0 FUNCTION This function creates a ClasslessObject, which can be UseObject()'d and DropObject()'d at will, whose included data is the data located in ptr, covering "size" bytes. If given both a non-NULL pointer and non-zero size, it allocates an object of sizeof(struct ClasslessObject)+size and sets up the fields according to what a ClasslessObject should look like: clb_size = size; clb_useCount = 1; clb_class = NULL; As noted, the returned object is Use'd once, so it should be DropObject()'d when its life expires. INPUTS void *ptr; - the object to effect the change upon. ULONG size; - the size of the data pointed to by ptr. OUTPUTS OBJECT object; - the allocated object. NULL if error. RESULT A new ClasslessObject is created. BUGS none known. NOTES SEE ALSO UseObject() DropObject() NAME DestroyMethodTable -- frees the array of methods. SYNOPSIS DestroyMethodTable( table ) a0 FUNCTION This function will destroy the MethodTable's array of MethodHandlers (usually the class' meta_verbs field). It resource-tracks the procObject, defnObject, and method names in the MethodHandler elements. INPUTS struct MethodTable *table; - required parameter. Usually found in class->meta_verbs. OUTPUTS RESULT The array, if a non-NULL ptr, is freed. BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() FindMethodHandle() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME DJM -- parses out the requested method, calls and/or sends out the appropriate function(s)/message(s) SYNOPSIS result = DJM( arguments, flags ) d0 a1 d1 FUNCTION This function is the work horse of the entire system. It is responsible for sending off all METHODs, whether synchronously, asynchronously, or as a function call. In addition, it also sends off all method patches as requested. DJM() caches methods for faster lookups (a bit more than twice as fast in worst case function calls). DJM() checks the class' doMethod function callback both BEFORE and AFTER any SHADOW_MSG_SUPER handling. This callback should act like DJM(), if you want to change the way DJM() works. If flags specifies that the methods should be forced to send all methods SHADOW_MSG_ASYNC or SHADOW_MSG_FORCE_ASYNC, then a single message is sent to the primary handle's procObject asynchronously with the function callback set back to DJM. DJM() is then called, where the message is parsed out by MessageParse() (Usually handled by ParseJazzMessage()), and the methods sent out as usual. This is to correctly handle the asyn. case of METHOD_FLAG_CHECK_CONTINUE. The following METHOD_FLAGs are passed in at method or patch creation in the MethodTag mtag_flags field: METHOD_FLAG_[POST|PRE]_BLOCK ends the sending of methods off as DJM() works from the highest priority patch, to the normal MethodHandle, to the lowest priority patch. POST_BLOCK ends the method chain after -that- method in the patch-chain is sent off, PRE_BLOCK ends it BEFORE that method is sent off. METHOD_FLAG_RTRN_ME informs DJM() that a patch wishes to use its return value as a possible return value, if no other method returns something farther down the priority chain. This is the default for ALL methods creatd by AddMethods(). METHOD_FLAG_CHECK_CONTINUE checks the return value returned in d1 (that's d1, not d0). If d1 is TRUE, then the method-chain is continued, if FALSE (zero), then the method chain ends at that point. A method-chain exists whenever a method is patched. These patches are called from high priority to zero, when the regular handle is called, and then lower priority patches are called. This chain of method calls can be terminated by the *_BLOCK or CHECK_CONTINUE flags mentioned above. INPUTS void **arguments; - a pointer to the arguments. First should be the object, then a valid class, then a method, then the rest of the arguments according to the MethodRef structure, ending with a METHOD_END (0x80000001) ULONG flags; - if low byte non-zero, treat as a specification for the type of method to send (SHADOW_MSG_CALL, etc.). A SHADOW_MSG_FORCE alone specifies that the method should be called. The flag affects any method patches as well. SHADOW_MSG_SUPER indicates the method should be sent to the superclass of the class as poassed in arguments[1]. SHADOW_MSG_FINDMETHOD indicates that the method needs to be lookup up in the systemString via the FindString call. OUTPUTS void *result; - result from method parse. RESULT BUGS none known. NOTES SEE ALSO DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() DestroyMethodTable() FindMethodHandle() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME DropObject -- resource tracking for shadow objects. SYNOPSIS DropObject( object ) a0 FUNCTION This function decrements the object's cob_useCount. You should Drop() an object when you free a structure that had a pointer-to-object in it. In addition, certain method calls, like METHOD_META_INIT return an object to you. When you are done using the pointer, you are expected to drop the pointer. A word about self-referencing. Self-referncing is an evil problem in useCount systems. You should DropObject() all self-references during the METHOD_META_REMOVE call of an object. For instance, if your class maintained a binary tree of gadget objects, and these gadget objects pointed back to the window object, the IDCMP_WINDOWCLOSE should do a METHOD_META_REMOVE on the window, which in turn should METHOD_META_REMOVE it's gadgets, and those gadgets should remove all references to the window object during that METHOD_META_REMOVE call. If the useCount of the object drops to zero furing DropObject(), the object's destructor (METHOD_META_DESTROY) is called. If the object in question has no class, than it is assumed to be a ClasslessObject, and the clb_size is looked at. If this field is non-zero, the object is freed, with "FreeMem(object, object->clb_size);" You must be careful when designing ASYNC METHOD_META_DESTROY methods -- please see IpcItemTransfer() for further details. INPUTS OBJECT object; - the object to effect the change upon. OUTPUTS RESULT BUGS none known. NOTES SEE ALSO UseObject() IpcItemTransfer() NAME DropString -- Removes a reference to a system string. SYNOPSIS DropString( buffer ) a2 FUNCTION This function searches the system string list for the system string corresponding to the passed buffer, then decrements the internal usage counter for that system string by one. If the counter becomes zero, that system string is freed from memory. If no string can be found to match buffer, no action is taken. INPUTS char *buffer; - equivalent string to the system string that you want the system to drop a reference to. OUTPUTS RESULT The system string corresponding to the passed buffer has one fewer references to it. BUGS none known. NOTES The buffer should be word-aligned for fastest access. SEE ALSO UseString() QuickUseString() FindString() QuickDropString() NAME FindAttrDefn -- Finds the attribute structure in the class SYNOPSIS attribute = FindAttrDefn( class, name ) d0 a0 a1 FUNCTION This function finds the Attribute structure (the element in the class' array) of the specified class. If the class has a callback attribute function, that function is called instead. Otherwise, the array is radix searched for the attribute whose name corresponds to FindString(name). INPUTS META class; - the class whose attribute is wanted returns NULL for a NULL class. char *name; - the name of the attribute to find. OUTPUTS struct Attribute *attribute; - pointer to the Attribute structure as specified in the class. RESULT BUGS none known. NOTES SEE ALSO PrepareAttrTags() FindString() AddAttributes() CopyDefaultAttributes() FreeAttributes() FindAttribute() NAME FindAttribute -- Finds the instance of the attribute in the object SYNOPSIS attribute = FindAttribute( object, name ) d0 a0 a1 FUNCTION This function will find the specified structure inside of the object and return the address of that structure. Calls FindAttrDefn() on the object's class. INPUTS OBJECT object; - the object whose attribute is wanted. returns NULL for a NULL object, or an object with a NULL class. char *name; - the name of the attribute to find. OUTPUTS void *attribute; - pointer to the object's attribute. This pointer points to the insides of an object. RESULT BUGS none known. NOTES Calls FindAttrDefn internally. SEE ALSO PrepareAttrTags() AddAttributes() CopyDefaultAttributes() FreeAttributes() FindAttrDefn() NAME FindBinNode -- Finds the object in the binary tree SYNOPSIS object = FindBinNode( bt, key ) d0 a0 d0 FUNCTION This function returns the first object in the binary tree that matched the key passed to the function. Note that a corollary function FindStringInBinTree() is usually defined as FindBinNode(bt, FindString(name)). The object is Used() via the UseObject() call. When the pointer that is returned is no longer needed, it should be Dropped() via the DropObject() call. INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. ULONG key; - the key to look for. OUTPUTS OBJECT object; - the object that is found NULL is returned if no object is found. RESULT The node is located in the binary tree. BUGS none known. NOTES Please DropObject() any objects returned when no longer needed. Remember that the keys are sorted unsigned, not signed. SEE ALSO UseObject()/DropObject() AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FreeAllNodesBinTree() RemoveWatchedBinNode() RecurseBinTree() RemoveStringWatchedBinNode() RemoveBinNode() RemoveStringBinNode() NAME FindInstanceInMeta -- Bi-level search for instances of a Meta SYNOPSIS class = FindInstanceInMeta( className, metaName ) d0 a0 a1 FUNCTION This function is useful for finding a Class. A Class always resides in the ATTR_OBJECTLIST of its defining Meta (until removed via the METHOD_META_REMOVE method). The Metas all reside in ShadowBase->sb_metaTree. Therefore, it takes two FIndStringInWatchedBinTree() calls to find a class (or Cluster). This is how FindJazzClass() and FindJazzCluster() are #defined.... INPUTS char *className; - the name of the class you are looking for. char *metaName; - the name of the Meta that the class is in. OUTPUTS OBJECT class; - the pointer to the class. NULL if can't find. RESULT BUGS none known. NOTES You should DropObject() the class when you are finished using it. SEE ALSO UseObject() DropObject() CreateMeta() NAME FindMethodHandle -- finds the associated handle in the class. SYNOPSIS handle = FindMethodHandle( class, method ) d0 a0 a1 FUNCTION This function will search the class' verb table for the required method. It does not look in any superclasses to find it. INPUTS META class; - the (optinal) class in which to find the method. char *method; - the name of the method to look for. OUTPUTS struct MethodHandle *handle; - the returned handle. NULL if not found. RESULT BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() DestroyMethodTable() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME FindNodePriInSList -- Finds an object in the singly linked list SYNOPSIS object = FindNodePriInSList( list, pri, name ) d0 a0 d0 a1 FUNCTION This function finds an object in a singly linked list with the given name at the given priority (list is ordered by priority). INPUTS SList *list; - a pointer to the list in which to find the object. long pri; - the priority char *name; - the name it was added as. OUTPUTS OBJECT object; - the object, if found. NULL otherwise. RESULT BUGS none known. NOTES The found object is UseObject()'d, please DropObject() it when you are finished using the pointer. SEE ALSO AddSListNode() AddWatchedSListNode() RemoveSListNode() RemoveWatchedSListNode() UseObject() DropObject() NAME FindString -- Find a system string SYNOPSIS string = FindString( buffer ) d0 a2 FUNCTION This function hashes the buffer string and searches on the collision binary tree for any matches. It will return the system string, if it finds it. It will NOT incremeent the internal useCount, so you should not use what is returned as either a system string, nor even as a string, but merely as an address you are searching a table for -- and even then, you must be careful of race conditions, the address should remain valid for the entire time you are searching a table or structure, or the table/structure must be locked in memory during the time you are searching it. INPUTS char *buffer; - the buffer whose system string you want to find. Given a NULL, will return a NULL OUTPUTS char *string; - the string, if found. NULL if no string. RESULT BUGS none known. NOTES The buffer should be word-aligned for fastest access. SEE ALSO UseString() QuickUseString() DropString() QuickDropString(); NAME FreeAllNodesBinTree -- Frees all nodes in a particular binary tree SYNOPSIS FreeAllNodesBinTree( bt ) a0 FUNCTION This function will remove all nodes off of the binary tree, dropping all objects, and all strings. The binary tree is assumed to contain objects sorted on a string as a key. Please do not call it on any other type of binary tree, as it would be dropping potnetially non-existant string objects. V4.2 UPDATE! You may now call it with a binary tree that is sorted on keys identical to the pointer to the objects each node holds. ie: keys added with: AddNodeBinTree(&bt, object, object); -or- with keys of less than 256, which are assumed to be merely longwords.... INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. OUTPUTS RESULT bt is now a pointer to an empty binary tree. BUGS none known. NOTES Don't call this function on a binary tree sorted by keys that aren't system strings, aren't less than 256 or aren't equal to the corresponding object. SEE ALSO AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() RemoveWatchedBinNode() RecurseBinTree() RemoveStringWatchedBinNode() RemoveBinNode() RemoveStringBinNode() NAME FreeAttributes -- Frees all Attribute structures for the class SYNOPSIS FreeAttributes( table ) a0 FUNCTION This function will free the array of Attributes in the AttributeTable. Called during METHOD_META_DESTROY for classes and metas. INPUTS struct AttributeTable *table; - pointer to the attribute table to free. Probably a pointer into a class that is going away. OUTPUTS none RESULT The memory allocated in that table is freed. The Table structure itself is NOT freed. BUGS Should probably be called DestroyAttributeTable() NOTES table is a required parameter SEE ALSO PrepareAttrTags() AddAttributes() CopyDefaultAttributes() FindAttribute() FindAttrDefn() NAME FreeClassWatchers -- frees all the watchers in the class' attributes SYNOPSIS FreeClassWatchers( class ) a0 FUNCTION This function frees all watchers left on any of the class' attribute-watching SLists. INPUTS META class; - the class whose attributes' watchers need to be removed. OUTPUTS RESULT All watchers in a class are removed. BUGS none known. NOTES For some reason, class watchers need to be removed from the class when the class is removed. Therefore, METHOD_META_REMOVE for the metas and roots call this function. SEE ALSO FreeObjectWatchers() AddClassWatcher() NAME FreeItem -- Frees an element belonging to a MemoryList SYNOPSIS FreeItem( list, ptr ) a0 a1 FUNCTION This function frees an element that was allocated via the AllocateItem() function. The element may, or may not, be returned to Exec's free memory pool, but may, thereafter, be re-used by AllocateItem for some other program. INPUTS SEMLIST list; - the MemoryList the element belongs to. void *ptr; - the element pointer OUTPUTS RESULT The element is returned to be re-used by AllocateItem for the specified MemoryList. BUGS Infinite loop occurs if ptr was not on the MemoryList. NOTES The MemoryList passed MUST be the MemoryList from which the element was allocated. SEE ALSO InitTable() AllocateItem() FreeTable() NAME FreeObjectWatchers -- frees all the watchers in the object's vars. SYNOPSIS FreeObjectWatchers( object ) a0 FUNCTION This function removes all watchers from all variables in the object. INPUTS OBJECT object; - the object whose watched variables need to be removed. OUTPUTS RESULT All watchers of all watched variables in the object are removed. BUGS none known. NOTES This function, as opposed to FreeClassWatchers(), can be called in the METHOD_META_DESTROY. The Metas and Roots currently call this function. SEE ALSO FreeClassWatchers() AddClassWatcher() NAME FreeTable -- free all the memory nodes on the MemoryList SYNOPSIS FreeTable( list ) a0 FUNCTION This function frees all resources that the MemoryList acquired during run-time. This means that any outstanding MemoryNodes are thereafter freed -- and therefore not usable to whomever may own them. No attempt is made to ensure all items have been released before all outstanding MemoryNodes are freed by the freefunc() originally passed to InitTable. FreeItem automatically frees MemoryNodes when it "feels" there are plenty of free elements available for use. However, that means that even when all elements are FreeItem()'d, there will still be many MemoryNodes on the MemoryList. This function will free those remaining MemoryNodes. INPUTS SEMLIST *list; - the MemoryList to purge. OUTPUTS RESULT The MemoryList no longer contains any outstanding resources. BUGS none known. NOTES SEE ALSO InitTable() AllocateItem() FreeItem() NAME GetTagsSize -- gets the size of a NULL terminated aray. SYNOPSIS size = GetTagsSize( tags, size ) d0 a0 d0 FUNCTION This function will find the size of a longword-NULL-terminated array. The NULL termination should be valid for the first longword of the last array element. The passed size should be the size of each array element. INPUTS void *tags; - a pointer to the array. If NULL, returns NULL long size; - the size of each element in the array. OUTPUTS long size; - the size of the array, including the NULL element. RESULT BUGS none known. NOTES SEE ALSO NAME InitOOProgram -- initialize an AmigaDOS process as a shadow process SYNOPSIS result = InitOOProgram( name ) d0 a0 FUNCTION This function will initialize the calling amigaDos process as a SHADOW process. This means that tc_UserData is HANDS OFF from that point on ('cept for read only). The process object is stored in tc_UserData and all message ports, etc. are allocated. This function MUST be called before initiating any non-CALL methods. Any methods that would require a SYNC or an ASYNC message require that a process object exist in tc_UserData of the calling task. If you want to use something other than PROCESSCLASS, then you may first set FindTask(NULL)->tc_UserData to NULL, then call METHOD_META_SUB on the process class, then send that class a METHOD_META_CREATE, then send the object that that returns a METHOD_PROC_ASSOCIATE. That's all this function does.... [Excepting the METHOD_META_SUB call, of course....] INPUTS char *name; - the name to give the process object. The name defaults to FindTask(NULL)->tc_Node.ln_Name when passed in as NULL. OUTPUTS BOOL result; - result code The result code is a boolean describing success or failure of process object creation. FALSE (0) is an error. RESULT Process object is created for the calling task. BUGS none known. NOTES tc_UserData is trashed (used) You should define a unique class for your program, and try to find that program's class when starting up. If found, instantiate that already existing class, and exit. See example: browser.c SEE ALSO RemoveCurrentProgram() NAME InitOOSystem -- private initialization routine by ramlib SYNOPSIS result = InitOOSystem( seglist ) d0 a0 FUNCTION This funtion should ONLY be called by ramlib when the library is starting up. For some reason the author is documenting the function publically. Heaven help us. The function's partner is the expunge routine. INPUTS seglist - the library's segment list that was loaded. OUTPUTS struct ShadowBase result; - The library base. RESULT The library is opened. MetaClass, metaCluster, rootClass, rootCluster, processClass, directorClass, and patcherClass are all created. BUGS none known. NOTES SEE ALSO DestroyOOSystem (internal name). AKA Expunge. (ain't no Docs :)) NAME InitTable -- Initializes a memory table. SYNOPSIS result = InitTable( list, allocfunc, freefunc, size ) d0 a0 a1 d0 d1 FUNCTION Shadow requires a number of very small elements to be coninually allocated and freed. This function initializes a struct MemoryList which attempts to ease the strain on AllocMem and FreeMem by allocating and freeing blocks that are 32 times "size". The individual elements are allocated via the AllocateItem() and FreeItem() functions. InitTable initializes the various elements of the passed MemoryList structure. INPUTS SEMLIST list; - a MemoryList to initialize. TABLENODE allocfunc(SEMLIST); - an allocation function that, given a d0 a0 MemoryList, returns a MemoryNode structure as a header to 32 elements to be doled out by AllocateItem(). If passed as NULL, the system allocates this for you. void freefunc(SEMLIST, TABLENODE); a0 a1 - a free function that, given a MemoryList and a MemoryNode, frees the Node plus the 32 elements from the List. If passed as NULL, the system frees the Node for you. long size - the size of each element. OUTPUTS BOOL result; - result code The result code is a boolean indicating the success or failure of the function call. A zero value indicates that an error occured. RESULT The specified list is initilized, the first 32 elements are allocated, the semaphore is initialized, the memlst_semUse flag in the structure is set to TRUE, and the memlst_size set to the passed size. BUGS none known. NOTES It's not very flexible, but it's used for BinNodes, semaphores, and list internal structures. It's got pretty good, but not fantastic, performance. See PerfTest. SEE ALSO AllocateItem() FreeItem() FreeTable() NAME InitThread -- initializes the process object associated with the task. SYNOPSIS task = InitThread( task ) d0 a0 FUNCTION This function initializes the passed task's object. It allocates necessary ports and messages that DJM() requires be present. When it is completed, it signals the parent task to resume. The parent waits for this signal when the thread was started. You should allocate any thread-specific information after the call to WaitThread() and before the call to InitThread(). This allows the parent to safely shutdown, in case you cannot open, say, a required library. In case you do fail to gain the required resources, you should fail in the following way: { -clean-up-any-resources-you-allocated- DoJazzMethod((OBJECT)task->tc_UserData, NULL, METHOD_META_REMOVE, METHOD_END); Signal(jproc->jp_parent, 1L << jproc->jp_parentSignal); return; } The parent will do the rest. INPUTS struct Task *task; - the task to initialize. MUST be non-NULL. OUTPUTS struct Task *task; - same as passed in. RESULT The resources required for synchronous methods are allocated, and the parent is allowed to resume processing. BUGS none known. NOTES You should NOT exit the thread until you receive a CTRL_C signal, and FindAttribute(task->tc_UserData, ATTR_JAZZPROCESS)->jp_parent is NULL. When you do exit, call RemoveThread() and then return from the top-level. SEE ALSO WaitThread() RemoveThread() FindAttribute() NAME InvalidateCache -- invalidates all cache entries for a class SYNOPSIS InvalidateCache( meta ) a0 FUNCTION This function will invalidate all entries in the method's cache that refer to the passed class. it must be called when a class is free'd. INPUTS META *meta; - a class. OUTPUTS RESULT No more references to a defunct class exists in the method calling cache. BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() SetMethodArgs() AddMethods() DestroyMethodTable() FindMethodHandle() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME IpcItemTransfer -- Transfers a resource from message to server. SYNOPSIS IpcItemTransfer( msg, num ) a0 d0 FUNCTION This function will transfer the resource found in the num'th item in msg to the calling server. Basically, the IPC_ITEM_TRANSFER flag is cleared, and the IPC_SERVER_OWNED flag is set. INPUTS struct IPCMessage *msg; - the (possibly NULL) message to xfer resources from. If msg is NULL, no action is taken. long num; - the item number where the resource is currently located. OUTPUTS none RESULT resource is no longer valid in the message. BUGS none known. NOTES SEE ALSO IpcARGTransfer() macro ppipc.library documentation. Not included in SHADOW, but available on a Fred Fish disk. NAME JunkIPCMessage -- Frees a message allocated by MessageMaker SYNOPSIS JunkIPCMessage( msg ) a0 FUNCTION This function will delete an IPCMessage, releasing all resources which have not been IpcItemTransfer()'d. The message itself is also deleted. Message should have been allocated by MessageMaker. INPUTS struct IPCMessage *msg; - the message to delete. OUTPUTS none RESULT One more message is gone. BUGS none known. NOTES SEE ALSO MessageMaker() IpcItemTransfer() NAME MessageMaker -- Creates a Message for the given MethodHandle & args. SYNOPSIS msg = MessageMaker( handle, args ) d0 a0 a1 FUNCTION This function will create a ppipc message that MessageParse() and ParseJazzMessage() can unroll in order to call a method asynchronously across tasks. Full resource tracking is done, and all resources are freed during the JunkIPCMessage() call, unless an IpcItemTransfer() was performed for that resource's item. IpcItemTransfer should be done during METHOD_META_DESTROY, at the very least. INPUTS struct MethodHandle *handle; - the method that the message should serve. Set the low bit of the address if this is actually a ptr into a MethodHandle object as returned from PatcherClass INIT. void **args; - the arguments that should be placed, one by one, into the message structure. Full resource tracking will be done for these arguments according to the MethodRef structure, so the message can be sent asynchronously. OUTPUTS struct IPCMessage *msg; - The returned message. RESULT A new message is constructed. BUGS none known. NOTES SEE ALSO JunkIPCMessage() DropObject() SetMethodArgs() ParseJazzMessage() MessageParse() NAME MessageParse -- Parses a message onto the stack. SYNOPSIS value = MessageParse( msg ) d0 a0 FUNCTION This function will parse a message onto the stack according to the MethodRef structure as passed inside of the message. The message must have exactly the right number of items, or bad things may happen. The Method is then called, and its return value returned in d0. There is also some magic which allows DJM() to be called as the function, so that methods which are forced ASYNC by the flags in an original DJM() call, actually work properly.... INPUTS struct IPCMessage *msg; - should be a valid message set up by MessageMaker(). OUTPUTS void *value; - the return value of the method call. RESULT The METHOD is called. BUGS none known. NOTES SEE ALSO MethodFuncParse() DJM() MessageMaker() NAME MethodFuncParse -- Copies the stack arguments back to the stack. SYNOPSIS return = MethodFuncParse( handle, object, class, args ) d0/d1 a2 d0 d1 a1 FUNCTION This function will copy the arguments found in args onto the stack, according to the MethodRef structure found in handle. Unlike MessageParse(), it must deal with missing arguments -- ie: it may encounter METHOD_END (0x80000001) before the end of the MethodRef argument array. The missing arguments are NULL'd out, then it calls the method function, and returns d0/d1 as a double. D0 is what should normally be considered as the return value. DJM() is incapable of returning real doubles at the current time. D1 is used by DJM() for its METHOD_FLAG_CHECK_CONTINUE. ParseJazzMessage() has some magic for storing D1 away for synchronous method calls. The 'msg' parameter of all Methods is NULL'd by MethodFuncParse(). INPUTS struct MethodHandler *handle; - the method's handle OBJECT object; - the object being called. META *class; - the class the method is defined in. void **args; - the (other) arguments to the function. OUTPUTS double return; - the return value is usually considered D0, but D1 is used by DJM() for its _CONTINUE checking. RESULT The METHOD was called. BUGS none known. NOTES SEE ALSO MessageParse() DJM() ParseJazzMessage() NAME ParseJazzMessage -- parses the three types of SHADOW messages SYNOPSIS ParseJazzMessage( msg ) a0 FUNCTION This function parses the three types of messages that SHADOW programs can receive -- AMET, SMET and JAZZ. AMET message are asynchronous messages, and these message are correctly handled by MessageParse() SMET messages are synchronous message and these message are correctly handled by MethodFuncParse() JAZZ are message you can send. The function pointer should be in the first element of the message, and the single argument to the function should be in the second argument. No value is currently returned -- but if someone needs to, please let me know. They are currently unused. The message is returned when the function is finished. INPUTS struct IPCMessage *msg; - a message sent to a SHADOW task's port. OUTPUTS none RESULT The correct function is called. Unknown messages are allowed to hang around unused..... BUGS Does not handle unknown messages without replyports properly. So don't send them! NOTES SEE ALSO MessageParse() MethodFuncParse() NAME PrepareAttrTags -- Prepares Attribute tags for class definition SYNOPSIS num = PrepareAttrTags( tags, countptr, super ) d0 a0 d1 a1 FUNCTION This function is designed specifically because of the inherent trickiness of Metas. Under normal situations, the functionality of this function would be incorporated into AddAttributes(). Unfortunately, because Metas are their own classes, the size of the Meta depends on the definitions held in the defining AttributeTags. Therefore, the Meta cannot be allocated until it knows the required size, it wouldn't know the size until the AddAttributes call, but it can't call AddAttributes until the Meta exists so that the AttributeTable pointer can be passed in. At anyrate, this function determines the number of new attribute there are (returned num) and the additional size that will be needed (by incrementing the *countptr for each new attribute). Attributes which are already contained within the super are cheerfully ignored. Respecified Attributes are assumed to be attempts to redefine the default value, not to resoecify an attribute. You probably won't need to use this function, unless you are creating your own Meta or METHODs for Metas. INPUTS ATTRIBUTE_TAG tags[]; - optional pointer to a NULL terminated array of AttributeTags. long *countptr; - initialized pointer to the long which will be incremented by the additional size required by the passed attributes. If any attributes are redefined (from the super), the size will not be incremented for that attribute. META *super; - optional pointer to a superclass. OUTPUTS long num; - number of new attributes (does not include attributes redefined from the passed super. RESULT The countptr variable is incremented by the additional size, above and beyond the size of 'super', that the passed attribute tags would require. BUGS none known. NOTES *countptr MUST be initialized, probably to the size of the superClass, as the size of the superClass is not used in calculating the size in this function. SEE ALSO AddAttributes() CopyDefaultAttributes() FreeAttributes() FindAttribute() FindAttrDefn() NAME PSem -- procures the semaphore for the given address. SYNOPSIS result = PSem( address, flags ) d0 a0 d0 FUNCTION This function semaphores the given address dictated by the following flags: SHADOW_EXCLUSIVE_SEMAPHORE 0 SHADOW_SHARED_SEMAPHORE 1 SHADOW_ATTEMPT_SEMAPHORE 2 If anyone else attempts to semaphore the same address (via PSem), the system takes appropriate action (according to the flags). if the system cannot allocate a sempahore object internally, a busy loop with a Delay(30) is used until it can. You are guaranteed that, when PSem returns, you have a lock o the semaphore -- unless SHADOW_ATTEMPT_SEMAPHORE is used, in which case you must look at the return code. INPUTS void *address; - Any address within the system. ULONG flags; - one of the three flags above. OUTPUTS BOOL result; - result code for AttemptSemaphore. Always TRUE otherwise. The result code is a Boolean indicating the success or failure of the function call. A zero value indicates that the AttemptSemaphore (when SHADOW_ATTEMPT_SEMAPHORE is passed) failed. RESULT The specified semaphore action will have taken place. BUGS none known. NOTES Although it is not strictly necessary, you will undoutedly encounter bugs if the address on which you have a semaphore is freed before the semaphore is. Mostly because another task may then allocate that address, and attempt a semaphore on it -- leading to unexpected deadly embrace conditions. The address passed need not point to an object, as the BinTree and List code require. SEE ALSO From exec.library: ObtainSemaphore() -- SHADOW_EXCLUSIVE_SEMAPHORE ObtainSemaphoreShared -- SHADOW_SHARED_SEMAPHORE AttemptSemaphore() -- SHADOW_ATTEMPT_SEMAPHORE VSem() NAME QuickDropString -- Decrements the useCount of a known system string. SYNOPSIS QuickDropString( string ) a2 FUNCTION This function decrements the useCount of a known system string. The passed string *must* be a pointer to a system string. If the useCount drops to zero, DropString is automatically called in order to delete the string object from the correct place in the system's string hash table. Therefore, only call QuickUseString when you think you will have more than one reference to them. That allows QDS() to work fastest. INPUTS char *string; - the string to lower the refcounts of the system string. OUTPUTS RESULT The given system string has had its useCount decremented. BUGS none known. NOTES SEE ALSO UseString() QuickUseString() FindString() DropString() NAME QuickUseString -- Increment the usage counter of a system string. SYNOPSIS string = QuickUseString( string ) d0 a2 FUNCTION This function increments the system usage counter for a string that you already know is a system string. This must be the *address* of the system string, not a buffer pointer equivalent. If you pass in a NULL, this function returns a NULL. You should UseString() whenever saving a suitable string into a structure -- a matching DropString() will then deallocate the reference. Under the appropriate conditions (mentioned above) you may use QuickUseString() to avoid the hash and binary search calls. INPUTS char *string; - the system string whose useCount should be incremented OUTPUTS char *string; - the system string. Exactly what was passed into it. RESULT The system string's internal useCount is incremented BUGS none known. NOTES Don't pass in arbitrary buffer pointers or you may risk overwriting your stack, or memory. SEE ALSO UseString() FindString() DropString() QuickDropString() NAME RecurseBinTree -- Recursively call a function on each BinNode of an AVLTREE SYNOPSIS result = RecurseBinTree( bt, func, data, recurse ) d0 a0 a1 d0 d1 FUNCTION This function will recurse through the binary tree, calling func() for each object found with the parameters 'object key data', where object is the object in the binary tree, key is the key that the object is sorted on, and data is the data passed into the Recurse() call. If this func() ever returns non-NULL, the recursion is stopped, and the non_NULL return code is returned to the caller of RecurseBinTree. There are three different ways to recurse through a binary tree. The following flags are defined in shadow/bintree.h: SHADOW_RECURSE_INORDER == 1 SHADOW_RECURSE_PREORDER == 2 SHADOW_RECURSE_POSTORDER == 3 The order of the recursion is determined by these flags passed as the recurse parameter. INORDER outputs the left children, then the root, then the right children. PREORDER outputs the root, the left, then the right. POSTORDER outputs the left, the right, then the root. INPUTS AVLTREE *bt; - the binary tree to recurse over. void *(*func)(void *, ULONG, void *) - the function. return value a0 d0 a1 used below. Return NULL to continue recursive calling, non-NULL to end recursive calls. Three parameters are: object, key, data. See above. void *data - the passed data long recurse - the recurse type flag. OUTPUTS void *result; - returns non-NULL of func() if func() ever returns non-NULL. Else returns NULL. RESULT func() called for each element in the binary tree. BUGS It calls a semaphore EXCLUSIVE on the AVLTREE, NOT SHARED! Sigh, I wish Exec knew enough to be able to get a SHARED semaphore on something you already had an EXCLUSIVE semaphore on. NOTES Do NOT RemoveBinNode() the object from the binary tree that you are recursing through in the passed function. AND do not call any methods that would.... Remember that the keys are sorted unsigned, not signed. SEE ALSO AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() RemoveWatchedBinNode() FreeAllNodesBinTree() RemoveStringWatchedBinNode() RemoveBinNode() RemoveStringBinNode() NAME RemoveAllPatches -- Removes all Patches from a given class. SYNOPSIS RemoveAllPatches( meta ) a0 FUNCTION This function will remove all of the method patches of a given class. This should be executed when deleting a class in which methods could be patched. It is currently called in the META_DESTROY of the metaclass and the metaCluster. Because of this, it is IMPOSSIBLE to patch the METHOD_META_DESTROY method for any metas, because they are their own classes -- the function that would call RemoveALlPatches may be in a method-chain, which would not be valid when control returned to DJM() to continue the method chain. This would be confusing, at best.... :( INPUTS META meta; - the class to delete all the patches from. OUTPUTS RESULT BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() DestroyMethodTable() FindMethodHandle() BlockMethod() SetupMethodTags() NAME RemoveAutoResource -- Removes resource from process' tracking tree. SYNOPSIS resource = RemoveAutoResource( task, resource, key ) d0 a0 d0 a1 FUNCTION The resource, which is found using the resource/key pair, is removed from the process' ATTR_RESOURCETREE and returned back to your control. No METHOD_META_REMOVE is done, and you must DropObject() the resource which is returned. Task parameter is optional and defaults to the current task. Resource parameter is optional, and defaults to whatever resource is found using the provided key. (If key >255, then key is assumed to be a string, and is handled accordingly.) INPUTS OBJECT task; - The optional task object that performs the auto-tracking. If not specified, assumes current taskObject. OBJECT resource; - The optional object being auto-tracked. If no resource, then resource is looked up on the binary tree using the value in key. char *key; - The name of the resource. Resources without names are stored by their addresses. Name addresses of 0-255 are reserved for priority freeing. Resources are freed in INCREASING key order. OUTPUTS OBJECT resource; - The resource as found. You must DropObject() the returned resource when you are no longer interested in it. RESULT BUGS none known. NOTES SEE ALSO AddAutoResource() DropObject() NAME RemoveBinNode -- Removes a node from a binary tree SYNOPSIS result = RemoveBinNode( bt, object, key ) d0 a0 a1 d0 FUNCTION This function will remove an object from the binary tree, dropping it via DropObject(). The object pointer is required to verify the correct node is being removed (in case nodes with the same key exist in the same tree). INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. OBJECT object; - the object to add into the tree. ULONG key; - the key value to insert on. OUTPUTS BOOL result returns FALSE on failure to remove. RESULT The object exists in the tree at least one fewer times than it did. BUGS none known. NOTES Remember that the keys are sorted unsigned, not signed. SEE ALSO DropObject() AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() RemoveWatchedBinNode() FreeAllNodesBinTree() RemoveStringWatchedBinNode() RecurseBinTree() RemoveStringBinNode() NAME RemoveClassWatcher -- Removes a watcher from all classes. SYNOPSIS RemoveClassWatcher( watchName, director, name, class ) a0 a1 d0 d1 FUNCTION This function will remove the director from the class' attribute watching SList of the passed name. This is a low-level routine. You should call the DIRECTOR CLASS routines instead. See browser.c, or ShadowLibMethods.doc. INPUTS char *watchName; - the attribute name that is watched OBJECT director; - the director to Remove from the attribute watching SList. char *name; - the name of the watcher. META class; - the class to remove the watcher from. OUTPUTS none RESULT The director is removed from the class' watch list. BUGS none known. NOTES SEE ALSO AddWatcherNode() RemoveWatcherNode() AddClassWatcher() NAME RemoveCurrentProgram -- removes the current process from the system. SYNOPSIS RemoveCurrentProgram( semaphore ) a0 FUNCTION This function is the counterpart of InitOOProgram(). It removes an AmigaDOS loaded program from the system so that that program can exit safely. This is SOP for cleaning up a -program-. RemoveCurrentProgram() waits for no other process to own a reference to the process associated with the program. While it does this, it handles messages on jp_port and jp_replyPort (struct JazzProcess). This function sends a METHOD_META_REMOVE to the processObject, waits on the process' jp_port and jp->replyPort for messages (which it manages by taking everything off the list, handling the messages, then checking for more signals). It also waits for a ^C and then checks that jp_parent is NULL. A program may create many threads on itself. When INIT'ing a process object, one parameter that the programmer can pass is a SEMF. This is a pointer to a semaphore that is passed in as NP_ExitData. It is ObtainShared() during the waitThread() call, and Release()'d when the thread is done executing. RemoveCurrentProgram() waits on this semaphore until all threads have exited before removing the program's process object. A NULL semaphore is dealt with appropriately. INPUTS struct SignalSemaphore *semaphore; - the thread semaphore OUTPUTS RESULT The program's process object is removed and associated ports freed. BUGS none known. NOTES SEE ALSO InitOOProgram() NAME RemoveSListNode -- removes a node from a prioritized, singly-linked list. SYNOPSIS result = RemoveSListNode( list, object, name ) d0 a0 a1 d1 FUNCTION This function removes an object from a singly linked list with the given name. INPUTS SList *list; - a pointer to the list from which to remove the object. OBJECT object; - the object to remove. char *name; - the name it was added as. OUTPUTS BOOL result; - result code returns FALSE if can't find the node to Remove. RESULT One fewer nodes are on the list. BUGS none known. NOTES SEE ALSO FindNodePriInSList() AddWatchedSListNode() AddSListNode() RemoveWatchedSListNode() NAME RemoveStringBinNode -- Removes a node from a binary tree. SYNOPSIS result = RemoveStringBinNode( bt, object, name ) a0 a1 d1 FUNCTION This function will remove an object from the binary tree, dropping it via DropObject(), and dropping the string via DropString (if found). The object pointer is required to verify that the correct node is being removed (in case nodes with the same key exist in the same tree). INPUTS AVLTREE *bt; - a pointer to the root of the binary tree. OBJECT object; - the object to add into the tree. char *name; - the name to insert on. OUTPUTS BOOL result returns FALSE on failure to remove. RESULT The object exists in the tree at least one fewer times than it did. BUGS none known. NOTES Yes, that's d1, not d0 for 'name' parameter. SEE ALSO DropObject DropString AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() RemoveWatchedBinNode() FreeAllNodesBinTree() RemoveStringWatchedBinNode() RecurseBinTree() RemoveBinNode() NAME RemoveStringWatchedBinNode -- Removes an object from the given binary tree SYNOPSIS result = RemoveStringWatchedBinNode( bt, object, name ) d0 a0 a1 d1 FUNCTION This function will remove an object from the watched binary tree, dropping it via DropObject(), and dropping the string via DropString (if found). The object pointer is required to verify the correct node is being removed (in case nodes with the same key exist in the same tree). If any parties are interested, WatcherDispatch is called with W_INSERT_NODE INPUTS W_AVLTREE *bt; - a pointer to the root of the watched binary tree. OBJECT object; - the object to add into the tree. char *name; - the name to insert on. OUTPUTS BOOL result returns FALSE on failure to remove. RESULT The object exists in the tree at least one fewer times than it did. BUGS none known. NOTES SEE ALSO DropObject DropString AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() RemoveWatchedBinNode() FreeAllNodesBinTree() RecurseBinTree() RemoveBinNode() RemoveStringBinNode() NAME RemoveThread -- removes a previously initialized thread. SYNOPSIS RemoveThread( object ) a0 FUNCTION This function deallocates the resources that were allocated by InitThread(). It should not be called until InitThread() has returned, a CTRL_C received by the thread, and the JazzProcess' jp_parent pointer (found in the taskObject -- see InitThread()) is NULL. The process' ATTR_RESOURCETREE and the process' ATTR_RESOURCESTACK are both freed -- meaning that all resources on that tree and on that list are sent a METHOD_META_REMOVE, and then all resources on that tree and list are removed from the tree/list. INPUTS OBJECT object; - the object of the task -- FindTask(NULL)->tc_UserData OUTPUTS none RESULT Resources for the thread are released. BUGS none known. NOTES Follows the conventions of exitting properly! So call it! SEE ALSO InitThread() RemoveThread() NAME RemoveWatchedBinNode -- Removes an object from the watched binary tree. SYNOPSIS result = RemoveWatchedBinNode( bt, object, key ) d0 a0 a1 d0 FUNCTION This function will remove an object from the watched binary tree, dropping it via DropObject(). The object pointer is required to verify the correct node is being removed (in case nodes with the same key exist in the same tree). If any parties are interested, WatcherDispatch is called with W_INSERT_NODE INPUTS W_AVLTREE *bt; - a pointer to the root of the watched binary tree. OBJECT object; - the object to add into the tree. ULONG key; - the key value to insert on. OUTPUTS BOOL result returns FALSE on failure to Remove. RESULT The object exists in the tree at least one fewer times than it did. Remember that the keys are sorted unsigned, not signed. BUGS none known. NOTES SEE ALSO DropObject() AddNodeBinTree() AddNodeWatchedBinTree() AddNodeStringBinTree() AddNodeStringWatchedBinTree() FindBinNode() FreeAllNodesBinTree() RemoveStringWatchedBinNode() RecurseBinTree() RemoveBinNode() RemoveStringBinNode() NAME RemoveWatchedSListNode -- removes a node from a watched, prioritized singly-linked list. SYNOPSIS result = RemoveWatchedSListNode( list, object, name ) d0 a0 a1 d1 FUNCTION This function removes an object from a watched, singly-linked list with the given name. If any parties are interested, WatcherDispatch is called with W_REMOVE_NODE for the flag parameter. INPUTS W_SLIST list; - a pointer to the list from which to remove the object. OBJECT object; - the object to remove. char *name; - the name it was added as. OUTPUTS BOOL result; - result code returns FALSE if can't Remove. RESULT One fewer nodes are on the list. BUGS none known. NOTES SEE ALSO FindNodePriInSList() AddWatchedSListNode() AddSListNode() RemoveSListNode() NAME RemoveWatcherNode -- Removes a watcher to the watched variable SYNOPSIS result = RemoveWatcherNode( wv, node, name ) a0 a1 d1 FUNCTION This removes a watcher node from a watched variable. This is a low-level routine. You should call the DIRECTOR CLASS routines instead. See browser.c, or ShadowLibMethods.doc. INPUTS W_VALUE *wv; - the watched variable being watched. OBJECT node; - the director to remove from the watch list. char *name; - the name of the watcher. OUTPUTS BOOL result returns FALSE if failed to Remove. RESULT The director is removed from the watch list. BUGS none known. NOTES SEE ALSO AddWatcherNode() AddClassWatcher() RemoveClassWatcher() NAME SetMethodArgs -- parses a MethodRef structure for method creation. SYNOPSIS SetMethodArgs( mh, args ) a0 a1 FUNCTION This function parses out the MethodRef structure. It sets up the mh_num, mh_size and mh_args field in the passed MethodHandle structure. If the function returns a variable that needs to be kept track of, the last MethodRef structure (whose mr_tag should be zero) in the array should contain information for async. method sends to safely deallocate or otherwise resource track the returned value. Valid returns are: SHADOW_RETURN_BLANK 0 SHADOW_RETURN_OBJECT 1 SHADOW_RETURN_STRING 2 SHADOW_RETURN_PORT 3 SHADOW_RETURN_TAGL 4 SHADOW_RETURN_PTR 5 These values should be stored in the mr_size field of the last MethodRef array item.. for SHADOW_RETURN_PTR, the size of the pointer should be stored in the mr_flags field of the same item. Normally, the system supports a number of mr_tag values: 'MRFO': used for object values which add sizeof(struct CoreObject) to the passed object pointer. mr_size should be four mr_flags ignored. 'JOBJ': Used for an object. mr_size should be four mr_flags should be one of: SHADOW_OBJECT SHADOW_CLASSLESSOBJECT SHADOW_META SHADOW_CLASS, SHADOW_CLUSTER SHADOW_COMPOSITE though this is more for peace of mind than necessity. 'JMSG': Used for a message creted by MessageMaker() mr_size should be four mr_flags should be zero 'JSTR': Used for a system string. mr_size should be four mr_flags should be zero 'PORT': Used for a ppipc port. mr_size should be four mr_flags should be ???? <-- anything you like! 'TAGL': Used for a NULL terminated array. mr_size should be four. mr_flags should be the size of each array item 'RTRN': reserved by the system, don't use. 'APTR' a pointer to some memory. mr_size should be four. mr_flags should be zero if you don't want to copy the data to another block when sending async., or should be the size of the data pointed to if you do. Create you own 4 character constant: mr_size should be an even number -- you can pass arbitrarily large structures on the stack, this way. mr_flags ignored. INPUTS struct MethodHandle *mh; - a MethodHandle being initialized. METHOD_REF args[]; - the (optional, and NULL-terminated) MethodRef array for this handle. OUTPUTS RESULT mh->mh_args, mh-Mh_num, mh->mh_size fields are set up properly. BUGS none known. NOTES SEE ALSO DJM() DoJazzMethod() InvalidateCache() AddMethods() DestroyMethodTable() FindMethodHandle() BlockMethod() RemoveAllPatches() SetupMethodTags() NAME SetupMethodTags -- defines all methods in the MethodTag array as being run by a certain process object, and being owned by a certain object. SYNOPSIS SetupMethodTags( tags, procObject, defnObject ) a1 d0 d1 FUNCTION This function will initialize the (required, NULL-terminated) tags array so that each method is located in a particular defnObject and wants to be called in a partiular procObject's process. For instance, gui methods may exist in a libraryObject (ie: a library) and want to be run by the guiProcObject. If passed objects of -1, the current task object is used. [That is; FindTask(NULL)->tc_UserData] INPUTS METHOD_TAG tags[]; - NULL-terminated MethodTag array. OBJECT procObject; - the process object in which to run the methods. OBJECT defnObject; - the object that "contains" the definition of the MethodREF -and- the function code. OUTPUTS RESULT BUGS none known. NOTES This is what guarantees that the function and MethodRef pointers remain valid as long as a method could call that function. The MethodRef structure is NOT copied when stored into the MethodHandler structure (the information in MethodTags and AttributeTags is). SEE ALSO DJM() DoJazzMethod() InvalidateCache() SetMethodArgs() AddMethods() DestroyMethodTable() FindMethodHandle() BlockMethod() RemoveAllPatches() NAME UseObject -- resource tracking for shadow objects. SYNOPSIS object = UseObject( object ) d0 a0 FUNCTION This function increments the object's cob_useCount field. You should Use an object whenever you save a pointer into a structure. INPUTS OBJECT object; - the object to effect the change upon. If NULL, nothing happens OUTPUTS OBJECT object; - the same as the object sent in. RESULT object's cob_object is incremented. BUGS none known. NOTES SEE ALSO DropObject() NAME UseString -- gets a system-wide address for a given string. SYNOPSIS string = UseString( buffer ) d0 a2 FUNCTION Shadow uses a system very much similar to the NeXT's -- a system- wide repository for string addresses. Strings are hashed into a 1024 table entry and chained onto sorted binary trees. The string which is returned is guaranteed to be a unique string address for the passed buffer. The passed buffer's address is *NOT* used as the system string address, so it can be a temporary stack-allocated buffer. The system string is created when a first UseString() is called for a given buffer. On the second UseString() call for the same buffer, the same string address will be returned, and an internal counter which tracks the string usage is incremented. These system strings may *NOT* be mangled, they are read-only. They are particularly good for static data that you wish to do searches on, as system-strings have a unique address, strcmp() is unnecessary, merely compare the string addresses. They are used internally for BinNode strings, Method names, attribute names, class names, etc. INPUTS char *buffer; - the string to retrieve a unique system pointer for. Given a NULL input, will return NULL. OUTPUTS char *string; - the unique string as returned by the system. A NULL signals an error. RESULT Either a new system string is created, and the buffer copied into it, or an old system string is retrieved and its usage counter incremented. BUGS none known. NOTES The buffer should be word-aligned for fastest access. SEE ALSO QuickUseString() FindString() DropString() QuickDropString() NAME VSem -- Vacate a semaphore SYNOPSIS VSem( address ) a0 FUNCTION This function does the equivalent of a ReleaseSemaphore on the given address. Every PSem() should be matched with a VSem(), except for PSem()s where a SHADOW_ATTEMPT_SEMAPHORE failed, in which case VSem() should NOT be called. INPUTS void *address; - Any address in the system. OUTPUTS RESULT The semaphore will be released (vacated), and the semaphore object freed if no longer needed. BUGS none known. NOTES SEE ALSO From exec.library: ReleaseSemaphore() PSem() NAME WaitThread -- synchronizes thread startup. SYNOPSIS task = WaitThread( ) d0 FUNCTION This function synchronizes the startup procedures for thread initialization. After a thread starts, there a number of things that the parent would like to be able to do. This function (which is required in the startup function you pass to the METHOD_META_INIT for a process object) allows the parent to complete its task BEFORE your thread is actually run. INPUTS none OUTPUTS struct Task *task; - the pointer to your task. RESULT parent has now filled in the task's object, so you can retrieve it from task->tc_UserData BUGS none known. NOTES SEE ALSO InitThread() RemoveThread() NAME WatcherDispatch -- Dispatches all notification methods. SYNOPSIS WatcherDispatch( flag, wv, first, second ) d0 a0 a1 d1 FUNCTION This function dispatches notification to all parties that have added themselves either to the WatchedVariable in question, or to the SList that wv->wv_firstClass points to. Watched Values are a tricky subject which will require a lot more than a simple AutoDoc note to explain them. Please see examples in browser.c for now, or refer to the DIRECTOR CLASS documentation in ShadowLibMethods.doc. INPUTS long flag; - Informs of the type of change made to the value: W_CHANGE_ZERO 1 W_CHANGE_NON_ZERO 2 W_INSERT_WATCHER 40 W_REMOVE_WATCHER 24 W_INSERT_NODE 32 W_REMOVE_NODE 16 W_VALUE *wv; - the watchedValue that was changed. void *first; - the object that was added to the list/AVLTREE, or the value that the variable was changed to. void *second; - the name or key for the new node in the list/AVLTREE OUTPUTS RESULT All interested parties are informed of the change. BUGS none known. NOTES SEE ALSO AddWatcherNode() AddClassWatcher()