627 lines
24 KiB
HTML
627 lines
24 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||
|
<HTML>
|
||
|
<HEAD>
|
||
|
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||
|
<META name="keywords" content="UL, PLIB, OpenGL, utility, library, portable, Baker, Steve, ulDir, ulClock, ulDynamicLibrary, ulList, ulLinkedList, ulHashTable, ulPropertySet, ulSleep, ulMilliSecondSleep, ulFindFile, ulFileExists, ulIsAbsolutePathName, ulGetCWD, ulMakePath, ulSetErrorCallback, ulGetErrorCallback, ulGetError, ulClearError, ulStrEqual, ulStrNEqual">
|
||
|
<META name="description" content="The PLIB Utility Library is targeted towards hiding common operating system functions behind a thin layer that makes them portable and provides some useful helper classes and routines.">
|
||
|
<TITLE>The Utility Library.</TITLE>
|
||
|
</HEAD>
|
||
|
<BODY text="#B5A642" link="#8FFF8F" vlink="#18A515" alink="#20336B"
|
||
|
bgcolor="#005000" background="../marble.png">
|
||
|
|
||
|
<H1>The PLIB general Utility Library.</H1>
|
||
|
By Sebastian Ude
|
||
|
<H2>Introduction</H2>
|
||
|
The 'UL' utility library is primarily targeted towards hiding common
|
||
|
operating system functions behind a thin layer that makes them portable.
|
||
|
Additionally, it provides some helper classes or routines that were
|
||
|
usually written to support certain parts of the
|
||
|
<a href="../index.html">PLIB</a> library, but at some point we felt that
|
||
|
they could be useful for user applications as well.
|
||
|
<p>
|
||
|
UL is a part of <a href="../index.html">PLIB</a>.
|
||
|
|
||
|
<h2>Contents:</h2>
|
||
|
<ul>
|
||
|
<li><a href="#miscFunc">Misc. routines</a>
|
||
|
<li><a href="#fileHandling">File handling</a>
|
||
|
<li><a href="#dirHandling">Directory handling</a>
|
||
|
<li><a href="#dataStorage">Data storage</a>
|
||
|
<li><a href="#errorHandling">Error handling</a>
|
||
|
<li><a href="#miscClasses">Misc. classes</a>
|
||
|
<li><a href="#endianHandling">Endian handling</a>
|
||
|
</ul>
|
||
|
|
||
|
<h2>Quick reference:</h2>
|
||
|
<table>
|
||
|
<tr>
|
||
|
<td><h3>Classes:</h3>
|
||
|
<td colspan=2><h3>Non-class functions:</h3>
|
||
|
|
||
|
<tr>
|
||
|
<td>
|
||
|
<ul>
|
||
|
<li><a href="#ulDir">ulDir</a>
|
||
|
<li><a href="#ulClock">ulClock</a>
|
||
|
<li><a href="#ulDynamicLibrary">ulDynamicLibrary</a>
|
||
|
<li><a href="#ulList">ulList</a>
|
||
|
<li><a href="#ulLinkedList">ulLinkedList</a>
|
||
|
<li><a href="#ulHashTable">ulHashTable</a>
|
||
|
<li><a href="#ulPropertySet">ulPropertySet</a>
|
||
|
</ul>
|
||
|
|
||
|
<td>
|
||
|
<ul>
|
||
|
<li><a href="#ulSleep">ulSleep</a>, <a href="#ulMilliSecondSleep">ulMilliSecondSleep</a>
|
||
|
<li><a href="#ulFindFile">ulFindFile</a>
|
||
|
<li><a href="#ulFileExists">ulFileExists</a>
|
||
|
<li><a href="#ulIsAbsolutePathName">ulIsAbsolutePathName</a>
|
||
|
<li><a href="#ulGetCWD">ulGetCWD</a>
|
||
|
<li><a href="#ulMakePath">ulMakePath</a>
|
||
|
<li><a href="#ulSetErrorCallback">ulSetErrorCallback</a>, <a href="#ulGetErrorCallback">ulGetErrorCallback</a>
|
||
|
</ul>
|
||
|
|
||
|
<td valign="top">
|
||
|
<ul>
|
||
|
<li><a href="#ulGetError">ulGetError</a>, <a href="#ulClearError">ulClearError</a>
|
||
|
<li><a href="#ulStrEqual">ulStrEqual</a>, <a href="#ulStrNEqual">ulStrNEqual</a>
|
||
|
</ul>
|
||
|
</table>
|
||
|
|
||
|
<h2><a name="miscFunc">Misc. routines</a></h2>
|
||
|
|
||
|
<h3><a name="ulSleep">ulSleep</a></h3>
|
||
|
<pre><i>
|
||
|
void ulSleep ( int seconds ) ;
|
||
|
</i></pre>
|
||
|
Now comes a typical example of what the UL library does. If you need to
|
||
|
'sleep' for, say, 3 seconds, then under Linux/UNIX, you'd need to call:
|
||
|
<pre><i>
|
||
|
sleep ( 3 ) ;
|
||
|
</i></pre>
|
||
|
But under MS-Windows, you have to say:
|
||
|
<pre><i>
|
||
|
Sleep ( 3000 ) ;
|
||
|
</i></pre>
|
||
|
In order to avoid writing non-portable code, you can instead call:
|
||
|
<pre><i>
|
||
|
ulSleep ( 3 ) ;
|
||
|
</i></pre>
|
||
|
...under either operating system.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulMilliSecondSleep">ulMilliSecondSleep</a></h3>
|
||
|
<pre><i>
|
||
|
void ulMilliSecondSleep ( int milliseconds ) ;
|
||
|
</i></pre>
|
||
|
Same as <a href="#ulSleep">ulSleep</a>, except that it sleeps (as you
|
||
|
may have guessed) a certain number of milliseconds instead of seconds.
|
||
|
|
||
|
<h2><a name="fileHandling">File handling</a></h2>
|
||
|
|
||
|
<h3><a name="ulFindFile">ulFindFile</a></h3>
|
||
|
<pre><i>
|
||
|
void ulFindFile ( char *filenameOutput, const char *path, const char * tfnameInput, const char *sAPOM ) ;
|
||
|
</i></pre>
|
||
|
Basically, this utility function adds tfnameInput to the path and puts this
|
||
|
into the buffer filenameOutput.
|
||
|
<p>
|
||
|
It handles special chars in path:
|
||
|
<ul>
|
||
|
<li>";;" is replaced by ";"
|
||
|
<li>"$$" is replaced by "$"
|
||
|
<li>"$(APOM)" is replaced by sAPOM
|
||
|
</ul>
|
||
|
If there are ";" in path, the path-variable is interpreted as several paths
|
||
|
"segments", delimited by ";". The first file found by this function is
|
||
|
returned. It looks from left to right. A segment may end in $(...). ulFindFile
|
||
|
will then look in in this path and recursively in all the sub-paths.
|
||
|
<p>
|
||
|
Some examples:
|
||
|
<p>
|
||
|
To load *.MDl-models, it is very nice to set the texture path to
|
||
|
"$(APOM);$(APOM)/texture;$(APOM)/../texture". This consists of three segments
|
||
|
and tells ulFindFile to look in the path of the model, in a subpath texture
|
||
|
and in a path texture "besides" the path of the model. Some *.mdl-models are
|
||
|
shipped in a directory which contains a "texture"-directory, a
|
||
|
"Model"-directory and others. In this case you find the texture in
|
||
|
"$(APOM)/../texture".
|
||
|
<p>
|
||
|
Another example: You have all your textures in a directory-structure under
|
||
|
/roomplan:
|
||
|
<pre>
|
||
|
textures --+-- Wallpapers
|
||
|
|
|
||
|
+-- Wood --+-- Oak
|
||
|
| |
|
||
|
| +-- pine
|
||
|
...
|
||
|
</pre>
|
||
|
Then you should simply use the following texture path:
|
||
|
"/roomplan/$(...)"
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulFileExists">ulFileExists</a></h3>
|
||
|
<pre><i>
|
||
|
bool ulFileExists ( const char *fileName ) ;
|
||
|
</i></pre>
|
||
|
Returns "true" if a file with the name 'fileName' exists, or "false" if
|
||
|
it does not.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulIsAbsolutePathName">ulIsAbsolutePathName</a></h3>
|
||
|
<pre><i>
|
||
|
int ulIsAbsolutePathName ( const char *pathname ) ;
|
||
|
</i></pre>
|
||
|
Returns '1' if 'pathname' is an absolute pathname or '0' if it is an
|
||
|
relative one.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulGetCWD">ulGetCWD</a></h3>
|
||
|
<pre><i>
|
||
|
char * ulGetCWD ( char *result, int maxlength ) ;
|
||
|
</i></pre>
|
||
|
Stores the current working directory in 'result', which has enough space
|
||
|
for 'maxlength' characters, including the trailing '\0'. On success,
|
||
|
'result' is returned.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulMakePath">ulMakePath</a></h3>
|
||
|
<pre><i>
|
||
|
char * ulMakePath ( char *path, const char *dir, const char *fname ) ;
|
||
|
</i></pre>
|
||
|
Concatenates the strings 'dir' and 'fname', puts the system's slash character
|
||
|
inbetween and stores stores the result in 'path'. Be sure that the buffer
|
||
|
'path' is large enough to store 'strlen ( dir ) + strlen ( fname ) + 2'
|
||
|
(slash and trailing '\0') characters.
|
||
|
|
||
|
<h2><a name="dirHandling">Directory handling</a></h2>
|
||
|
|
||
|
<h3><a name="ulDir">struct ulDir</a></h3>
|
||
|
This structure provides a portable way to read directories. To allocate and
|
||
|
initialize a new ulDir structure, call:
|
||
|
<pre><i>
|
||
|
ulDir * ulOpenDir ( const char* dirname ) ;
|
||
|
</i></pre>
|
||
|
This function returns a pointer to a newly allocated ulDir structure on
|
||
|
success or a NULL pointer if the specified directory could not be read.
|
||
|
<p>
|
||
|
After you have constructed an ulDir structure, the directory content can
|
||
|
be read with subsequent calls to:
|
||
|
<pre><i>
|
||
|
struct ulDirEnt
|
||
|
{
|
||
|
char d_name [ UL_NAME_MAX+1 ] ;
|
||
|
bool d_isdir ;
|
||
|
} ;
|
||
|
ulDirEnt * ulReadDir ( ulDir *dir ) ;
|
||
|
</i></pre>
|
||
|
This function returns a pointer to a ulDirEnt structure which resides in
|
||
|
the corresponding ulDir structure and which has the above form. The "d_isdir"
|
||
|
flag indicates if a directory entry is another directory. If the end of the
|
||
|
directory has been reached, the function returns NULL.
|
||
|
<p>
|
||
|
To free an ulDir object and to close the associated directory stream,
|
||
|
please call:
|
||
|
<pre><i>
|
||
|
void ulCloseDir ( ulDir *dir ) ;
|
||
|
</i></pre>
|
||
|
|
||
|
<h2><a name="dataStorage">Data storage</a></h2>
|
||
|
|
||
|
<h3><a name="ulList">class ulList</a></h3>
|
||
|
<pre><i>
|
||
|
ulList::ulList ( int init_max = 1 ) ;
|
||
|
</i></pre>
|
||
|
This class stores a list of generic (void*) pointers using an
|
||
|
automatically-growing array. Since the process of resizing the internal
|
||
|
array is rather expensive, it is important that one picks a reasonable default
|
||
|
array size (<i>init_max</i>) when constructing an ulList object if performance
|
||
|
matters. Remember that a too large size means that some memory is wasted (but
|
||
|
memory is cheap nowadays), while a too small one means that expensive array
|
||
|
resize operations will be necessary later.
|
||
|
<p>
|
||
|
If you have absolutely no clue about how many entities will be stored,
|
||
|
you should probably look at the <a href="#ulLinkedList">linked list class</a>
|
||
|
below, which has it's own disadvantages, though.
|
||
|
<p>
|
||
|
Once you have constructed an ulList (hopefully with a good initial size),
|
||
|
you can insert an element using one of the following methods:
|
||
|
<pre><i>
|
||
|
void ulList::addEntity ( void *entity ) ;
|
||
|
void ulList::addBefore ( int n, void *entity ) ;
|
||
|
</i></pre>
|
||
|
While the first one simply adds the new entity to the tail of the list,
|
||
|
the second one lets you specify an exact position (0 is the first element).
|
||
|
Note that due to it's array implementation, inserting an entity at the head
|
||
|
or the middle of the ulList requires that the following entities are all
|
||
|
shifted one array slot to the right, which can be a rather expensive
|
||
|
operation.
|
||
|
<p>
|
||
|
These functions automatically check whether there is room for one more element
|
||
|
and double the internal array's size if necessary. However, as said
|
||
|
previously, resizing the array is a rather expensive process, so it is not
|
||
|
recommended that you rely too much on this behavior. Instead, pick a good
|
||
|
initial array size.
|
||
|
<p>
|
||
|
Note that ulList allows you to have multiple entities with the same data
|
||
|
value in the list. Please also note that ulList does not make it's own copy
|
||
|
of the data pointed to by 'entity'. It is up to you to take care of that the
|
||
|
memory region that 'entity' points to holds something useful as long as the
|
||
|
ulList exists. Be especially careful with addresses of variables that have a
|
||
|
limited lifetime.
|
||
|
<p>
|
||
|
To retrieve an entity, call:
|
||
|
<pre><i>
|
||
|
void * ulList::getEntity ( unsigned int n ) ;
|
||
|
</i></pre>
|
||
|
Where 'n' is the position of the entity in the list. If 'n' is not a valid
|
||
|
index, NULL is returned. Once you have called this function, you can use
|
||
|
subsequent calls to
|
||
|
<pre><i>
|
||
|
void * ulList::getNextEntity ( void ) ;
|
||
|
</i></pre>
|
||
|
in order to retrieve the following entities in the list. If there are no more
|
||
|
entities, this function will return NULL.
|
||
|
<p>
|
||
|
To remove an entity, call one of:
|
||
|
<pre><i>
|
||
|
void ulList::removeEntity ( unsigned int n ) ;
|
||
|
void ulList::removeEntity ( void *entity ) ;
|
||
|
</i></pre>
|
||
|
Where the second function removes the <b>first</b> entity with the specified
|
||
|
data value in case there are multiple ones.
|
||
|
<p>
|
||
|
To replace the value of an entity, call one of:
|
||
|
<pre><i>
|
||
|
void ulList::replaceEntity ( unsigned int n, void *new_entity ) ;
|
||
|
void ulList::replaceEntity ( void *old_entity, void *new_entity ) ;
|
||
|
</i></pre>
|
||
|
Where the second function will replace the value of the <b>first</b> entity
|
||
|
with the specified old data value in case there are multiple ones.
|
||
|
<p>
|
||
|
And finally, you can retrieve the number of entities stored in the list
|
||
|
(that's <b>not</b> necessarily the internal array's size), remove all
|
||
|
entities or retrieve the position of an entity by specifying it's data
|
||
|
value:
|
||
|
<pre><i>
|
||
|
void ulList::getNumEntities ( void ) const ;
|
||
|
void ulList::removeAllEntities () ;
|
||
|
int ulList::searchForEntity ( void *entity ) const ;
|
||
|
</i></pre>
|
||
|
Where the latter returns a negative value if no entity with the specified
|
||
|
value was found in the list, and otherwise the position of the <b>first</b>
|
||
|
entity with the specified data value.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulLinkedList">class ulLinkedList</a></h3>
|
||
|
<pre><i>
|
||
|
ulLinkedList::ulLinkedList () ;
|
||
|
</i></pre>
|
||
|
The ulLinkedList class stores generic (void*) pointers using a linked list
|
||
|
of nodes where each node maintains a pointer to the next node.
|
||
|
<p>
|
||
|
This technique has some advantages compared to an array implementation of a
|
||
|
list like <a href="#ulList">ulList</a>.
|
||
|
<ul>
|
||
|
<li>
|
||
|
No wasted memory. When storing data using arrays (as
|
||
|
<a href="#ulList">ulList</a> does), it is a common practice to choose an array
|
||
|
size that seems "large enough". Most of the time the number of entities stored
|
||
|
will be smaller than the available array slots, so some memory space is wasted.
|
||
|
With a linked list, we allocate single nodes. No memory is wasted (except a
|
||
|
few bytes for each node's pointer to the next node).
|
||
|
|
||
|
<li>
|
||
|
Resizing an array is an expensive operation, since usually the whole array
|
||
|
content has to be copied from the old to the new memory location. We do not
|
||
|
have this problem with linked lists.
|
||
|
|
||
|
<li>
|
||
|
In contrast to arrays, it is a cheap operation to insert or remove entities
|
||
|
to / from the head or middle of a linked list. While with an array, the
|
||
|
following entities must all be shifted one slot to the left or right, we
|
||
|
simply need to (re)connect a few pointers with a linked list.
|
||
|
</ul>
|
||
|
There are some disadvantages, though:
|
||
|
<ul>
|
||
|
<li>
|
||
|
In contrast to an array, there is no cheap way to locate the n-th entity in a
|
||
|
linked list. With an array, you simply have to add the desired position
|
||
|
multiplied with the size of an element to the array's base address and
|
||
|
look at the content of the memory at this location - a very simple operation.
|
||
|
With a linked list, however, we need to iterate over all nodes 'n' times,
|
||
|
so locating the 1000th node is a rather expensive operation.
|
||
|
|
||
|
<li>
|
||
|
One may argue that insertion operations are more expensive with linked lists
|
||
|
than with arrays, since we allocate single nodes from the heap in contrast
|
||
|
to an array, where the whole list is one huge allocated block of memory.
|
||
|
Although allocation from the heap is indeed rather expensive, this is not
|
||
|
true when it comes to insertions to the middle of a list, these are usually
|
||
|
<b>way</b> more expensive with arrays. Furthermore, a list implemented using
|
||
|
an array such as <a href="#ulList">ulList</a> may make resizes of the array
|
||
|
necessary on insertions, which are again rather expensive.
|
||
|
</ul>
|
||
|
Decide yourself if a list implemented as an array such as
|
||
|
<a href="#ulList">ulList</a> or a linked list implementation like this one fits
|
||
|
your needs better.
|
||
|
<p>
|
||
|
Once you have constructed a ulLinkedList object, you can insert a node using
|
||
|
one of:
|
||
|
<pre><i>
|
||
|
void ulLinkedList::appendNode ( void *data ) ;
|
||
|
void ulLinkedList::prependNode ( void *data ) ;
|
||
|
void ulLinkedList::insertNode ( void *data, int pos ) ;
|
||
|
</i></pre>
|
||
|
While "appendNode" adds the new node at the tail of the list, "prependNode"
|
||
|
will place the new node at the head of the list, and "insertNode" allows
|
||
|
you to specify the desired position ('0' is the first node) yourself; 'pos'
|
||
|
must be either '0' or a number between '0' and the number of nodes minus one.
|
||
|
"prependNode" is equal to calling "insertNode" with pos == 0.
|
||
|
<p>
|
||
|
Note that ulLinkedList allows you to have two nodes with the same data in
|
||
|
the list. Also note that just as <a href="#ulList">ulList</a>, ulLinkedList
|
||
|
does not make it's own copy of the memory pointed to by 'data', so make sure
|
||
|
that the corresponding memory location holds something useful as long as the
|
||
|
list exists.
|
||
|
<p>
|
||
|
To retrieve the number of nodes in the list, call:
|
||
|
<pre><i>
|
||
|
int ulLinkedList::getNumNodes ( void ) const ;
|
||
|
</i></pre>
|
||
|
<p>
|
||
|
To retrieve the data of the node at a certain position in the list, call:
|
||
|
<pre><i>
|
||
|
void * ulLinkedList::getNodeData ( int pos ) const ;
|
||
|
</i></pre>
|
||
|
Where 'pos' must be a number between '0' and the number of nodes minus one,
|
||
|
again.
|
||
|
<p>
|
||
|
If you need to retrieve the position of a node in the list by specifying it's
|
||
|
data value, call:
|
||
|
<pre><i>
|
||
|
int ulLinkedList::getNodePosition ( void *data ) const ;
|
||
|
</i></pre>
|
||
|
If there is more than one node whose data value is 'data' in the list, this
|
||
|
function will return the position of the <b>first</b> one. If there is no
|
||
|
node with the specified data value in the list, this function will return a
|
||
|
negative number to indicate failure.
|
||
|
<p>
|
||
|
Checking if the return value of "getNodePosition" is non-negative is also
|
||
|
the recommended way to determine whether there exists at least one node with
|
||
|
a certain data value in a list.
|
||
|
<p>
|
||
|
To remove a node from the list, call one of:
|
||
|
<pre><i>
|
||
|
bool ulLinkedList::removeNode ( void *data ) ;
|
||
|
void * ulLinkedList::removeNode ( int pos ) ;
|
||
|
</i></pre>
|
||
|
Where the first function returns 'true' if the node was sucessfully removed or
|
||
|
'false' if it could not find a node whose value is 'data'. In case there is
|
||
|
more than one node whose data value is 'data', it will remove the <b>first</b>
|
||
|
one. With the second function, 'pos' has to be a number between '0' and the
|
||
|
number of nodes minus one. It's return value is the removed node's data
|
||
|
value.
|
||
|
<p>
|
||
|
To iterate over the list (starting from the head) and to have a custom
|
||
|
function being called for each node's data pointer, call:
|
||
|
<pre><i>
|
||
|
typedef bool (*ulIterateFunc)( void *data, void *user_data ) ;
|
||
|
void * ulLinkedList::forEach ( ulIterateFunc fn, void *user_data = NULL ) const ;
|
||
|
</i></pre>
|
||
|
The iteration process will stop if your ulIterateFunc returns 'false', in
|
||
|
which case "forEach" returns the data value of the node at which the iteration
|
||
|
stopped, or if the tail of the list has been reached, in which case "forEach"
|
||
|
returns NULL. The user_data pointer will be passed to your ulIterateFunc as
|
||
|
the second argument.
|
||
|
<p>
|
||
|
ulLinkedList allows you to maintain a sorted list as an option. To set up
|
||
|
a sorted list, simply be sure to insert all nodes using the sorted insertion
|
||
|
function as soon as there is at least one node in the list. It's prototype is:
|
||
|
<pre><i>
|
||
|
typedef int (*ulCompareFunc)( const void *data1, const void *data2 ) ;
|
||
|
int ulList::insertSorted ( void *data, ulCompareFunc comparefn ) ;
|
||
|
</i></pre>
|
||
|
Where 'comparefn' is your custom comparison function that takes two
|
||
|
data pointers, compares them and returns a memcmp / strcmp-like result:
|
||
|
<ul>
|
||
|
<li>
|
||
|
A number <b>less than zero</b> if "data1" is "smaller" than "data2", that
|
||
|
means if "data1" had to be inserted <b>before</b> "data2" in the list.
|
||
|
|
||
|
<li>
|
||
|
A number <b>equal to zero</b> if "data1" is equal to "data2", that means if
|
||
|
"data" had to be inserted immediately before or after "data2" in the list.
|
||
|
|
||
|
<li>
|
||
|
A number <b>greater than zero</b> if "data1" is "greater" than "data2",
|
||
|
that means if "data" had to be inserted <b>after</b> "data2" in the list.
|
||
|
</ul>
|
||
|
The return value of "insertSorted" is the position of the new node in the list
|
||
|
on success, or a negative value if you tried to do a sorted insertion on a
|
||
|
non-sorted list, that is a list which contains more than one node of which
|
||
|
at least one was not inserted using the sorted insertion function. In the
|
||
|
latter case, the new node would not have been inserted to the list.
|
||
|
<p>
|
||
|
To determine whether a list is sorted or not, call the following function:
|
||
|
<pre><i>
|
||
|
bool ulLinkedList::isSorted ( void ) const ;
|
||
|
</i></pre>
|
||
|
Note that with a linked list, you <b>must not</b> modify the criteria of a
|
||
|
node's data that is used for sorting without removing the node from the list
|
||
|
and re-inserting it.
|
||
|
<p>
|
||
|
Finally, you can empty a list (remove all nodes) by calling:
|
||
|
<pre><i>
|
||
|
typedef bool (*ulIterateFunc)( const void *data ) ;
|
||
|
void ulList::empty ( ulIterateFunc destroyfn = NULL, void *user_data = NULL ) ;
|
||
|
</i></pre>
|
||
|
Where "destroyfn" is an optionally specified function that will be called
|
||
|
with each destroyed node's data pointer as the first and with user_data as
|
||
|
the second argument. This is for example useful if the list entries are
|
||
|
pointers to dynamically allocated objects that have to be freed on destruction
|
||
|
of the list. The return value of the specified function is ignored.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulHashTable">ulHashTable</a></h3>
|
||
|
Not yet.
|
||
|
|
||
|
<h2><a name="errorHandling">Error handling</a></h2>
|
||
|
|
||
|
<h3><a name="ulSetErrorCallback">ulSetErrorCallback</a></h3>
|
||
|
<pre><i>
|
||
|
typedef void (*ulErrorCallback) ( enum ulSeverity severity, char* msg ) ;
|
||
|
void ulSetErrorCallback ( ulErrorCallback cb ) ;
|
||
|
</i></pre>
|
||
|
<a href="../index.html">PLIB</a> has an internal error handling system
|
||
|
that the subsystems use to report debug, warning or error messages.
|
||
|
An application can set up an error callback that PLIB will call whenever such
|
||
|
a message occurs in addition to printing the message on the user's terminal.
|
||
|
<p>
|
||
|
ulSeverety indicates the importance of an message and is currently defined
|
||
|
the following way:
|
||
|
<pre><i>
|
||
|
enum ulSeverity
|
||
|
{
|
||
|
UL_DEBUG,
|
||
|
UL_WARNING,
|
||
|
UL_FATAL
|
||
|
} ;
|
||
|
</i></pre>
|
||
|
Where
|
||
|
<ul>
|
||
|
<li>UL_DEBUG are unimportant debug messages that can usually safely be ignored
|
||
|
<li>UL_WARNING are important warning messages that should not be ignored
|
||
|
<li>UL_FATAL are fatal errors that PLIB can not recover from
|
||
|
</ul>
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulGetErrorCallback">ulGetErrorCallback</a></h3>
|
||
|
<pre><i>
|
||
|
typedef void (*ulErrorCallback) ( enum ulSeverity severity, char* msg ) ;
|
||
|
ulErrorCallback ulGetErrorCallback ( void ) ;
|
||
|
</i></pre>
|
||
|
Returns the current <a href="#ulSetErrorCallback">error callback</a> (if
|
||
|
any, else NULL is returned).
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulGetError">ulGetError</a></h3>
|
||
|
<pre><i>
|
||
|
char * ulGetError ( void ) ;
|
||
|
</i></pre>
|
||
|
Returns a pointer to the error buffer, that is, the last error message or an
|
||
|
empty string if there were not any error messages or if the error buffer has
|
||
|
just been <a href="#ulClearError">cleared</a>.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulClearError">ulClearError</a></h3>
|
||
|
<pre><i>
|
||
|
void ulClearError ( void ) ;
|
||
|
</i></pre>
|
||
|
Clears the <a href="#ulGetError">error buffer</a>.
|
||
|
|
||
|
<h2><a name="miscClasses">Misc. classes</a></h2>
|
||
|
|
||
|
<h3><a name="ulDynamicLibrary">class ulDynamicLibrary</a></h3>
|
||
|
<pre><i>
|
||
|
ulDynamicLibrary::ulDynamicLibrary ( const char *libname ) ;
|
||
|
</i></pre>
|
||
|
This class provides a portable way to load a dynamic library and to retrieve
|
||
|
the memory address of a specific function afterwards. When constructing an
|
||
|
ulDynamicLibrary object, you have to specify the name of the dynamic library
|
||
|
you want to operate on <b>without</b> the platform-specific file extension
|
||
|
for dynamic libraries.
|
||
|
<p>
|
||
|
Afterwards, you can retrieve the memory address where a function / symbol of
|
||
|
the library has been loaded by calling:
|
||
|
<pre><i>
|
||
|
void * ulDynamicLibrary::getFuncAddress ( const char *funcname ) :
|
||
|
</i></pre>
|
||
|
This function returns NULL if the specified symbol was not found.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulClock">ulClock</a></h3>
|
||
|
<pre><i>
|
||
|
ulClock::ulClock () ;
|
||
|
</i></pre>
|
||
|
No further documentation yet.
|
||
|
|
||
|
<h3><a name="ulPropertySet">ulPropertySet</a></h3>
|
||
|
Not yet.
|
||
|
|
||
|
<h2><a name="stringHandling">String handling</a></h2>
|
||
|
|
||
|
<h3><a name="ulStrEqual">ulStrEqual</a></h3>
|
||
|
<pre><i>
|
||
|
int ulStrEqual ( const char *s1, const char *s2 ) ;
|
||
|
</i></pre>
|
||
|
This function provides a portable way to compare two strings while ignoring
|
||
|
the case of the characters. We need it since half of the machines on the
|
||
|
planet provide strcasecmp and the other half stricmp for this purpose.
|
||
|
<p>
|
||
|
In contrast to the libc string comparison routines, this routine returns '1'
|
||
|
if the strings are <b>equal</b> and '0' if they are <b>not</b>.
|
||
|
|
||
|
<p>
|
||
|
<h3><a name="ulStrNEqual">ulStrNEqual</a></h3>
|
||
|
<pre><i>
|
||
|
int ulStrNEqual ( const char *s1, const char *s2, int len ) ;
|
||
|
</i></pre>
|
||
|
Same as ulStrEqual, except that it only compares the first 'len' characters
|
||
|
of the strings.
|
||
|
|
||
|
<p>
|
||
|
<h2><a name="endianHandling">Endian handling</a></h2>
|
||
|
<pre><i>
|
||
|
bool ulIsLittleEndian ( void ) ;
|
||
|
bool ulIsBigEndian ( void ) ;
|
||
|
|
||
|
unsigned short ulEndianLittle16 ( unsigned short x ) ;
|
||
|
unsigned int ulEndianLittle32 ( unsigned int x ) ;
|
||
|
float ulEndianLittleFloat ( float x ) ;
|
||
|
|
||
|
unsigned short ulEndianBig16 ( unsigned short x ) ;
|
||
|
unsigned int ulEndianBig32 ( unsigned int x ) ;
|
||
|
float ulEndianBigFloat ( float x ) ;
|
||
|
|
||
|
void ulEndianLittleArray16 ( unsigned short *x, int length ) ;
|
||
|
void ulEndianLittleArray32 ( unsigned int *x, int length ) ;
|
||
|
void ulEndianLittleArrayFloat ( float *x, int length ) ;
|
||
|
|
||
|
void ulEndianBigArray16 ( unsigned short *x, int length ) ;
|
||
|
void ulEndianBigArray32 ( unsigned int *x, int length ) ;
|
||
|
void ulEndianBigArrayFloat ( float *x, int length ) ;
|
||
|
|
||
|
unsigned short ulEndianReadLittle16 ( FILE *f ) ;
|
||
|
unsigned int ulEndianReadLittle32 ( FILE *f ) ;
|
||
|
float ulEndianReadLittleFloat ( FILE *f ) ;
|
||
|
|
||
|
unsigned short ulEndianReadBig16 ( FILE *f ) ;
|
||
|
unsigned int ulEndianReadBig32 ( FILE *f ) ;
|
||
|
float ulEndianReadBigFloat ( FILE *f ) ;
|
||
|
|
||
|
size_t ulEndianWriteLittle16 ( FILE *f, unsigned short x ) ;
|
||
|
size_t ulEndianWriteLittle32 ( FILE *f, unsigned int x ) ;
|
||
|
size_t ulEndianWriteLittleFloat ( FILE *f, float x ) ;
|
||
|
|
||
|
size_t ulEndianWriteBig16 ( FILE *f, unsigned short x ) ;
|
||
|
size_t ulEndianWriteBig32 ( FILE *f, unsigned int x ) ;
|
||
|
size_t ulEndianWriteBigFloat ( FILE *f, float x ) ;
|
||
|
</i></pre>
|
||
|
No further documentation yet.
|
||
|
|
||
|
<hr>
|
||
|
<table>
|
||
|
<tr>
|
||
|
<td>
|
||
|
<a href="http://validator.w3.org/check/referer"><img border="0" src="../valid-html40.png" alt="Valid HTML 4.0!" height="31" width="88"></a>
|
||
|
<td>
|
||
|
<ADDRESS>
|
||
|
Sebastian Ude <<A HREF="mailto:ude@handshake.de">ude@handshake.de</A>>
|
||
|
</ADDRESS>
|
||
|
</table>
|
||
|
</BODY>
|
||
|
</HTML>
|
||
|
|