Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Utility Library"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
 
(29 intermediate revisions by 2 users not shown)
Line 2: Line 2:
 
== Utility Library ==
 
== Utility Library ==
   
Utility library is the home for all the OS functions which don't fit in the other libraries. Among the calls in utility library are calls to manage tags and tag lists, callback hooks, and some generic 32-bit math functions, all discussed below.
+
Utility library is the home for all the OS functions which don't fit in the other libraries. Among the calls in utility library are calls to manage tags and tag lists, callback hooks, strings, data structures and more.
   
  +
The various functions are grouped into several sections:
== Tags ==
 
  +
* [[Tags]]
 
  +
* [[Callback Hooks]]
Tags make it possible to add new parameters to system functions without interfering with the original parameters. They also make specifying parameter lists much clearer and easier.
 
  +
* [[String Functions]]
 
=== Tag Functions and Structures ===
+
* [[Date Functions]]
  +
* [[Named Objects]]
 
  +
* [[Data Structures]]
A tag is made up of an attribute/value pair as defined below (from <utility/tagitem.h>):
 
 
<syntaxhighlight>
 
struct TagItem
 
{
 
ULONG ti_Tag; /* identifies the type of this item */
 
ULONG ti_Data; /* type-specific data, can be a pointer */
 
};
 
</syntaxhighlight>
 
 
The ti_Tag field specifies an attribute to set. The possible values of ti_Tag are implementation specific. System tags are defined in the include files. The value the attribute is set to is specified in ti_Data. An example of the attribute/value pair that will specify a window's name is:
 
 
<syntaxhighlight>
 
ti_Tag = WA_Title;
 
ti_Data = "My Window's Name";
 
</syntaxhighlight>
 
 
The ti_Data field often contains 32-bit data as well as pointers.
 
 
These are brief descriptions of the utility functions you can use to manipulate and access tags. For complete descriptions, see the "Simple Tag Usage" and "Advanced Tag Usage" sections.
 
 
The following utility library calls are for supporting tags:
 
 
Utility Library Tag Functions
 
 
{| class="wikitable"
 
| AllocateTagItems() || Allocate a TagItem array (or chain).
 
|-
 
| FreeTagItems() || Frees allocated TagItem lists.
 
|-
 
| CloneTagItems() || Copies a TagItem list.
 
|-
 
| RefreshTagItemClone() || Rejuvenates a clone from the original.
 
|-
 
| FindTagItem() || Scans TagItem list for a tag.
 
|-
 
| GetTagData() || Obtain data corresponding to tag.
 
|-
 
| NextTagItem() || Iterate TagItem lists.
 
|-
 
| TagInArray() || Check if a tag value appears in a Tag array.
 
|-
 
| FilterTagChanges() || Eliminate TagItems which specify no change.
 
|-
 
| FilterTagItems() || Remove selected items from a TagItem list.
 
|-
 
| MapTags() || Convert ti_Tag values in a list via map pairing.
 
|-
 
| PackBoolTags() || Builds a "Flag" word from a TagItem list.
 
|}
 
 
=== Simple Tag Usage ===
 
 
One way tags are passed to system functions is in the form of tag lists. A tag list is an array or chain of arrays of TagItem structures. Within this array, different data items are identified by the value of ti_Tag. Items specific to a subsystem (Intuition, Graphics,...) have a ti_Tag value which has the TAG_USER bit set. Global system tags have a ti_Tag value with TAG_USER bit clear. The global system tags include:
 
 
Global System Tags
 
 
{| class="wikitable"
 
! Tag Value
 
! Meaning
 
|-
 
| TAG_IGNORE || A no-op. The data item is ignored.
 
|-
 
| TAG_MORE || The ti_Data points to another tag list, to support chaining of TagItem arrays.
 
|-
 
| TAG_DONE || Terminates the TagItem array (or chain).
 
|-
 
| TAG_SKIP || Ignore the current tag item, and skip the next ''n'' array elements, where ''n'' is kept in ti_Data.
 
|}
 
 
Note that user tags need only be unique within the particular context of their use. For example, the attribute tags defined for OpenWindow() have the same numeric value as some tags used by OpenScreen(), but the same numeric value has different meaning in the different contexts.
 
 
System functions receive TagItems in several ways. One way is illustrated in the Intuition function OpenWindow(). This function supports an extented NewWindow structure called ExtNewWindow. When the NW_EXTENDED flag is set in the ExtNewWindow.Flags field, OpenWindow() assumes that the ExtNewWindow.Extension field contains a pointer to a tag list.
 
 
Another method of passing a tag list is to directly pass a pointer to a tag list, as OpenWindowTagList() does in the following code fragment.
 
 
<syntaxhighlight>
 
struct TagItem tagitem[3];
 
struct Screen *screen;
 
struct Window *window;
 
 
tagitem[0].ti_Tag = WA_CustomScreen;
 
tagitem[0].ti_Data = screen; /* Open on my own screen */
 
tagitem[1].ti_Tag = WA_Title;
 
tagitem[1].ti_Data = "Amiga Test Window";
 
tagitem[2].ti_Tag = TAG_DONE; /* Marks the end of the tag array. */
 
 
/* Use defaults for everything else. Will open as big as the screen. */
 
/* Because all window parameters are specified using tags, we don't */
 
/* need a NewWindow structure */
 
 
if (window = IIntuition->OpenWindowTagList(NULL, tagitem))
 
{
 
/* rest of code */
 
IIntuition->CloseWindow(window);
 
}
 
</syntaxhighlight>
 
 
Notice that window parameters need not be explicitly specified. Functions that utilize tags have reasonable defaults to fall back on in case no valid attribute/value pair was supplied for a particular parameter. This fall back capability is a useful feature. An application only has to specify the attributes that differ from the default, rather than unnecessarily listing all the possible attributes.
 
 
Many functions also support another way to pass TagItems. Rather than passing a tag list, the function OpenWindowTags() receives the attribute/value pairs in the argument list, much like the standard C function printf() receives its arguments. Any number of attribute/value pairs can be specified. This type of argument passing is called VarArgs. The following code fragment illustrates the usage of OpenWindowTags().
 
 
<syntaxhighlight>
 
struct Window *window;
 
 
/* Just pass NULL to show we aren't using a NewWindow */
 
window = IIntuition->OpenWindowTags( NULL,
 
WA_CustomScreen, screen,
 
WA_Title, "Amiga Test Window",
 
TAG_DONE );
 
</syntaxhighlight>
 
 
Tags are not exclusively for use with the operating system; the programmer can implement them as well. The run-time utility library contains several functions to make using tags easier.
 
 
=== Simple Tag Usage Example ===
 
 
The following example shows simple usage of tags. It shows how to allocate a tag array and use it, it also shows how to build a tag array on the stack.
 
 
<pre>;/* tag1.c - Execute me to compile me with SAS C 5.10
 
LC -b1 -cfis -j73 tag1.c
 
Blink FROM LIB:c.o,tag1.o TO tag1 LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
*/
 
 
#include &lt;exec/types.h&gt;
 
#include &lt;exec/libraries.h&gt;
 
#include &lt;utility/tagitem.h&gt;
 
#include &lt;intuition/intuition.h&gt;
 
#include &lt;clib/exec_protos.h&gt;
 
#include &lt;clib/intuition_protos.h&gt;
 
#include &lt;clib/utility_protos.h&gt;
 
 
extern struct Library *SysBase;
 
struct Library *IntuitionBase, *UtilityBase;
 
 
int main (int argc, char **argv)
 
{
 
struct TagItem *tags;
 
struct Window *win;
 
 
/* For this example we need Version 2.0 */
 
if (IntuitionBase = OpenLibrary (&quot;intuition.library&quot;, 37))
 
{
 
/* We need the utility library for this example */
 
if (UtilityBase = OpenLibrary (&quot;utility.library&quot;, 37))
 
{
 
 
/****************************************************************/
 
/* This section allocates a tag array, fills it in with values, */
 
/* and then uses it. */
 
/****************************************************************/
 
 
/* Allocate a tag array */
 
if (tags = AllocateTagItems (7))
 
{
 
/* Fill in our tag array */
 
tags[0].ti_Tag = WA_Width;
 
tags[0].ti_Data = 320;
 
tags[1].ti_Tag = WA_Height;
 
tags[1].ti_Data = 50;
 
tags[2].ti_Tag = WA_Title;
 
tags[2].ti_Data = (ULONG) &quot;Amiga Tag Example 1&quot;;
 
tags[3].ti_Tag = WA_IDCMP;
 
tags[3].ti_Data = IDCMP_CLOSEWINDOW;
 
tags[4].ti_Tag = WA_CloseGadget;
 
tags[4].ti_Data = TRUE;
 
tags[5].ti_Tag = WA_DragBar;
 
tags[5].ti_Data = TRUE;
 
tags[6].ti_Tag = TAG_DONE;
 
 
/* Open the window, using the tag attributes as the
 
* only description. */
 
if (win = OpenWindowTagList (NULL, tags))
 
{
 
/* Wait for an event to occur */
 
WaitPort (win-&gt;UserPort);
 
 
/* Close the window now that we're done with it */
 
CloseWindow (win);
 
}
 
 
/* Free the tag list now that we're done with it */
 
FreeTagItems(tags);
 
}
 
 
/****************************************************************/
 
/* This section builds the tag array on the stack, and passes */
 
/* the array to a function. */
 
/****************************************************************/
 
 
/* Now use the VarArgs (or stack based) version. */
 
if (win = OpenWindowTags ( NULL,
 
WA_Width, 320,
 
WA_Height, 50,
 
WA_Title, (ULONG)&quot;Amiga Tag Example 1&quot;,
 
WA_IDCMP, IDCMP_CLOSEWINDOW,
 
WA_CloseGadget, TRUE,
 
WA_DragBar, TRUE,
 
TAG_DONE))
 
{
 
/* Wait for an event to occur */
 
WaitPort (win-&gt;UserPort);
 
 
/* Close the window now that we're done with it */
 
CloseWindow (win);
 
}
 
 
/* Close the library now */
 
CloseLibrary (UtilityBase);
 
}
 
 
/* Close the library now that we're done with it */
 
CloseLibrary (IntuitionBase);
 
}
 
}</pre>
 
 
=== Advanced Tag Usage ===
 
 
The previous section provided the background material necessary to start using tags. This section will show how to use the more advanced features of tags using functions within utility library.
 
 
==== Creating a New Tag List ====
 
 
The AllocateTagItems() function can be used to create a new tag array ready for use. The tag array should be passed to FreeTagItems() when the application is done with it.
 
 
<syntaxhighlight>
 
struct TagItem *tags;
 
uint32 tags_needed;
 
 
/* Indicate how many tags we need */
 
tags_needed = 10;
 
 
/* Allocate a tag array */
 
if (tags = IUtility->AllocateTagItems(tags_needed))
 
{
 
/* ...do something with the array... */
 
 
/* Free the array when your done with it */
 
IUtility->FreeTagItems (tags);
 
}
 
</syntaxhighlight>
 
 
==== Copying an Existing Tag List ====
 
 
The CloneTagItems() function is used to copy an existing tag array into a new tag array.
 
 
<syntaxhighlight>
 
struct TagItem *otags; /* Original tag array */
 
struct TagItem *ntags; /* New tag array */
 
 
/* Make sure there is a TagItem array */
 
if (otags)
 
{
 
/* Copy the original tags into a new tag array */
 
if (ntags = IUtility->CloneTagItems(otags))
 
{
 
/* ...do something with the array... */
 
 
/* Free the array when your done with it */
 
IUtility->FreeTagItems (ntags);
 
}
 
}
 
</syntaxhighlight>
 
 
This function can also be used to implement a function that will insert tag items into an array.
 
 
<syntaxhighlight>
 
struct TagItem *otags; /* Original tag array */
 
struct TagItem *tags; /* New tag array */
 
 
/* Insert a couple of tags into an existing tag array */
 
if (tags = IUtility->MakeNewTagList (GA_LeftEdge, 10,
 
GA_TopEdge, 20,
 
TAG_MORE, otags))
 
{
 
/* ...do something with the array... */
 
 
/* Free the array when your done with it */
 
IUtility->FreeTagItems (tags);
 
}
 
 
/* This function will create a tag array from tag pairs placed on
 
* the stack */
 
struct TagItem *MakeNewTagList (uint32 data,...)
 
{
 
struct TagItem *tags = (struct TagItem *) &data;
 
 
return IUtility->CloneTagItems (tags);
 
}
 
</syntaxhighlight>
 
 
==== Filtering an Existing Tag List ====
 
 
Sometimes it is necessary to only allow certain attributes to be visible in a tag list. In order to achieve this, the tag array would need to be filtered.
 
 
A number of functions are provided for filtering items in a tag array. They are FilterTagChanges(), FilterTagItems() and RefreshTagItemClone().
 
 
<syntaxhighlight>
 
/* We want the text entry gadget to receive the following tags */
 
Tag string_attrs[] =
 
{
 
STRINGA_MaxChars,
 
STRINGA_Buffer,
 
STRINGA_TextVal,
 
TAG_END,
 
};
 
 
/* These are attributes that the model understands */
 
Tag model_attrs[] =
 
{
 
CGTA_Total,
 
CGTA_Visible,
 
CGTA_Top,
 
ICA_TARGET,
 
ICA_MAP,
 
TAG_END,
 
};
 
 
struct TagItem *otags; /* Original tag list */
 
struct TagItem *ntags; /* New, work, tag list */
 
 
/* Make a copy of the original for us to work with */
 
ntags = IUtility->CloneTagItems (otags);
 
 
/* Create a tag list that only contains attributes that are
 
* listed in the model_attrs list. */
 
if (IUtility->FilterTagItems (ntags, model_attrs, TAGFILTER_AND))
 
{
 
/* Work with filtered tag list (ntags) */
 
 
/* Restore the tag list */
 
IUtility->RefreshTagItemClones (ntags, otags);
 
 
/* Create a tag list that only contains attributes that
 
* aren't in the model_attrs list. */
 
if (IUtility->FilterTagItems (ntags, model_attrs, TAGFILTER_NOT))
 
{
 
/* Work with filtered tag list (ntags) */
 
}
 
 
/* Restore the tag list */
 
IUtility->RefreshTagItemClones (ntags, otags);
 
 
/* Create a tag list that only contains attributes that
 
* are in the string_attrs list. */
 
if (IUtility->FilterTagItems (ntags, string_attrs, TAGFILTER_AND))
 
{
 
/* Work with filtered tag list (ntags) */
 
}
 
}
 
 
/* Free work tag list. */
 
IUtility->FreeTagItems (ntags);
 
</syntaxhighlight>
 
 
==== Locating an Attribute ====
 
 
To see if an attribute is in a tag array, the TagInArray() function is used.
 
 
<syntaxhighlight>
 
/* See if the listview labels attribute is located in a tag array */
 
if (IUtility->TagItemArray(GTLV_Labels, tags))
 
{
 
/* Yes, the attribute is in the list */
 
}
 
else
 
{
 
/* No, the attribute isn't in the list */
 
}
 
</syntaxhighlight>
 
 
The FindTagItem() function will return a pointer to the actual tag that has the desired attribute. This allows you to manipulate the tag or to determine if the attribute exists but just has a NULL value.
 
 
<syntaxhighlight>
 
struct TagItem *tag;
 
 
/* See if they are trying to set a sound */
 
if (tag = IUtility->FindTagItem(MGA_Sound, attrs))
 
{
 
/* Set the sound attribute to point to the specified sound data */
 
tag->ti_Data = sound;
 
}
 
</syntaxhighlight>
 
 
==== Sequential Access of Tag Lists ====
 
 
In order to sequentially access the members of a tag array, the NextTagItem() function is used.
 
 
<syntaxhighlight>
 
struct TagItem *tags = msg->ops_AttrList;
 
struct TagItem *tstate;
 
struct TagItem *tag;
 
 
/* Start at the beginning */
 
tstate = tags;
 
 
/* Step through the tag list while there are still items in the
 
* list */
 
while (tag = NextTagItem (&tstate))
 
{
 
/* Cache the data for the current element */
 
uint32 tidata = tag->ti_Data;
 
 
/* Handle each attribute that we understand */
 
switch (tag->ti_Tag)
 
{
 
/* Put a case statement here for each attribute that your
 
* function understands */
 
case PGA_Freedom:
 
lod->lod_Flags |= tidata;
 
break;
 
 
case GTLV_Labels:
 
lod->lod_List = (struct List *) tidata;
 
break;
 
 
/* We don't understand this attribute */
 
default:
 
break;
 
}
 
}
 
</syntaxhighlight>
 
 
==== Random Access of Tag Lists ====
 
 
The GetTagData() function will return the data for the specified attribute. If there isn't a tag that matches, then the default value is returned.
 
 
<syntaxhighlight>
 
APTR sound;
 
 
/* Get the sound data that our function will use. */
 
sound = (APTR) GetTagData (MGA_Sound, (uint32) DefaultSound, attrs);
 
</syntaxhighlight>
 
 
==== Obtaining Boolean Values ====
 
 
Often times data is best represented as simple boolean (TRUE or FALSE) values. The PackBoolTags() function provides an easy method for converting a tag list to bit fields.
 
 
<syntaxhighlight>
 
/* These are the attributes that we understand, with the
 
* corresponding flag value. */
 
struct TagItem activation_bools[] =
 
{
 
/* Attribute Flags */
 
{GA_ENDGADGET, ENDGADGET},
 
{GA_IMMEDIATE, GADGIMMEDIATE},
 
{GA_RELVERIFY, RELVERIFY},
 
{GA_FOLLOWMOUSE, FOLLOWMOUSE},
 
{GA_RIGHTBORDER, RIGHTBORDER},
 
{GA_LEFTBORDER, LEFTBORDER},
 
{GA_TOPBORDER, TOPBORDER},
 
{GA_BOTTOMBORDER, BOTTOMBORDER},
 
{GA_TOGGLESELECT, TOGGLESELECT},
 
 
/* Terminate the array */
 
{TAG_END}
 
};
 
 
/* Set the activation field, based on the attributes passed */
 
g->Activation = IUtility->PackBoolTags(g->Activation, tags, activation_bools);
 
</syntaxhighlight>
 
 
==== Mapping Tag Attributes ====
 
 
To translate all occurrences of an attribute to another attribute, the MapTags() function is used.
 
 
<syntaxhighlight>
 
struct TagItem map_list[] =
 
{
 
/* Original New */
 
{MGA_LeftEdge, GA_LeftEdge},
 
{MGA_TopEdge, GA_TopEdge},
 
{MGA_Width, GA_Width},
 
{MGA_Height, GA_Height},
 
 
/* Terminate the array */
 
{TAG_END}
 
}
 
 
/* Map the tags to the new attributes, keeping all attributes that
 
* aren't included in the mapping array */
 
IUtility->MapTags(tags, map_list, MAP_KEEP_NOT_FOUND);
 
</syntaxhighlight>
 
 
== Callback Hooks ==
 
 
The callback feature provides a standard means for applications to extend the functionality of libraries, devices, and applications. This standard makes it easy for the operating system to use custom modules from different high level programming languages as part of the operating system. For example, the layers library, which takes care of treating a display as a series of layered regions, allows an application to attach a pattern function to a display layer. Instead of filling in the background of a layer with the background color, the layers library calls the custom pattern function which fills in the layer display with a custom background pattern.
 
 
=== Callback Hook Structure and Function ===
 
 
An application passes a custom function in the form of a callback Hook (from <utility/hooks.h>):
 
 
<pre>
 
struct Hook
 
{
 
struct MinNode h_MinNode;
 
ULONG (*h_Entry)(); /* function entry point */
 
ULONG (*h_SubEntry)(); /* secondary function entry point (not usually used) */
 
VOID *h_Data; /* owner specific */
 
};
 
</pre>
 
 
; h_MinNode
 
: This field is reserved for use by the module that will call the Hook.
 
 
; h_Entry
 
: This is the address of the callback function. Since AmigaOS 4.0, all callbacks adhere to the PowerPC SysV ABI which is stack based and therefore the order of the parameters is important. When AmigaOS ran only on 68000 based CPUs, this entry would point to a hook stub which would take the arguments from 68000 registers A0, A1, and A2, push them on the stack and finally call h_SubEntry.
 
 
; h_SubEntry
 
: This is the address of the secondary function entry point. It should only used when emulating 68000 code.
 
 
; h_Data
 
: This field is for the application to use. It could point to a global storage structure that the callback function utilizes.
 
 
There is only one function defined in utility library that relates to callback hooks:
 
 
<syntaxhighlight>
 
ULONG CallHookPkt(struct Hook *hook, APTR object, APTR paramPkt);
 
</syntaxhighlight>
 
 
CallHookPkt will always ensure the correct procedure is used to invoke a callback. If the callback points to PowerPC code, it will be called directly. If the callback points to 68000 code, it will invoke the emulator and take the appropriate action.
 
 
=== Simple Callback Hook Usage ===
 
 
A Hook function accepts the following three parameters in the order specified:
 
 
# Pointer to the Hook structure.
 
# Pointer to an object to manipulate. The object is context specific.
 
# Pointer to a message packet. This is also context specific.
 
 
For a callback function written in C, the parameters must appear in this order:
 
 
<pre>
 
myCallbackFunction(Pointer to Hook, // A0 in 68000
 
Pointer to Object, // A2 in 68000
 
Pointer to message); // A1 in 68000
 
</pre>
 
 
A callback function is executed on the context of the module that invoked it. This usually means that callback functions cannot call functions that need to look at environment specific data. For example, Printf() needs to look at the current process's input and output stream. Entities like Intuition have no input and output stream. To find out which context your callback is running on use the FindTask() function from Exec.
 
 
The following is a simple function that can be used in a callback hook which indicates which context it is running on.
 
 
<syntaxhighlight>
 
uint32 MyFunction (struct Hook *h, VOID *o, VOID *msg)
 
{
 
struct Task *task = IExec->FindTask(0);
 
 
/* Debugging function to send a string to the serial port */
 
IExec->DebugPrintF("MyFunction() running on Task %s\n",
 
(task->tc_Node.ln_Name == NULL) ? "NoName" : task->tc_Node.ln_Name);
 
 
return 1;
 
}
 
</syntaxhighlight>
 
 
The next step is to initialize the Hook for use. This basically means that the fields of the Hook structure must be filled with appropriate values. There are two ways to accomplish this. Either use the AllocSysObject() function with an object type of ASOT_HOOK or declare the hook statically and manually initialize the fields.
 
 
The following example shows how to allocate a Hook structure dynamically:
 
 
<syntaxhighlight>
 
struct Hook *hook = IExec->AllocSysObjectTags(ASOT_HOOK,
 
ASOHOOK_Entry, func,
 
ASOHOOK_Data, data,
 
TAG_END);
 
</syntaxhighlight>
 
 
The following simple function initializes a static Hook structure.
 
 
<syntaxhighlight>
 
/* This simple function is used to initialize a Hook */
 
VOID InitHook (struct Hook *h, uint32 (*func)(), VOID *data)
 
{
 
/* Make sure a pointer was passed */
 
if (h != NULL)
 
{
 
/* Fill in the hook fields */
 
h->h_Entry = func;
 
h->h_SubEntry = NULL;
 
h->h_Data = data;
 
}
 
}
 
</syntaxhighlight>
 
 
The following is a simple example of a callback hook function.
 
 
<pre>
 
;/* hooks1.c - Execute me to compile me with SAS C 5.10
 
LC -b1 -cfis -j73 hooks1.c
 
Blink FROM LIB:c.o,hooks1.o TO hooks1 LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
*/
 
 
#include &lt;exec/types.h&gt;
 
#include &lt;exec/libraries.h&gt;
 
#include &lt;utility/hooks.h&gt;
 
#include &lt;dos.h&gt;
 
 
#include &lt;clib/exec_protos.h&gt;
 
#include &lt;clib/dos_protos.h&gt;
 
#include &lt;clib/utility_protos.h&gt;
 
 
#include &lt;stdio.h&gt;
 
 
extern struct Library *SysBase;
 
struct Library *UtilityBase;
 
 
#define ASM __asm
 
#define REG(x) register __ ## x
 
 
/* This function converts register-parameter Hook calling
 
* convention into standard C conventions. It requires a C
 
* compiler that supports registerized parameters, such as
 
* SAS/C 5.xx or greater.
 
*/
 
 
ULONG ASM
 
hookEntry(REG(a0) struct Hook *h, REG(a2) VOID *o, REG(a1) VOID *msg)
 
{
 
return ((*(ULONG (*)(struct Hook *,VOID *,VOID *))(h-&gt;h_SubEntry))(h, o, msg));
 
}
 
 
/* This simple function is used to initialize a Hook */
 
VOID InitHook (struct Hook *h, ULONG (*func)(), VOID *data)
 
{
 
/* Make sure a pointer was passed */
 
if (h)
 
{
 
/* Fill in the Hook fields */
 
h-&gt;h_Entry = (ULONG (*)()) hookEntry;
 
h-&gt;h_SubEntry = func;
 
h-&gt;h_Data = data;
 
}
 
}
 
 
/* This function only prints out a message indicating that we are
 
* inside the callback function.
 
*/
 
 
ULONG MyFunction (struct Hook *h, VOID *o, VOID *msg)
 
{
 
/* Obtain access to the global data segment */
 
geta4();
 
 
/* Debugging function to send a string to the serial port */
 
printf(&quot;Inside MyFunction()\n&quot;);
 
 
return (1);
 
}
 
 
int main (int argc, char **argv)
 
{
 
struct Hook h;
 
 
/* Open the utility library */
 
if (UtilityBase = OpenLibrary (&quot;utility.library&quot;, 36))
 
{
 
/* Initialize the callback Hook */
 
InitHook (&amp;h, MyFunction, NULL);
 
 
/* Use the utility library function to invoke the Hook */
 
CallHookPkt (&amp;h, NULL, NULL);
 
 
/* Close utility library now that we're done with it */
 
CloseLibrary (UtilityBase);
 
}
 
else printf (&quot;Couldn't open utility.library\n&quot;);
 
}
 
</pre>
 
 
== String Functions ==
 
 
=== Regular String Functions ===
 
 
These functions perform operations on strings with no regard for localization.
 
 
Currently implemented are:
 
 
{| class="wikitable"
 
| Strlcat() || Length limited string concatenation.
 
|-
 
| Strlcpy() || Length limited string copy.
 
|-
 
| VASPrintf || Formatted output conversion with result are stored in dynamically allocated buffer.
 
|-
 
| VSNPrintf || Length limited formatted output conversion.
 
|}
 
 
=== International String Functions ===
 
 
When the localization library is opened, these functions will be replaced by ones which will take the locale as defined by the user into account. This means that the compare order may change according to the locale, so care should be taken not to rely on obtaining specific compare sequences.
 
 
Currently implemented are:
 
 
{| class="wikitable"
 
| Stricmp() || Compare string case-insensitive.
 
|-
 
| Strnicmp() || Compare string case-insensitive, with a specified length.
 
|-
 
| ToLower() || Convert a character to lower case.
 
|-
 
| ToUpper() || Convert a character to upper case.
 
|}
 
 
These functions operate in the same manner as their ANSI C equivalents, for the most part. For more information, see the "Utility Library" Autodocs in the SDK. Here is a simple example of the usage of the international string functions.
 
 
<pre>
 
;/* istr.c - Execute me to compile me with SAS C 5.10
 
LC -b1 -cfis -j73 istr.c
 
Blink FROM LIB:c.o,istr.o TO istr LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
*/
 
 
#include &lt;exec/types.h&gt;
 
#include &lt;stdio.h&gt;
 
#include &lt;string.h&gt;
 
 
#include &lt;clib/exec_protos.h&gt;
 
#include &lt;clib/utility_protos.h&gt;
 
 
void main(void);
 
struct Library *UtilityBase;
 
 
void main(void)
 
{
 
UBYTE *butter = &quot;B√∏tervl√∏√∏t&quot;;
 
UBYTE *bread = &quot;Knåckerbrøt&quot;;
 
UBYTE ch1, ch2;
 
LONG result;
 
 
/* Fails silently if &lt; 37 */
 
if (UtilityBase = OpenLibrary(&quot;utility.library&quot;, 37))
 
{
 
result = Stricmp(butter, bread);
 
 
printf(&quot;comparing %s with %s yields %ld\n&quot;, butter, bread, result );
 
 
result = Strnicmp(bread, butter, strlen(bread));
 
 
printf(&quot;comparing (with length) %s with %s yields %ld\n&quot;, bread, butter, result );
 
 
ch1 = ToUpper(0xE6); æ /* ASCII character 230 ae ligature */
 
ch2 = ToLower(0xD0); Ð /* ASCII character 208 Icelandic Eth */
 
 
printf(&quot;Chars %c %c\n&quot;, ch1, ch2);
 
}
 
}
 
</pre>
 
 
== Date Functions ==
 
 
To ease date-related calculations, the utility library has some functions to convert a date, specified in a ClockData structure, in the number of seconds since 00:00:00 01-Jan-78 and vice versa.
 
 
To indicate the date, the ClockData structure (in &lt;utility/date.h&gt;) is used.
 
 
<syntaxhighlight>
 
struct ClockData
 
{
 
UWORD sec; /* seconds (0 - 59)*/
 
UWORD min; /* minutes (0 - 59) */
 
UWORD hour; /* hour (0 - 23) */
 
UWORD mday; /* day of the month (1 - 31) */
 
UWORD month; /* month of the year (1 - 12)
 
UWORD year; /* 1978 - */
 
UWORD wday; /* day of the week (0 - 6, where 0 is Sunday) */
 
};
 
</syntaxhighlight>
 
 
The following functions are available to operate on ClockData:
 
 
Utility Library Date Functions
 
 
{| class="wikitable"
 
| Amiga2Date() || Calculate the date from the specified timestamp (in seconds).
 
|-
 
| CheckDate() || Check the legality of a date.
 
|-
 
| Date2Amiga() || Calculate the timestamp from the specified date.</td>
 
|}
 
 
Amiga2Date() takes a number of seconds from 01-Jan-78 as argument and fills in the supplied ClockData structure with the date and time.
 
 
CheckDate() checks if the supplied ClockData structure is valid, and returns the number of seconds from 01-Jan-78 if it is. Note that this function currently does not take the supplied day of the week in account.
 
 
Date2Amiga() takes a ClockData structure as argument and returns the number of seconds since 01-Jan-78. The supplied ClockData structure ''must'' be valid, since no checking is done.
 
 
The following example shows various uses of the utility library date functions.
 
 
<pre>
 
;/* a2d.c - Execute me to compile me with SAS C 5.10
 
LC -b1 -cfis -j73 a2d.c
 
Blink FROM LIB:c.o,a2d.o TO a2d LIBRARY LIB:LC.lib,LIB:Amiga.lib
 
quit
 
*/
 
#include <exec/types.h>
 
#include <exec/memory.h>
 
#include <dos/datetime.h>
 
#include <devices/timer.h>
 
 
#include <clib/exec_protos.h>
 
#include <clib/timer_protos.h>
 
#include <clib/utility_protos.h>
 
 
#include <stdio.h>
 
 
LONG main(void);
 
 
struct Library *TimerBase;
 
struct Library *UtilityBase;
 
 
LONG main(void)
 
{
 
struct ClockData *clockdata;
 
struct timerequest *tr;
 
struct timeval *tv;
 
LONG seconds;
 
 
if (UtilityBase = IExec->OpenLibrary("utility.library", 37))
 
{
 
if (tr = IExec->AllocMem(sizeof(struct timerequest), MEMF_CLEAR))
 
{
 
if (tv = IExec->AllocMem(sizeof(struct timeval), MEMF_CLEAR))
 
{
 
if (clockdata = IExec->AllocMem(sizeof(struct ClockData), MEMF_CLEAR))
 
{
 
if (!(IExec->OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0) ))
 
{
 
TimerBase = tr->tr_node.io_Device;
 
 
ITimer->GetSysTime(tv);
 
 
printf("GetSysTime():\t%d %d\n", tv->tv_secs, tv->tv_micro);
 
 
IUtility->Amiga2Date(tv-&gt;tv_secs, clockdata);
 
 
printf("Amiga2Date(): sec %d min %d hour %d\n", clockdata->sec,
 
clockdata->min, clockdata->hour);
 
 
printf(" mday %d month %d year %d wday %d\n";, clockdata->mday,
 
clockdata->month, clockdata->year, clockdata->wday);
 
 
seconds = IUtility->CheckDate(clockdata);
 
 
printf("CheckDate():\t%ld\n", seconds);
 
 
seconds = IUtility->Date2Amiga(clockdata);
 
 
printf("Date2Amiga():\t%ld\n", seconds);
 
 
IExec->CloseDevice((struct IORequest *)tr);
 
}
 
IExec->FreeMem(clockdata, sizeof(struct ClockData));
 
}
 
IExec->FreeMem(tv, sizeof(struct timeval));
 
}
 
IExec->FreeMem(tr, sizeof(struct timerequest));
 
}
 
IExec->CloseLibrary(UtilityBase);
 
}
 
}
 
</pre>
 
 
== Named Objects ==
 
 
{| class="wikitable"
 
| AddNamedObject() || Add a named object to a namespace.
 
|-
 
| AllocNamedObject() || Allocate a named object.
 
|-
 
| AttemptRemNamedObject() || Attempt to remove a named object.
 
|-
 
| FindNameObject() || Find the next named object (case sensitive).
 
|-
 
| FreeNamedObject() || Frees a named object.
 
|-
 
| NamedObjectName() || Return the name of a named object.
 
|-
 
| ReleaseNamedObject() || Release usage of a named object.
 
|-
 
| RemNamedObject() || Remove a named object from any namespace.
 
|-
 
|}
 
 
Insert documentation here.
 
 
== Data Structures ==
 
 
=== Splay Trees ===
 
 
Splay trees are a form of binary tree which organizes itself in response to insertions and searches. Whenever a search finds a specific tree node, that node is "pulled up" into the tree root, and the tree is subsequently reorganized. This reorganization is called "splaying" and has the effect of making the tree flatter, shortening the distances between the root and leaf nodes. Also, more frequently-used nodes will move more closely to the root of the tree during each splay operation. The more splay operations are performed, the more closely the tree will represent the frequency of the node accesses, and will eventually place the most frequently-used nodes close to the root of the tree. This self-organization makes splay trees well-suited for use in caches or dictionaries. Because search operations will modify the splay tree, you should always use an arbitration mechanism such as a [[Exec_Mutexes|Mutex]] if you share the same splay tree with several Tasks or Processes.
 
 
{| class="wikitable"
 
| CreateSplayTree() || Allocate a splay tree data structure.
 
|-
 
| DeleteSplayTree() || Free a splay tree and all its nodes.
 
|-
 
| FindSplayNode() || Search for a key in a splay tree.
 
|-
 
| InsertSplayNode() || Insert a new key into a splay tree.
 
|-
 
| RemoveSplayNode() || Remove a node from a splay tree.
 
|}
 
 
=== Skip Lists ===
 
 
{| class="wikitable"
 
| CreateSkipList() || Allocate a skip list data structure.
 
|-
 
| DeleteSkipList() || Free a skip list and all its nodes.
 
|-
 
| FindSkipNode() || Search for a key in a skip list.
 
|-
 
| GetFirstSkipNode() || Get a pointer to the first node of a skip list.
 
|-
 
| GetNextSkipNode() || Get a pointer to the following node in a skip list.
 
|-
 
| InsertSkipNode() || Insert a new key into a skip list.
 
|-
 
| RemoveSkipNode() || Remove a node from a skip list.
 
|}
 
 
Insert documentation here.
 
 
== Function Reference ==
 
 
The tables which follow contain breif descriptions of the functions inside the utility library. See the SDK for details on each function call.
 
 
=== Tag Function Reference ===
 
 
The following are brief descriptions of the utility library functions which pertain to tags and tag lusts.
 
 
{| class="wikitable"
 
! Function
 
! Description
 
|-
 
| AllocateTagItems()
 
| Allocate a TagItem array (or chain).
 
|-
 
| FreeTagItems()
 
| Frees allocated TagItem lists.
 
|-
 
| CloneTagItems()
 
| Copies a TagItem list.
 
|-
 
| RefreshTagItemClone()
 
| Rejuvenates a clone from the original.
 
|-
 
| FindTagItem()
 
| Scans TagItem list for a tag.
 
|-
 
| GetTagData()
 
| Obtain data corresponding to tag.
 
|-
 
| NextTagItem()
 
| Iterate TagItem lists.
 
|-
 
| TagInArray()
 
| Check if a tag value appears in a Tag array.
 
|-
 
| FilterTagChanges()
 
| Eliminate TagItems which specify no change.
 
|-
 
| FilterTagItems()
 
| Remove selected items from a TagItem list.
 
|-
 
| MapTags()
 
| Convert ti_Tag values in a list via map pairing.
 
|-
 
| PackBoolTags()
 
| Builds a "Flag" word from a TagItem list.
 
|}
 
 
=== Callback Hook Function Reference ===
 
 
The following are brief descriptions of the utility library functions which pertain to callback hooks.
 
 
{| class="wikitable"
 
! Function
 
! Description
 
|-
 
| CallHookPkt()
 
| Call a standard callback Hook function.
 
|}
 
 
=== International String Function Reference ===
 
 
The following are brief descriptions of the utility library functions which pertain to string operations using the international ASCII character set.
 
 
{| class="wikitable"
 
! Function
 
! Description
 
|-
 
| Stricmp()
 
| Compare strings, case-insensitive.
 
|-
 
| Strnicmp()
 
| Compare strings, case-insensitive, with specified length.
 
|-
 
| ToLower()
 
| Convert a character to lower case.
 
|-
 
| ToUpper()
 
| Convert a character to upper case.
 
|}
 
 
=== Date Function Reference ===
 
 
The following are brief descriptions of the utility library functions which pertain to date conversion.
 
 
{| class="wikitable"
 
! Function
 
! Description
 
|-
 
| CheckDate()
 
| Check the legality of a date.
 
|-
 
| Amiga2Date()
 
| Calculate the date from a specified timestamp.
 
|-
 
| Date2Amiga()
 
| Calculate the timestamp from a specified date.
 
|}
 

Latest revision as of 22:28, 26 March 2014

WIP.png This page is currently being updated to AmigaOS 4.x. Some of the information contained here may not yet be applicable in part or totally.

Utility Library

Utility library is the home for all the OS functions which don't fit in the other libraries. Among the calls in utility library are calls to manage tags and tag lists, callback hooks, strings, data structures and more.

The various functions are grouped into several sections: