first commit

This commit is contained in:
mplib1 2014-04-22 02:03:26 +01:00
commit 59a096572e
488 changed files with 61943 additions and 0 deletions

78
Makefile Normal file
View file

@ -0,0 +1,78 @@
#
#
default:: all
ifndef MAJOR_VERSION
MAJOR_VERSION=4
endif
ifndef MINOR_VERSION
MINOR_VERSION=2
endif
.PHONY: all clean install
#SHELL=/bin/sh
TARFILE=mplib1.tar
SUBDIRS= libsrc libsrc_bpo libsrc_gdbm test util bin doc include mplib1 lib util_doc src_doc platform compat
TOPFILES=Makefile make_include gen_html_index index.html
ifdef PLATFORM
all: platform_dir
else
all: libsrc_all util_all test_all
endif
libsrc_all: platform_dir
$(MAKE) -C libsrc all
$(MAKE) -C libsrc_bpo all
$(MAKE) -C libsrc_gdbm all
util_all: platform_dir
$(MAKE) -C util all
test_all: platform_dir
$(MAKE) -C test all
clean: libsrc_clean util_clean test_clean platform_clean top_clean
libsrc_clean:
$(MAKE) -C libsrc clean DOING_CLEAN=TRUE
$(MAKE) -C libsrc_bpo clean DOING_CLEAN=TRUE
$(MAKE) -C libsrc_gdbm clean DOING_CLEAN=TRUE
util_clean:
$(MAKE) -C util clean DOING_CLEAN=TRUE
test_clean:
$(MAKE) -C test clean DOING_CLEAN=TRUE
platform_clean:
$(MAKE) -C platform clean
top_clean:
@rm -rf $(TARFILE)
install: install_lib install_util
install_lib: platform_dir
$(MAKE) -C libsrc install
install_util: platform_dir
$(MAKE) -C util install
ship: clean
tar cf $(TARFILE) $(TOPFILES) $(SUBDIRS)
docs: platform_dir
$(MAKE) -C libsrc docs
$(MAKE) -C util docs
docs_clean: platform_dir
$(MAKE) -C libsrc docs_clean
$(MAKE) -C util docs_clean
platform_dir:
$(MAKE) -C platform all

5
Makefile.am Normal file
View file

@ -0,0 +1,5 @@
# this is the main Makefile.am
# first of all, parse the subdirectories in the order given
SUBDIRS = platform libsrc util test

BIN
doc/bback.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

BIN
doc/bpin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

47
doc/bpo_alloc.html Normal file
View file

@ -0,0 +1,47 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE> bpo_alloc - Shared Memory Allocation Routines </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> bpo_alloc - Shared Memory Allocation Routines </h1>
The bpo_alloc module provides dynamic shared memory allocation
in an almost identical manner to that provided by the system
standard routines malloc() and free(). The only variation
is in the replacement for the malloc call which requires
a hint as to which shared memory segment the allocation
should take place in.
<p>
<hr>
<pre>
extern void *shalloc( void *hint, size_t size );
</pre>
This routine takes a hint and a size parameter. If the allocation
is successful, the routine returns a pointer to the allocated block.
If the routine fails to allocate (the segment does not support allocation,
or there is no resource left) then it returns NULL.
<P>
<pre>
extern void shfree( void *ptr );
</pre>
This routine takes a pointer to a previously allocated block,
and returns the block to the free list. If the pointer is not
to a previously allocated block then the call silently fails.
<p>
<hr>
<p>
Additionally there are pair of support routines which provide
string duplication into shared memory.
<pre>
char *bpo_strdup( void *hint, const char *s1 );
off_t bpo_strdup_offset( void *hint, const char *s1 );
</pre>
These routines allocate a block of memory in the shared memory region
pointed to by <tt>hint</tt> and if successful, copy the supplied string
into the new block and return either a pointer to the new string
or the offset of the allocated block within the region.
<p><hr><p>
</BODY>
</HTML>

224
doc/bpo_init.html Normal file
View file

@ -0,0 +1,224 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE> bpo_init - Shared Object and Resource routines </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> bpo_init - Shared Object and Resource routines </h1>
All of the bpo_* routines are based on the idea of shared memory-mapped
data. There are two sorts of item that can be memory-mapped, they are
System V IPC shared memory and <tt>mmap()</tt>-ed files.
<p>
bpo_init provides the routines which attach and detach these segments
and provides a way of registering resources allocated within the segments.
The create routines provide the hints which are used with the functions
described in the associated files.
<p>
<hr>
<h3>The Create Functions</h3>
There are two basic functions for attaching to the shared segements,
one for each memory type.
<pre>
void *Create_SODB_mmap_priv( const char *use_name,
const char *mmap_name,
size_t msize,
off_t moff,
int flags,
mode_t priv );
void *Create_SODB_shm_priv( const char *use_name,
const char *fname,
char id,
size_t msize,
int flags,
mode_t priv );
</pre>
These functions create/attach the segments used by the other bpo_*
routines. They both return a pointer which is normally the base of
the mapped object (see note below about SODB_ADD_HEADER).
<p>
The functions take both take a use_name parameter which is the name
by which this segment will be known. They also take a set of flags
which are used to determine the properties of this segment
(whether it supports dynamic allocation, etc), and a privileges
parameter which determines the permissions on the segment.
The other parameters
are directly related to the system calls these functions overlay.
<p>
In the case of the _mmap function, the parameters are the file name
to map, what offset into the file should be used, and how much of the file
to map.
<P>
For the _shm function the parameters are the file name (which should
exist) and the id to use in a call to the ftok() routine, and what
the size of the shared memory segment should be.
<p>
There are two values that may be passed as the flag. These values are.
<dl>
<dt>SODB_USE_SHALLOC</dt><dd>This specifies that the segment allows
dynamic allocation of memory within it using the routines provided
in <a href="bpo_alloc.html">bpo_alloc</a>. Use of the flag enables the
use of the resource functions described below.</dd>
<dt>SODB_ADD_HEADER</dt><dd>This specifies that the size of the
shared object header should be added to the requested size, and that
the routine, on success, should return a pointer to beyond the
shared object header.</dd>
</dl>
If there is a problem at any point during the create/attach the
routines return NULL. If the segment required already exists, then
the shared object header is checked against the supplied parameters.
If any of the parameters does not match (use_name, size, etc.) then
the create routine will fail and return NULL.
<p>
<pre>
void *Create_SODB_mmap( const char *use_name,
const char *mmap_name,
size_t msize,
off_t moff,
int flags );
void *Create_SODB_shm( const char *use_name,
const char *fname,
char id,
size_t msize,
int flags );
</pre>
These two routines are simply wrappers for the ones mentioned above,
but without the attache privileges parameter. These routines provide
default value for this parameter. The new defaults for both of the
privileges is 0600, which gives maximum security.
<hr>
<h3>The Detach Functions</h3>
These functions detach the segments pointed to by the provided hint.
Care should be taken to call the right call corresponding to the
Create call used.
<pre>
int Detach_SODB_mmap( void *hint );
int Detach_SODB_shm( void *hint );
</pre>
There is also a call to use in case you do not know how a particular
SODB was attached.
<pre>
int Detach_SODB_lump( const void *hint );
</pre>
This will either detach (<i>shmdt</i>) the shared memory,
or <i>munmap</i> the relevant SODB.
<p>
<hr>
<h3> Utility Functions </h3>
<pre>
void *Get_SODB_Pointer( const void *hint, off_t item_offset );
</pre>
This function returns the pointer within the SODB of the hint for
the offset provided (or NULL if not supplied a valid hint for an SODB
or the offset if outside the supplied SODB).
<pre>
off_t Get_SODB_Offset( const void *vp );
</pre>
This function returns the offset into the SODB of the supplied
object (or 0 if not supplied a valid pointer for an SODB).
<pre>
mode_t Get_SODB_Privs( const void *vp );
</pre>
This function returns the attach mode of the SODB pointed to by the
parameter (or 0 if not supplied a valid pointer for an SODB).
<pre>
void * Get_SODB_Base( const void *hint );
</pre>
This function returns a pointer to the start of the SODB which
contains the hint (or NULL if the hint is not in an SODB).
<pre>
int SODB_in_Segment( const void *hint, const void *chk );
</pre>
This function returns a non-zero result if the check parameter is within
the same SODB as the hint.
<p>
<hr>
<h3>The Resource Functions</h3>
These functions allow the tracking of allocated sections within
a segment by name. These sections are refered to by name, and
are stored as a name/offset pair on the resource list (internal).
<p>
These functions only work if the initial Create routine was
called with SODB_USE_SHALLOC as part of the flags.
<pre>
void * Find_SODB_Resource( void *hint, char *res_name );
</pre>
The function returns a pointer to the named resource, it it exists.
If it does not, it returns a NULL. If a given resource is not found
it is likely that the following routine will be called.
<pre>
off_t Add_SODB_Resource( void *object, char *res_name );
</pre>
This adds a resource, with the supplied name, to the resource list
in the relevant segment. If the resource already exists, or there
is a problem in adding the resource (the segment does not support
resources) then the routine returns (off_t)0, otherwise it returns
the offset within the segment of the supplied object.
<p>
<pre>
void * Fetch_SODB_Resource( void *hint, char *name, size_t s_size,
void (* s_init)( void * ) );
</pre>
This function provides a wrapper for the Find_ and Add_ resource
functions. It is most easily described using the following
pseudo-code.
<pre>
void * Fetch_SODB_Resource( void *hint, char *name, size_t s_size,
void (* s_init)( void * ) )
{
void *rv,tp;
rv = Find_SODB_Resource( hint, name );
if (rv==NULL)
{
tp = shalloc( hint, s_size );
if (tp)
{
(* s_init)( tp );
if (Add_SODB_Resource( tp, name )==(off_t)0)
shfree(tp);
rv = Find_SODB_Resource( hint, name );
}
}
return(rv);
}
</pre>
As can be seen, we either find it, or create it. Note, we allow for
somebody creating it between our search and add. In addition, there
are a couple of other safety measures that are taken to ensure that
the memory cannot be freed by some rouge program.
<p>
The initialise function should perform any base initialisation
required to the data area, but should not assume that the pointer
passed is going to be the resource (given we may have been pre-empted).
<p>
For further clarification, consider the following code.
<pre>
struct fred
{
struct bpo_pid_lock fred_lock;
int fred_value;
};
static void init_fred( struct fred *fp )
{
bpo_Init_pid_lock( &amp;fp->fred_lock, NULL );
fp->fred_value=1;
return;
}
struct fred * find_fred( void *hint )
{
struct fred *fp;
fp = Fetch_SODB_Resource( hint, "FRED",
sizeof(struct fred),
(void (*)(void *))init_fred );
return(fp);
}
</pre>
<p>
<hr>
</BODY>
</HTML>

74
doc/bpo_intro.html Normal file
View file

@ -0,0 +1,74 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE> bpo_* - Base Plus Offset routines </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> bpo_* - Base Plus Offset routines </h1>
This document describes the various files in the bpo_* series and details
the functions described therein.
<p>
The bpo_* routines are designed to provide process independent method
of sharing data using IPC shared memory or <tt>mmap()</tt>-ed files. The
routines provide convenient ways to attach to segments, allocate memory,
register processes and resources, inter-process locking, message queueing.
<p>
Most of the functions described require a <i>hint</i> as to where the
required action should take place. This is because there can be many
such attached segments, not all of them with the same characteristics.
This hint can usually take the form of the pointer returned when the
segment was created/attached.
<p>
An important point to note is that within the various routines, and in
any stored structures, there are no actual memory addresses used. This
is because the given segment may be mapped to different addresses for
given processes. So, all object references are stored as the offset
from the base of the segment.
<p>
In a number of cases, the routines will
return a genuine pointer, this is for the application's convenience. Any
reference to the object returned that is to be stored directly by the
application should be done as an offset rather than the pointer, probably
by calling the relevant conversion routine.
<p>
<hr>
<h2> The Files </h2>
The various routines are split into various files according to their
function. To use routines defined in a given module include the relevant
<tt>.h</tt> Any required <tt>bpo_*.h</tt> files will automatically
be included.
In addition, the following standard include files will usually be required.
<pre>
#include &lt;sys/types.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;sys/ipc.h&gt;
#include &lt;sys/shm.h&gt;
</pre>
<P>
The various files in the suite are..
<dl>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_lock.html"><tt>mplib1/bpo_lock.h</tt></a></dt>
<dd>Inter-process locks.</dd>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_list.html"><tt>mplib1/bpo_list.h</tt></a></dt>
<dd> Linked List functions </dd>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_init.html"><tt>mplib1/bpo_init.h</tt></a></dt>
<dd> Segment Create/Attach &amp; Resource functions </dd>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_alloc.html"><tt>mplib1/bpo_alloc.h</tt></a></dt>
<dd> Allocate routines </dd>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_proc.html"><tt>mplib1/bpo_proc.h</tt></a></dt>
<dd> Process functions </dd>
<dt><img src="bpin.gif" align=bottom width=21 height=21>
<a href="bpo_queue.html"><tt>mplib1/bpo_queue.h</tt></a></dt>
<dd> Queue functions </dd>
</dl>
<p>
<hr>
</BODY>
</HTML>

393
doc/bpo_list.html Normal file
View file

@ -0,0 +1,393 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE> bpo_list - Double-linked List Functions </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> bpo_list - Double-linked List Functions </h1>
This file provides linked list functions. There are functions
for initialising, add, removing, and searching. These functions
almost exactly mirror those provided in
<a href="dl_list.html"><tt>mplib1/dl_list.h</tt></a>, but
require that all items be within the same segment.
<p>
Objects are linked together using bpo_Node_t structures and are
collected together by linking to a bpo_List_t structure. These nodes
and lists can each be parts of larger structures or can exist seperately
from the structures they refer to.
<p>
The two structures used have typedefs available for ease of use.
<pre>
typedef struct bpo_Node bpo_Node_t;
typedef struct bpo_List bpo_List_t;
</pre>
<p>
Because there is a issue with sychronisation within shared memory
the bpo_List_t structure contains a number of elements to ensure the
list remains consistent. The first of these is a <tt>bpo_pid_lock</tt>
structure which is used to lock the list before any modifications are
performed on the list header or the list itself. The second item is
a serial number which is updated every time a list is modified in any way.
<p>
<hr>
<h3>The Initialisation functions</h3>
<pre>
bpo_Node_t *bpo_Init_Node( bpo_Node_t *node, char *name, void *item );
</pre>
The Init_Node function is used to initialise a node. All non-NULL
parameters should be in the same segment. The item pointer can be
used with subsequent functions as a pointer to the beginning of the
meta-structure referenced (rather than having to work out its
base by subtracting the node's offset into the structure from the
node pointer returned).
<pre>
bpo_List_t * bpo_Init_List( bpo_List_t *list, int flags );
</pre>
The bpo_Init_List function is used to initialise a bpo_List_t structure.
The only flag that may be passed (other than 0) is LN_IGNORECASE which
causes searchs on the list to be case-insensitive.
<P>
<hr>
<h3>The Remove functions</h3>
There are two sub-groups within the remove functions. The first, most
primitive, are the node based functions. These remove the relevant node
and return a pointer to that node, or NULL if applicable. The second
sub-group are the ones that return pointers to the items referenced in
the nodes. Since these return void pointers they can be simply assigned
to whatever structure type is relevant without any casting.
<p>
Since the latter sub-group return pointers to meta-objects it is likely
that these are the most commonly used.
<pre>
bpo_Node_t *bpo_Remove_Node( bpo_Node_t *node1 );
bpo_Node_t *bpo_Remove_Head( bpo_List_t *list );
bpo_Node_t *bpo_Remove_Tail( bpo_List_t *list );
void *bpo_Remove_Head_Item( bpo_List_t *list );
void *bpo_Remove_Tail_Item( bpo_List_t *list );
</pre>
<hr>
<h3>The Add functions</h3>
The add functions allow for given nodes to be added to lists, either
at the head of the list, or the tail. Unlike the second group of remove
functions, these require the node rather than the object (since an object
may be on multiple lists, so the correct node to use must be provided).
<P>
These functions return either a pointer to the node added, or NULL if there
was a problem (node and list not in same segment, etc).
<pre>
bpo_Node_t *bpo_Add_Head( bpo_List_t *list, bpo_Node_t *node );
bpo_Node_t *bpo_Add_Tail( bpo_List_t *list, bpo_Node_t *node );
</pre>
<p>
There are also to two add functions to place an item at a specific
relative position within a list.
<pre>
bpo_Node_t *bpo_Add_Node_After( bpo_Node_t *node1, bpo_Node_t *node2 );
bpo_Node_t *bpo_Add_Node_Before( bpo_Node_t *node1, bpo_Node_t *node2 );
</pre>
These functions add node2 After or Before node1 respectively.
<hr>
<h3>The Search Functions</h3>
<pre>
void *bpo_Find_Item_By_Name( bpo_List_t *list, char *name );
</pre>
This function searches the list for the named item. If the list
was initialised with the LN_IGNORE_CASE flag, then the search will
be case insensitive (<a href="stricmp.h">stricmp</a>).
The function returns either a pointer to the first item matching
the search, or NULL. Note that the item is not removed from the
list. To remove the item use the bpo_Remove_Node function described
above.
<p>
<pre>
void *bpo_Find_Next_Item_By_Name( bpo_Node_t *node, char *name );
</pre>
The bpo_Find_Next_Item_By_Name function
searches the list which the provided node is on for the first item
<i>after</i> the provided node which matches the name parameter.
The function returns either a pointer to the located item, or NULL.
As with the bpo_Find_Item_By_Name function a found item is not removed
from the list.
<p>
<pre>
bpo_Node_t *bpo_Find_Node_By_Item( bpo_List_t *list, void *item );
</pre>
This function searches the provided list for a node
which points to the supplied item. It either returns
a pointer to the first node that points to the item
or NULL.
<p>
<pre>
void *bpo_Find_Item_From_Node( bpo_Node_t *node );
</pre>
This function returns the item pointed to by the supplied
node, or NULL if it does not point to one. This is of use for
programs that do not want to deal with the internals of a
bpo_Node_t structure.
<p>
<hr>
<h3>The List Walk functions</h3>
<pre>
void bpo_Walk_List( struct bpo_List_t *l_ptr,
bpo_Walk_List_t disp,
void *param );
int bpo_Walk_List2( struct bpo_List_t *l_ptr,
bpo_Walk_List2_t disp,
void *param );
</pre>
where the typedefs are defined as
<pre>
typedef void (*bpo_Walk_List_t) ( void *, void * );
typedef int (*bpo_Walk_List2_t) ( void *, void * );
</pre>
These two functions walk the supplied list and call the supplied
function with a pointer to each item and the supplied parameter.
The bpo_Walk_List
function calls the function for every item on the list. The
bpo_Walk_List2 function calls the function for each item
on the list until the function returns a non-zero value. bpo_Walk_List2
returns either the non-zero value, or reachs the end of the list and returns 0.
<p>
The only permitted modification operation on the list whilst it is
being walked is to remove the supplied node, any other operation
may seriously impair system integrity. It is permissable to
call the bpo_Find_Item_From_Node function.
<p>
To illustrate, consider a structure containing a node and a string.
<pre>
struct demo
{
bpo_Node_t demo_node;
char name[80];
};
</pre>
If a list structure has been allocated <tt>demo_list_ptr</tt> and
has number of these structures
on it, it is possible to list the contents by calling the
<tt>print_demo_list()</tt> function shown below.
<pre>
static void print_demo_item( void *vp1, void *vp2 )
{
FILE *fh;
struct demo *dp;
dp = vp1;
fh = vp2;
fprintf( fh, "Item: %s\n", qp->name );
return;
}
void print_demo_list( FILE *fh )
{
bpo_Walk_List( demo_list_ptr, print_demo_item, fh );)
return;
}
</pre>
<p>
<hr>
<h3>The List Work functions</h3>
The Work_List functions provide a mechanism to operate on a list
whilst ensuring that list is locked for the duration of the required
operation. The functions are similar in style to the Walk_List2 function
with the variation that they take a pointer to a function which has the
list pointer as its first parameter.
<pre>
int bpo_Work_List( bpo_List_t *list,
bpo_Work_List_t work,
void *param );
int bpo_Work_List2( bpo_List_t *list,
bpo_Work_List2_t work,
void *param1, void *param2 );
</pre>
where the function typedefs are defined as
<pre>
typedef int (*bpo_Work_List_t) ( bpo_List_t *, void * );
typedef int (*bpo_Work_List2_t) ( bpo_List_t *, void *, void * );
</pre>
The reason for providing these functions instead of a pair of Lock/Unlock
functions is to ensure that the unlock does actually occur instead of
possibly being forgotten and leaving the list in a locked state which
the owning process is not aware of and blocking access for other
procceses.
<p>
There are another pair of functions which are similar the Work_List
functions but which are designed to only call the work routine when
the list has changed.
<pre>
int bpo_May_Work_List( bpo_List_t *list,
unsigned long *last_ser_nbr,
bpo_Work_List_t work,
void *param );
int bpo_May_Work_List2( bpo_List_t *list,
unsigned long *last_ser_nbr,
bpo_Work_List2_t work,
void *param1, void *param2 );
</pre>
These functions lock the list and then
check whether the serial number pointed to by the
supplied parameter is less than the serial number contained within
the list structure (which, as mentioned above gets incremented every
time there is a list modification). If it is then the work function
is called, on its return the value pointed to by <i>last_ser_nbr</i>
is updated to the current value held on the list.
In either case, the list is then unlocked and the function returns;
<p>
There is also a function
<pre>
unsigned long bpo_Touch_List( bpo_List_t *list );
</pre>
which increments the serial number of a list and returns the current
value.
<p>
<hr>
<h3> List Sort Functions </h3>
There are two sort functions provided for shared memory lists. These
mirror the two sort functions in the
<a href="dl_list.html"> Private List </a> group, and are also
based on the <a href="lmsort.html"> lmsort </a> routine.
<pre>
typedef int (* bpo_sort_i_t)(const void *, const void *);
int bpo_sort_i( bpo_List_t *sort_list, bpo_sort_i_t compar );
int bpo_sort_n( bpo_List_t *sort_list );
</pre>
The first function takes a pointer to a comparison function
which will be called with two pointers to items on the list to be
compared. The value returned from the function should be &gt;0, 0,
of &lt;0 just like <i>qsort</i> &amp; <i>lmsort</i>.
<p>
The second function sorts the list by name observing the case matching
rules on the list.
<p>
<hr>
<h3> List Miscellany </h3>
There are number of other functions available
<pre>
int bpo_Any_In_List( bpo_List_t *list );
</pre>
This function returns the number of items in the list. Note that
unless the list already locked via a call to one of the work list
functions then the value may change due to some other process modifying
the list before your own process can perform its task.
<pre>
int bpo_Transfer_Lists( bpo_List_t *fl_ptr, bpo_List_t *tl_ptr );
</pre>
This function transfers the items from the <i>fl_ptr</i> list to the
<i>tl_ptr</i> list. It does this as a sequence of
<i>bpo_Remove_Head</i> &amp; <i>bpo_Add_Tail</i> operations to avoid
possible deadlock conditions with the two lists.
<p>
<pre>
void bpo_Free_List( bpo_List_t *list, int flags );
void bpo_Free_Node( bpo_Node_t *node, int flags );
</pre>
where the flags are a bit-wise or of the following defines
<pre>
BPO_REMOVE_NODES
BPO_FREE_NODES
BPO_FREE_ITEMS
BPO_FREE_NAMES
</pre>
The <i>bpo_Free_List</i> function provides a mechanism to free up the
various elements of items on a list. It is, not surprisingly, implemented
as a call to <i>bpo_Walk_List</i> with <i>bpo_Free_Node</i> as the supplied
function.
<p>
The <i>bpo_Free_Node</i> function takes a pointer to a node and a
set of flags. It then performs the following operations
<ol>
<li>If <b>BPO_REMOVE_NODES</b> or <b>BPO_FREE_NODES</b> is set the
node is removed from the list.
<li>If <b>BPO_FREE_NAMES</b> is set any name pointed to by the
node is freed and the pointer cleared.
<li>If <b>BPO_FREE_ITEMS</b> is set any item pointed to by the
node is freed and the pointer cleared.
<li>If <b>BPO_FREE_NODES</b> is set the node is freed.
</ol>
<p>
<hr>
<h2> List Validation </h3>
<pre>
typedef int (*p_func_t)(FILE *,const char *,...);
int bpo_List_Chk( bpo_List_t *rlp,
p_func_t p_func,
FILE *fh );
int bpo_Validate_List( bpo_List_t *rlp );
int node_list_header( p_func_t p_func, FILE *fh );
int node_list_details( void *base, bpo_Node_t *bnp,
p_func_t p_func,
FILE *fh );
</pre>
The <i>bpo_List_Chk</i> function provides a way to validate the
integrity of the supplied list. It returns a non-zero value if the
list has problems.
<p>
The parameters are a list pointer, a pointer to a print function
and a file handle. The print function should
take a file pointer, a format string and a variable number
of additional arguments exactly like <i>fprintf</i> and
<a href="fprintfile.html"><i>fprintfile</i></a>. It is permissable
to pass <b>NULL</b> for the print function to avoid any output.
<p>
The validation checks the list header contains
the correct list header information, the linkage between each of the
nodes on the list in both directions, and that the items claim to
be on the list supplied.
<p>
The <i>bpo_Validate_List</i> function is simply a wrapper around
<i>bpo_List_Chk</i> where the print function is <i>fprintf</i> and
the file handle is <b>stderr</b>.
<p>
The <i>node_list_header</i> function provides the column headings for
a node display. The <i>node_list_details</i> function prints out
details of the node itself. These functions are used in the
validate functions above to display details of the node or nodes
with problems. They can also be used to show the contents of a node
when a display of the details is required, as in the following example.
<pre>
static void show_node( bpo_Node_t *node, FILE *fh )
{
void *base;
base = Get_SODB_Base( node );
node_list_details( base, node, fprintf, fh );
return;
}
static int show_list( bpo_List_t *list, FILE *fh )
{
if (bpo_Any_In_List( list ))
{
node_list_header( fprintf, fh );
bpo_Walk_List_N( list, (bpo_Walk_List_N_t)show_node, fh );
}else
{
fprintf( fh, "list is empty\n" );
}
return(0);
}
int
Show_This_List( bpo_List_t *list, FILE *fh )
{
return(bpo_Work_List( list, (bpo_Work_List_t)show_list, fh );
}
</pre>
<hr><p>
</BODY>
</HTML>

View file

@ -0,0 +1,37 @@
<html>
<head>
<title> bpo_list - List Walking Example </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> bpo_list - List Walking Example </h1>
To illustrate the shared list walk function,
consider a structure containing a node and a string.
<pre>
struct demo
{
bpo_Node_t demo_node;
char name[80];
};
</pre>
If a list structure has been allocated <tt>demo_list_ptr</tt> and
has number of these structures
on it, it is possible to list the contents by calling the
<tt>print_demo_list()</tt> function shown below.
<pre>
static void print_demo_item( struct demo *dp, FILE *fh )
{
fprintf( fh, "Item: %s\n", qp->name );
return;
}
void print_demo_list( FILE *fh )
{
bpo_Walk_List( demo_list_ptr,
(bpo_Walk_List_t)print_demo_item,
fh );
return;
}
</pre>
<p><hr><p>
</body>
</html>

104
doc/bpo_lock.html Normal file
View file

@ -0,0 +1,104 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title> bpo_lock - Inter-Process Locking Routines </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> bpo_lock - Inter-Process Locking Routines </h1>
Since multiple processes can access a block of shared memory at any
one time there needs to be some form of locking mechanism to avoid
a number of processes modifying the structure at once, and putting
the structure into an indeterminate state.
<p>
There are a number of variations of locking available with different
characteristics.
<p>
<hr>
<h2> Process Tracking Locks </h2>
These main class of lock functions are those that deal with process locks.
These functions behave like traditional binary access locks but with the
additional capability that the pid currently owning the lock
is held within the lock structure so that if the process dies this
can be deteced by other processes attempting to obtain the lock and
allowing the first process to detect this a way of obtaining the lock.
<p>
This group of functions is the prefered locking mechanism since it allows
recovery from a number of exception conditions which cannot be
handled by a simple bit-lock.
<p>
<pre>
struct bpo_pid_lock * bpo_Init_pid_lock( struct bpo_pid_lock *bplp,
struct timeval *udtp );
void bpo_pid_Lock( struct bpo_pid_lock *bplp );
void bpo_pid_Unlock( struct bpo_pid_lock *bplp );
</pre>
The initialisation function takes a pointer to the lock and a pointer
to a <b>timeval</b> structure which should contain a timeout value to
be used to determine how often a process should check whether the
current owner has died. If the <b>timeval</b> pointer is <b>NULL</b>
the timeout value will default to one second.
<p>
The lock and unlock functions perform as one would expect.
<p>
<hr>
<h2>The Binary Lock</h2>
The binary locking routines consist of a complementary pair of lock and unlock
routines. These both take as their sole parameter a pointer to a b_lock
structure. The routines perform processor atomic instructions or equivalent
on this structure to ensure lock consistency.
<p>
<pre>
void b_Init( b_lock *lockp );
</pre>
This function sets the lock up for use by the other functions. If this
is used on a lock already in use then unexpected behaviour may occur.
<p>
<pre>
void b_Lock( b_lock *lockp );
</pre>
This function waits until it can gain exclusive access to the structure.
It waits by using the select call with a small timeout.
<p>
<pre>
void b_Unlock( b_lock *lockp );
</pre>
This function clears the lock, freeing it up for other users.
<p>
<pre>
int b_TryLock( b_lock_t *lockp );
</pre>
This function attempts to obtain the lock. It returns zero if
it succeeds, and non-zero if it failed.
<p>
<pre>
long b_Lockval( b_lock *lockp );
</pre>
This function returns a non-zero value if the lock is currently
held by someone.
<p>
<hr>
There is also a third method of locking whose use is not recommended.
Details of it can be found
<a href="bpo_lock_old.html"> here. </a>
<p>
<hr>
<h2> Sleep functions </h2>
The lock routines normally use the following routines when waiting
to obtain access to the locks described above.
<p>
<pre>
int bpo_nap_a_while( long secs, long usecs );
</pre>
This function uses the <i>select</i> system call to causes the
process to sleep for the specified time.
<p>
<pre>
int bpo_take_a_nap( void );
</pre>
This function call the one above to sleep for a pre-defined time,
usually 5mS.
<p>
</BODY>
</HTML>

62
doc/bpo_lock_old.html Normal file
View file

@ -0,0 +1,62 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE> bpo_lock - Inter-Process Locking Routines </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> bpo_lock - Inter-Process Locking Routines - Deprecated </h1>
The following group of inter-process locking routines has
been deprecated and their use in new code is not recommended.
<p>
Experience in using these functions within the other parts of the
<i>bpo_</i> sub-system has shown that they are not the best solution
to the problem of providing sequential access to structures. They are
are no longer used internally and may be removed from a later version
of the library.
<p>
<hr>
<h2>The Read/Write Lock</h2>
These more complex locks allow for multiple simutaneous readers or for
a single writer. It also ensures that once a process is waiting for the
write lock all processes that require a read lock are suspended until
the write lock as been obtained and freed.
<p>
There are six functions in three pairs. They all take as their single
parameter a pointer to a <tt>bpo_fl_lock</tt> structure.
<p>
The read lock functions
<pre>
void bpo_RLock( struct bpo_fl_lock *bflp );
void bpo_RUnlock(struct bpo_fl_lock *bflp );
</pre>
the write lock functions
<pre>
void bpo_WLock( struct bpo_fl_lock *bflp);
void bpo_WUnlock(struct bpo_fl_lock *bflp );
</pre>
and the lock change functions
<pre>
int bpo_RWLock( struct bpo_fl_lock *bflp );
void bpo_WRLock( struct bpo_fl_lock *bflp );
</pre>
<p>
The first four functions behave as one might expect, blocking on Lock until
appropriate, and clear immediately on Unlock.
<p>
The last two functions
require a little explanation. These are provided to allow an upgrade
from Read lock status to Write lock status and vice-versa. For the change
from Read to Write lock the function returns an integer which specifies
whether the change was succesfull. It returns 1 on success, and 0 on
failure.
<p>Failure can occur if there is already a process waiting for
the write lock. If the routine fails, then the application should release
the read lock (which the other application is waiting for) and retry after
some suitable interval to either gain a read lock and upgrade, or to
obtain a write lock straight away. Regardless of which method is used, any
object being refered to on the list should be searched for again, since the
process that gained the write lock previously may have removed it (unless
you can <b>guarantee</b> that this is not the case).
</BODY>
</HTML>

218
doc/bpo_proc.html Normal file
View file

@ -0,0 +1,218 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title> bpo_proc - Process Registration Routines </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> bpo_proc - Process Registration Routines </h1>
The bpo_proc module provides the means for a process to register
its interest within one or more segments, and to provide a notification
channel (in the form of a file-system fifo) that can be used
by other processes to inform one that there is something to be done.
<p>
<pre>
int Set_My_Proc_Details( const char *group_name,
const char *prog_name,
const char *fifo_prefix,
const char *fifo_name,
int fifo_mode,
int flags );
</pre>
This call sets the base data used when registering in a shared
memory segment. The group name and program name are provide
a way to catagorise sets of programs and differentiate between
programs within a group.
<p>
The <b>group_name</b> parameter, if provided, is a informational
parameter which gives the logical group the program belongs in.
<p>
The <b>program_name</b> parameter, if provided, gives the logical
name of the program.
<p>
The <b>fifo_prefix</b> if provided, gives the directory where the
pipe for the process should be created. If the parameter is NULL
or empty then the routine will use
<pre>
eval_config_default( "PIPE_DIR", "$HOME/pipe" )
</pre>
as a default.
<p>
The <b>fifo_name</b> parameter, if provided, gives the full name
to be used for the process fifo.
<p>
The <b>fifo_mode</b> parameter gives the access mode for the fifo
if it has not already been created.
<p>
The <b>flags</b> parameter is a set of bit flags which modify the
behaviour of the routine. The three values, which can be bit-wise
or-ed together are
<pre>
#define SHM_INHERIT_GROUP BIT(0)
#define SHM_INHERIT_PROGRAM BIT(1)
#define SHM_AUTOMAGIC_PIPE BIT(2)
</pre>
If <b>SHM_INHERIT_GROUP</b> or <b>SHM_AUTOMAGIC_PIPE</b> is set
then the <b>group_name</b> parameter is ignored, and the value is
taken from the environment value <b>GROUP_NAME</b>.
<p>
If <b>SHM_INHERIT_PROGRAM</b> or <b>SHM_AUTOMAGIC_PIPE</b> is set
then the <b>program_name</b> parameter is ignored and the value
is taken from the environment value <b>PROGRAM_NAME</b>. If this is
not set then the value <i>unknown</i> is used.
<p>
If <b>SHM_AUTOMAGIC_PIPE</b> is set then the pipe_name parameter is
ignored and a string based on group name, program name and pid is used.
<hr>
<pre>
int Register_Process_Details( const void *hint );
int Deregister_Process_Details( const void *hint );
</pre>
The Register_Process_Details routine takes a hint to describe
which segment to use. This is combined with the details
previously sent to <i>Set_My_Proc_Details</i> and used to
register in the segment indicated. If <i>Set_My_Proc_Details</i> has
not been called, it is called automatically as
<pre>
Set_My_Proc_Details( NULL, NULL, NULL, NULL,
Get_SODB_Privs(hint), SHM_AUTOMAGIC_PIPE );
</pre>
<p>
The Deregister_Process_Details routine takes a hint to identify
the segment in question. It removes the process details from
the segment.
<p>
<hr>
<pre>
int Inform_Process_Str( const void *hint, const char *pid_str );
int Inform_Process_Pid( const void *hint, pid_t pid );
</pre>
These two routines provide the mechanism to inform another process
that there is some work for it to do. They both take a hint as to
which segment to use, and then a pid number in some form (pid_t or
string of the pid).
<p>
The routines then search the process details in the segment
provided and, if found, open the fifo associated with
the supplied pid and write a token to the fifo, and close the
file. Both routines return 1 on success and 0 on failure (cannot
find process, cannot open fifo).
<p>
<pre>
int Inform_Named_Pipe( const char *pipe_name );
</pre>
This routine simply perfors the last steps of the previous routines
and opens the named pipe, writes a token to it and closes the pipe.
The routine return 1 on success and 0 on failure.
<p>
<hr>
<pre>
int Wait_Process_Pipe( void );
</pre>
This routine is used to wait for an event for oneself. It does
this by reading a single byte from its own fifo. The return value
from the routine is either 0 (unknown segment, process not registered)
with errno set to 0, or the return from the read() call,
in this case the normal errno processing should be performed.
<p>
<hr>
<pre>
int Get_Process_Pipe_fd( void );
</pre>
This routine returns the file descriptor for the fifo
opened when the process was registered. The return value
is -1 if the process details could not be found or the file
was not opened. This routine would normally be used in conjunction
with other file descriptors in a select() call.
<p>
<pre>
int Add_This_Pid_Resource( const void *hint, bpo_Node_t *nptr );
</pre>
This function allows for an allocated block from a segment to be attached
to the process registration. Thus, when the process completes and
deregisters (or is cleaned up, see below) any blocks are also freed.
<p>
<hr>
<h2> Standard Communications Shared Memory Segment </h2>
<pre>
void *comms_shm_attach( const char *config_name, int flags );
</pre>
This function provides a way to connect to a standardised shared memory
segment which can be used for core communications activity and small
application specific data blocks.
<p>
The <b>config_name</b>parameter must be a non-NULL parameter and
specify the name of a file containing the configuration details
of the standard communications shared memory segment. Details of
the required configuration variables can be found
<a href="../util_doc/common/shm.html"> here. </a>
<p>
The <b>flags</b> parameter should be zero or <b>SODB_READ_CONFIG</b>
which causes the configuration file to read into a configuration
space of the same name.
<pre>
void comms_shm_detach( void );
</pre>
This function provides a way to detach the standard communications shared
memory segment.
<pre>
void *get_comms_hint( void );
</pre>
This function returns a pointer to the standard communications
shared memory segment if it is attached or NULL otherwise.
<p>
<hr>
<h2> Typical Use </h2>
A lot of programs will typically only use the standard communications
segment and attach to it using the <i>comms_shm_attach</i> routine.
The typical call sequence which provides the best set of in-core
information would normally be placed within the <i>main</i> routine
and would look like.
<pre>
/* Read configuration file, either some default or a
command line option
*/
read_config_file( config_file );
/* Set the process details if they will not inherit correctly */
if (getenv("PROGRAM_NAME")==NULL)
Set_My_Proc_Details( NULL, mpbasename(argv[0]),
NULL, NULL, 0600, 0 );
/* get the name of the shared memory configuration
file from the main configuration file
*/
shm_file = eval_config_default( "SHM_CONFIG",
"$HOME/config/shm.cfg" );
/* Attach to shared memory */
comms_hint = comms_shm_attach( shm_file, SODB_READ_CONFIG );
</pre>
<p>
<hr>
<h2> House Keeping Routines </h2>
The following routines are normally used by the
<a href="../util_doc/watchdog/watchdog.html"> watchdog </a>
utility to tidy up any process related details, and any redundant
fifo files.
<p>
<pre>
int scan_dead_pipes( const char *dir_name );
</pre>
This function scans the provided directory for pipe files
whose name is of the format <b>xxxx.nnnn</b>. It then decodes
the <b>nnnn</b> and tests whether a process of that id is dead. If it
is then the pipe is removed.
<p>
<pre>
int Remove_Shm_Process( const void *hint, const char *pid_str );
</pre>
This function removes the details of the supplied process from
the provided segment if the process is registerd in it and appears
to be dead. In addition, any previously attached process specific
resources added above will also be freed.
</body>
</html>

160
doc/bpo_queue.html Normal file
View file

@ -0,0 +1,160 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title> bpo_queue - Message Queue Routines </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> bpo_queue - Message Queue Routines </h1>
The bpo_queue module provides the mechanisms for queueing
messages between processes, and for rendevousing on a queue
for a message.
<p>
<hr>
<pre>
struct bpo_Q * mpCreateQ( const void *hint,
const char *q_name,
int q_max, int q_flags,
int q_mech );
</pre>
The mpCreateQ routine allows for the creation of a queue, and how the queue
should react when messages are placed on it. This routine
should also be called when the queue already exists as a multiple reader
and your process wishes to be registered as a reader.
<p>
The parameters are as follows:
<dl>
<dt>void *hint</dt><dd>A hint pointer for which segment to use.</dd>
<dt>char *q_name</dt><dd>The name the queue should be known by.</dd>
<dt>int q_max</dt><dd>Specifies the maximum number of items that are
allowed on the queue.</dd>
<dt>int q_flags</dt><dd>The flags parameter can be one of two values.
<ul>
<li><tt>Q_SOLE_READER</tt> This will be the only process reading
from this queue.
<li><tt>Q_MULTI_READ</tt> This process may be one of many that
will read from the queue.
<li><tt>Q_PERSISTENT</tt> This flag can be used in conjunction with
the <tt>Q_SOLE_READER</tt> flag to ensure that the queue is not
removed on a cleanup operation when there is not current reader.
</ul>
</dd>
<dt>int q_mech</dt><dd>This specifies what form of notification
should be used when an item is placed on the queue. It currently
may be one of two values.
<ul>
<li><tt>Q_NM_NONE</tt> No action should be taken when an item is added.
<li><tt>Q_NM_PIPE</tt> This causes the <i>Inform_Process_Pid</i>
routine to be called for each attached process whenever a message
is placed on the queue.
</ul>
</dd>
</dl>
The routine either returns a pointer to the queue structure, or NULL
if there is any problem. The routine may fail for a number of reasons,
these include;
<ul>
<li>Invalid hint.
<li>Segment does not support queues.
<li>Unable to allocate queue resource.
<li>Queue already exists and is <tt>Q_SOLE_READER</tt> by another live process.
<li>Unable to allcoate space for queue structure.
</ul>
Note that it is possible for a process to take over a existing
Q_SOLE_READER queue structure if the process that created it is no longer
running.
<p>
<hr>
<pre>
int mpPutMsg( const char *q_name, bpo_Node_t *q_node );
</pre>
This function attaches the node to the queue in question.
The function function returns -1 on a serious error
(queue does not exist, queue has been deleted, etc),
0 if the queue is full and 1 if the message was added successfully.
<p>
<pre>
void *mpGetMsg( const char *q_name, const void *hint );
</pre>
This function attempts to remove an item from the named queue.
If the function succeeds the value returned will be a pointer
to whatever type of structure was pointed to when the queue node
was initialised. If there is a problem (queue does not exist, nothing
on the queue) then the function returns NULL.
<p>
<hr>
The following functions deal with a higher layer abstraction, a queue
message. This structure
<pre>
struct bpo_Q_Mesg
{
bpo_Node_t Q_Node; /* Node for linking to Q */
off_t reply_Q; /* offset to reply Q */
};
</pre>
contains a node for linking the item into a queue, and an offset
to a queue which should exist, and where the message should be sent
after it has been processed.
<p>
The usual operation of these functions would be as follows
<pre>
<b>Process One</b> <b>Process Two</b>
Create reply queue Create work Q
Create item with Q_mesg Wait on work Q
Post to work Q (with reply Q)
GetMsg from work Q
Wait Reply Q process message
Reply message
Get message from reply Q
</pre>
The two functions are:
<pre>
int mpPostMsg( const char *q_name,
struct bpo_Q_Mesg *mesp,
struct bpo_Q *reply_q );
int mpReplyMsg( struct bpo_Q_Mesg *mesp );
</pre>
As is apparent, the mpPostMsg routine, takes a name parameter specifying
the queue to attach the node to, a pointer to the bpo_Q_Mesg structure
containing the node to be linked, and a pointer to the reply queue.
<p>
The mpReplyMsg function simply takes a pointer a bpo_Q_Mesg structure
which will already have the queue to return to set by the originator's
mpPostMsg call.
<p>
<hr>
<pre>
void *mpFindQ( const char *q_name, const void *hint );
</pre>
This function returns a pointer to the requested queue if it
exists, or NULL if it does not.
<p>
<pre>
int mpCheckQ( const char *q_name, const void *hint );
</pre>
This function returns that number of items on the queue,
or -1 if the queue cannot be found.
<p>
<pre>
int mpWaitQ( const char *name, const void *hint );
</pre>
The mpWaitQ function waits on the named queue until there
is either a message on the queue, or the process is signalled.
The function returns the number of items on the queue or -1
if the queue could not be found.
<p><hr>
<pre>
void *bpo_send_and_get( const char *q_name,
struct bpo_Q_Mesg *bpo_msg,
struct bpo_Q *reply_q );
</pre>
The <i>bpo_send_and_get</i> function provides a convenient wrapper
around a
<pre>
mpPostMsg();
mpWaitQ();
mpGetMsg();
</pre>
sequence together with suitable error trapping.
</body>
</html>

81
doc/build_argv.html Normal file
View file

@ -0,0 +1,81 @@
<html>
<head>
<title> build_argv </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> build_argv </h1>
The <i>build_argv</i> function is a mechanism to build an <b>argv</b>
vector like that provided to <i>main</i>.
<p>
<pre>
struct argv_track *build_argv_track( struct argv_track *argvtp, ... );
</pre>
The function takes pointer to an <b>argv_track</b> structure allocated
on a previous call to the function or NULL if
you require one to be allocated for you, and then a sequence of string
pointers terminated by a NULL.
<p>
The function duplicates each string, splits it on whitespace, and if the
sub-string begins with a '$' or '%' then it is replaced by its evaluation
from the environment and configuration space. This is done by a call to
<i>eval_config_default( NULL, sub_string )</i>.
<p>
Once all the strings have been split and evaluated the routine
then constructs an <b>argv</b> array with a terminating NULL pointer.
<p>
The routine then sets the argv and argc elements of the tracking structure
and returns a pointer to the track structure.
<p>
If the routine is unable to allocate an <b>argv_track</b> structure
when required the function returns NULL.
<p>
<pre>
void free_argv_track( struct argv_track *argvtp );
</pre>
This function frees up the <b>argv_track</b> structure and any associated
memory that was allocated during the string duplication.
<hr>
<h2> Example Use </h2>
Given a program like
<pre>
static void print_argv( int argc, char *argv[] )
{
int t=0;
while (t&lt;argc)
{
printf("argv[%d]=%s\n",t,argv[t]);
t++;
}
return;
}
int main( int argc, char *argv[] )
{
struct argv_track *argvtp;
printf("Original argv\n");
print_argv( argc, argv );
set_config_string( "WIDTH", "50" );
argvtp = build_argv_track( NULL, "$USER %WIDTH", argv[1], NULL );
printf("New argv\n");
print_argv( argvtp-&gt;argc, argvtp-&gt;argv );
free_argv_track( argvtp );
return(0);
}
</pre>
Would give behave as follows
<pre>
$ argv_test this is a test
Original argv
argv[0]=argv_test
argv[1]=this
argv[2]=is
argv[3]=a
argv[4]=test
New argv
argv[0]=eric
argv[1]=50
argv[2]=this
</pre>
</body>
</html>

139
doc/cfg_eval.html Normal file
View file

@ -0,0 +1,139 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines - Evaluation</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines - Evaluation</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
<hr>
<h2>eval_private_default</h2>
<pre>
char *eval_private_default( const char *list_name,
const char *config_name,
const char *def_name );
#define eval_config_default(cfg,def) eval_private_default( NULL, cfg, def )
</pre>
This function checks whether a given config keyword exists. If it
does, the value is passed to <tt>eval_private_str()</tt> and a
pointer to the result is returned to the caller. If the keyword
does not exist, the <tt>def_name</tt> parameter is passed to
<tt>eval_private_str()</tt> instead, and the result returned to
the caller.
<p>
So, when the environment contains
<pre>
LOG_DIR=/var/log
TMPDIR=/var/tmp
</pre>
and the configuration file contains
<pre>
LOG_FILE=$LOG_DIR/mylogfile
ERROR_FILE=$LOG_DIR/%(PROGNAME).err
PROGNAME=kibolater
</pre>
Among the possible evaluations are:
<pre>
eval_config_default( "LOG_FILE", "$LOGDIR/log.tmp" );
</pre>
gives
<pre>
/var/log/mylogfile
</pre>
And
<pre>
eval_config_default( "ERROR_FILE", "$TMPDIR/error_file" );
</pre>
gives
<pre>
/var/log/kibolater.err
</pre>
<p>
Note that it is only environment variables and configuration variables in
the initial value or default that are expanded.
<hr>
<h2>eval_private_str</h2>
<pre>
char *eval_private_str( const char *list_name, const char *value );
#define eval_config_str(from) eval_private_str( NULL, from )
</pre>
This function returns a pointer to string which is the result
of expanding any components of the supplied value which refer
to environment variables or configuration variables in the
supplied list.
<p>
This is best illustrated by considering the following example.
<P>
Suppose the environment contains
<pre>
LOG_DIR=/var/log
</pre>
and that the configuration has
<pre>
LOG_FILE=log_file.now
</pre>
the string returned by
<pre>
eval_config_str( "$LOG_DIR/%LOG_FILE" );
</pre>
would be
<pre>
/var/log/log_file.now
</pre>
The config value may contain multiple environment variables, or
none at all.<p>
In addition, a <tt>'%'</tt> character followed by a variable name
is assumed to refer to another configuration value, and is also
evaluated.<br>
So, if the environment has
<pre>
LOG_DIR=/var/log
</pre>
and the configuration has
<pre>
LOG_FILE=$LOG_DIR/%LOG_UNIT/log_file.now
LOG_UNIT=mylogdir
</pre>
then the string returned by
<pre>
eval_config_str( "LOG_FILE" );
</pre>
would be
<pre>
/var/log/mylogdir/log_file.now
</pre>
<p>
There is a further variation which can be used. Any <tt>'$'</tt>
or <tt>'%'</tt> character may be followed by the other character
(preceding the variable name). In this case, if the variable is
not found in the first location, it is searched for in the second.
<p>
To produce a <tt>'$'</tt>
or <tt>'%'</tt> in an evaluated string the character should be doubled.
Therefore <tt>'$$'</tt> produces <tt>'$'</tt>
and <tt>'%%'</tt> produces <tt>'%'</tt>.
<p>
No nested evaluatiuon takes place in an effort to avoid
looped contructs.
<p>
<h3>Note:</h3>
By default, evaluation of config variables will produce a result
which will be stored in a <tt>malloc</tt>ed buffer which will be stored
against the variable in case it is needed again. These stored evaluations
will be freed any time an item is added to the list, or a value is changed.
<p>
This behavour can be inhibited by performing
<pre>
set_config_flags( list_name, CONFIG_NO_EVAL );
</pre>
on the requisite list.
<p>
<hr>
</body>
</html>

62
doc/cfg_example.html Normal file
View file

@ -0,0 +1,62 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file examples</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file examples</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
The configuration file routines can be used in a number of ways. The
most obvious example is signalling whether to output debugging
information. So, suppose we have a routine which we are writing which
looks up an employee name for a given an employee ID.
<pre>
get_emp_name( int emp_id, char *emp_name )
{
int get_emp_name_debug,rv;
*emp_name='\0';
get_emp_name_debug = get_config_flag("GET_EMP_NAME_DEBUG");
if (get_emp_name_debug)
fprintfile(stderr,"get_emp_name: entry: id=%d\n", emp_id );
.... do fetch ....
if (get_emp_name_debug)
{
if (rv==FAIL)
fprintfile(stderr,"get_emp_name: failed\n" );
else
fprintfile(stderr,"get_emp_name: name=<%s>\n", emp_name );
}
return(rv);
}
</pre>
So, instead of making the debug portion compile conditional which
leads to a different set of code being produced for production than
that tested, the same routine goes to production. Since the default
for a flag variable is false the debug output is suppressed until
a configuration variable is provided which changes the value.
<p>
Another example would be to determine the name of a logfile.
<pre>
char *logname;
FILE *log_fh;
logname = eval_config_default( "LOGFILE_NAME", "$LOG_DIR/progname.log" );
log_fh = fopen( logname, "a" );
if (log_fh)
fprintfile( log_fh, "logfile %s opened\n", logname );
</pre>
Where <tt>progname</tt> is replaced with the name of the program
being developed.
<p>
<hr>
<p>
</body>
</html>

47
doc/cfg_file.html Normal file
View file

@ -0,0 +1,47 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
The configuration file routines provide a general mechanism for
storing run-time configuration information. They
provide a suite of routines to initialise, read, and evaluate
configuration variables. To read an introduction to the users'
view of these routines click
<a href="configsummary.html">here.</a>
<p>
For examples of use click
<a href="cfg_example.html">here.</a>
<p>
Each set of variables and their corresponding values are held in
a designated namespace. Each namespace is know by its <i>list_name</i>,
and there is a default namespace where the <i>list_name</i> is
<tt><b>NULL</b></tt>. Since most programs normally only need a
single namespace there are a set of macros defined in the header
file which automatically supply the
<tt><b>NULL</b></tt> list_name. The macro definitions are shown
below the corresponding private function they expand to.
<p>
<hr>
The routines can split up into the following logical sections.
<p>
<img src="ppin.gif">
<a href="cfg_init.html">Initialisation </a><p>
<img src="ppin.gif">
<a href="cfg_read.html">Reading variables </a><p>
<img src="ppin.gif">
<a href="cfg_set.html">Setting Variables </a><p>
<img src="ppin.gif">
<a href="cfg_eval.html">Evaluating Variables </a><p>
<img src="ppin.gif">
<a href="cfg_misc.html">Miscelleaneous </a><p>
<p>
<hr>
</body>
</html>

69
doc/cfg_init.html Normal file
View file

@ -0,0 +1,69 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines - Initialisation</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines - Initialisation</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
<hr>
<h2>Initialisation Routines</h2>
There are 3 initialisation routines, these either read the contents
of a file, a single string, or an array of strings.
<h2>read_private_file</h2>
<pre>
int read_private_file( const char *list_name,
const char *filename );
#define read_config_file(filename) read_private_file( NULL, filename )
</pre>
This function reads the contents of the specified file as a series
of lines. After discarding comment lines (those starting with '#')
and blank lines, the contents are parsed for two fields seperated
by one of the following characters <tt>' ',',','=',':','\t'</tt>.
Thus the format is;
<pre>
KEYWORD=VALUE
</pre>
These fields are stored on a configuration list and are available
for interrogation at some later time.
<p>
Lines are read in order, and duplicate keywords will replace the
previous values. All keywords are case insensitive.
<p>
This function returns <tt>1</tt> if the file was opened successfully
and <tt>0</tt> if the open failed.
<p>
<hr>
<h2>read_private_string</h2>
<pre>
int read_private_string( const char *list_name,
const char *config_string );
#define read_config_string(line) read_private_string( NULL, line )
</pre>
This function takes a single string conforming to the format described
in <tt>read_private_string</tt>, parses it and adds/inserts the details
into the configuration list.
<P>
This function returns <tt>TRUE</tt> if the details were added/inserted
and <tt>FALSE</tt> if it failed.
<p>
<hr>
<h2>read_config_string_array</h2>
<pre>
int read_private_string_array( const char *conf_array[] );
#define config_string_array(cs) read_private_string_array( NULL, cs )
</pre>
This function takes an array of string pointers and parses, adds/inserts
each in turn into the configuration list.
<p>
The function returns the number of lines successfully processed.
<p>
<hr>
</body>
</html>

117
doc/cfg_misc.html Normal file
View file

@ -0,0 +1,117 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
There are a number of miscelleaneous functions which are available.
These can be used
<p>
<h3>List Flags</h3>
<pre>
int get_list_flags( const char *list_name );
int set_list_flags( const char *list_name, int new_val );
</pre>
These two functions allow for the setting and reviewing of the flags
stored against the supplied list. The only value currently of use is
<tt><b>CONFIG_NO_EVAL</b></tt> which forces the list not to cache
the evaluated strings.
<hr>
<h3>Default Config File Use</h3>
<pre>
int watch_cfg_file( const char *config_name );
int check_cfg_file( int force );
</pre>
The <tt>watch_cfg_file()</tt> function takes a string parameter
which specifies a filename which should be monitored. The current
modification timestamp (st_mtime) of the file is noted for later
comparison.
<p>
The <tt>check_cfg_file()</tt> function checks the current modification
timestamp of the file specified to <tt>watch_cfg_file()</tt>. If the
file has changed or the force parameter is set then the file is read
using the <tt>read_config_file</tt> macro (which reads into the default
list namespace).
<p>
<hr>
<h3>Evaluation Flushing</h3>
<pre>
int flush_list_evals( const char *list_name );
void flush_item_eval( const char *list_name, const char *item )
</pre>
When evaluating configuration variables the routines will normally
maintain a copy of the result to speed up any further evaluations of
the variable. These copies are flushed whenever any of the
<a href="cfg_init.html">read</a> functions are called. In case
there is a requirement to flush on demand the above two functions
are provided.
<p>
The <tt>flush_list_evals()</tt> function takes a list name and
flushes all evaluation strings for that list.
<p>
The <tt>flush_item_eval()</tt> function takes a list name and an
item name and flushes the evaluation for that item.
<p>
<hr>
<h3>Accessing A List's Contents </h3>
There are two functions available which can be used to access
a given configuration list's contents.
The first is
<pre>
int dump_private_contents( const char *list_name, FILE *fh );
</pre>
This function takes the name of a list and a file handle and produces
a listing of the contents similar to the following
<pre>
List Name: my_config
Time: 1996/12/31 13:45:56:78
Item Key: LOG_FILE
Value: $LOG_DIR/mylog.log
Eval: /var/spool/log/mylog.log
Item Key: CURRENCY_DEBUG
Value: FALSE
</pre>
where evaluations are printed if they exist.
<p>
The second function available is
<pre>
typedef void (*config_disp_t)( const char *, const char *,
const char *, void * );
int report_private_contents( const char *list_name,
config_disp_t disp_func,
void *param );
</pre>
This function takes the name of a list, a pointer to a reporting function,
and a <tt>void *</tt> parameter to be passed to that function. The
reporting function is passed four parameters. These are, in order, the item
name, the item value, the evaluation, and the <tt>void *</tt> parameter
passed to the <tt>report_private_contents()</tt> function.
<p>
Thus, the item details as illustrated above can be produced as follows.
<pre>
void item_show( const char *item, const char *value,
const char *eval, void *param )
{
FILE *fh = param;
fprintf( fh, "Item Key: %s\n", item );
fprintf( fh, " Value: %s\n", value );
if (eval)
fprintf( fh, " Eval: %s\n", eavl );
return;
}
</pre>
<hr>
</body>
</html>

67
doc/cfg_private.html Normal file
View file

@ -0,0 +1,67 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
The following are details of the functions which provide
multiple namespace versions of the standard configuration file routines.
<pre>
int read_private_file( const char *list_name,
const char *fname );
int read_private_string( const char *list_name,
const char *conf_str );
int read_private_string_array( const char *list_name,
const char *conf_str[] );
int raw_private_string( const char *list_name,
const char *key,
const char *value );
char *get_private_string( const char *list_name,
const char *key );
int get_private_int( const char *list_name,
const char *key );
double get_private_double( const char *list_name,
const char *key );
int get_private_flag( const char *list_name,
const char *key );
char *eval_private_str( const char *list_name,
const char *from );
char *eval_private_default( const char *list_name,
const char *config_name,
const char *def_name );
int set_private_string( const char *list_name,
const char *key,
const char *newval );
int set_private_int( const char *list_name,
const char *key,
int newval );
int set_private_double( const char *list_name,
const char *key,
double newval );
int set_private_flag( const char *list_name,
const char *key,
int newval );
</pre>
<p>
<hr>
<p>
</body>
</html>

87
doc/cfg_read.html Normal file
View file

@ -0,0 +1,87 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
<hr>
<h2>get_private_string</h2>
<pre>
char *get_private_string( const char *list_name,
const char *key );
#define get_config_string(key) get_private_string( NULL, key )
</pre>
This function returns a pointer to the value field if the
keyword was found, or <tt>NULL</tt> if it was not found.
<p>
<b>Note:</b>
The pointer returned is actually that of a static buffer,
not to the real item stored on the list. If the value is required
to be maintained then please ensure that the string is copied
into your own buffer before calling this or any other routines in
this suite.
<p>
<hr>
<h2>get_private_int</h2>
<pre>
int get_private_int( const char *list_name,
const char *key );
#define get_config_int(key) get_private_int( NULL, key )
</pre>
This function returns an <tt>atoi()</tt> of the value if the
keyword is found, and 0 if it is not found.
<p>
<hr>
<h2>get_private_double</h2>
<pre>
double get_private_double( const char *list_name,
const char *key );
#define get_config_double(key) get_private_double( NULL, key )
</pre>
This function returns an <tt>atof()</tt> of the value if the
keyword is found, and 0.0 if it is not found.
<p>
<hr>
<h2>get_private_flag</h2>
<pre>
int get_private_flag( const char *list_name,
const char *key );
#define get_config_flag(key) get_private_flag( NULL, key )
</pre>
This function returns an <tt>TRUE</tt> if the value of the
keyword is "TRUE" or "1", and <tt>FALSE</tt> if the the
string is not or if it is not found.
<p>
<hr>
<h2>raw_private_string</h2>
<pre>
int raw_private_string( const char *list_name,
const char *key,
const char *output );
#define raw_config_string(key,val) raw_private_string( NULL, key, val )
</pre>
This function takes three parameters. The first is the
list name, the second is the keyword
to search for, and the third is a return buffer for the value against
that keyword.
<P>
The function returns <tt>1</tt> if the keyword is found, and
<tt>0</tt> if it was not found. In addition, if the keyword was
found the current value will be copied into the output buffer provided.
If the keyword was not found the output buffer will not be modified.
<p>
<hr>
</body>
</html>

62
doc/cfg_set.html Normal file
View file

@ -0,0 +1,62 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Configuration file routines - Setting Values</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Configuration file routines - Setting Values</h1>
<pre>
#include &lt;mplib1/cfg_file.h&gt;
</pre>
<hr>
<h2>set_private_string</h2>
<pre>
int set_private_string( const char *list_name,
const char *key,
const char *val );
#define set_config_string(k,v) set_private_string( NULL, k, v)
</pre>
This funciton sets the value of the named keyword in the named list.
<p>
<hr>
<h2>set_private_int</h2>
<pre>
int set_private_int( const char *list_name,
const char *key,
int newval );
#define set_config_int(k,v) set_private_int( NULL, k, v )
</pre>
This function sets the value of the named keyword in the supplied list
to a string representation of the supplied integer.
<p>
<hr>
<h2>set_private_flag</h2>
<pre>
int set_private_flag( const char *list_name,
const char *key,
int newval );
#define set_config_flag(k,v) set_private_flag( NULL, k, v )
</pre>
This function sets the value of the named keyword in the supplied list
to a boolean string representation of the supplied integer.
<p>
<hr>
<h2>set_private_double</h2>
<pre>
int set_private_double( const char *list_name,
const char *key,
int newval );
#define set_config_double(k,v) set_private_double( NULL, k, v )
</pre>
This function sets the value of the named keyword in the supplied list
to a string representation of the supplied floating point number.
</body>
</html>

146
doc/configsummary.html Normal file
View file

@ -0,0 +1,146 @@
<html>
<head>
<title> Configuration file Basics </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> Configuration file Basics </h1>
Configuration files contain lines which are either comments, or keywords
and their corresponding values.<p>
Comments are assumed to be lines which start with '<tt>#</tt>'.
Keywords are any sequence of alpha-numerics (
plus '<tt>_</tt>', '<tt>.</tt>', '<tt>-</tt>' ) followed by a comma,
space or equals symbol. The remainder of the line (starting from the
next alpha-numeric) is assumed to be the value associated with that
keyword.
<p>
Programs which use the configuration sytem enquire of the value
associated with a keyword. There are then routines which will
interpret the value and return the result.
<p>
A value can be interpreted as:
<ul>
<li><a href="#string">a string</a>
<li><a href="#flag">a flag</a>
<li><a href="#integer">a integer</a>
<li><a href="#floating">a floating point number</a>
<li><a href="#dynamic">a dynamic string</a>
</ul>
The following is a more detailed description of these types.
<hr>
<a name="string"> <h3>A String</h3> </a>
This is simply a string of characters, exactly as stored by
the configuration system. Any structure that is required must
be applied by the calling program.
<p>
An example would be:
<pre>
MY_NAME=Michael Caine
</pre>
<p>
<hr>
<a name="flag"> <h3>A Flag</h3> </a>
The value associated with the keyword is checked and if it
is <tt>TRUE</tt>, or <tt>ON</tt>, or <tt>YES</tt> then the value
1 is returned to the calling program. If the keyword value is not
one of the above, or the keyword does not exist, then the value
0 is returned to the calling program.
<pre>
SCREAM_AT_MONSTER=YES
</pre>
<p>
<hr>
<a name="integer"> <h3>An Integer</h3> </a>
The value associated with the keyword is converted to an integer
which is returned to the calling routine. If the keyword does
not exist, or the value is not numeric, then the value returned to
the calling program is 0.
<pre>
NUMBER_OF_PROGRAMMERS_TO_CHANGE_LIGHT_BULB=5
</pre>
<p>
<hr>
<a name="floating"> <h3>A Floating Point Number</h3> </a>
The value associated with the keyword is converted to an floating point number
which is returned to the calling routine. If the keyword does
not exist, or the value is not numeric, then the value returned to
the calling program is 0.0 .
<pre>
PI=3.14159265
</pre>
<p>
<hr>
<a name="dynamic"> <h3>A Dynamic String</h3> </a>
The value associated with the keyword is evaluated as if it were
a shell variable. For example, if the configuration system contains
<pre>
LOGFILE=$HOME/logfile
</pre>
and the environment has
<pre>
HOME=/home/me
</pre>
the result of evaluating <tt>LOGFILE</tt> would be
<tt>/home/me/logfile</tt>.
<p>
There are a couple of other variations which are associated with
dynamic evaluation.
<ol>
<li>If the value contains a '<tt>%</tt>' character, the following word
is treated as a configuration keyword, and the value associated with the
keyword is used in place of the keyword.
<li>If the original keyword is not found, a <tt>NULL</tt> string is returned,
unless a default string is supplied, in which case that is evaluated as if
it were the value associated with the keyword.
</ol>
To illustrate;<br>
If the configuration file contains:
<pre>
FORENAME=Leonardo
SURNAME=Da Vinci
TITLE=Mr.
FULL_NAME=%TITLE %FORENAME %SURNAME
</pre>
and the environment has
<pre>
HOME=/home/me
</pre>
Then the results of evaluation are:
<table border=1>
<tr> <td> KEYWORD </td><td> DEFAULT </td><td> RESULT
</td></tr>
<tr> <td> FULL_NAME</td><td> NULL</td><td> Mr. Leonardo Da Vinci</td></tr>
<tr> <td> LOGFILE</td><td> NULL</td><td> NULL</td></tr>
<tr> <td> LOGFILE</td><td> $HOME/logfile.%FORENAME</td><td> /home/me/logfile.Leonardo</td></tr>
</table>
<p>
There is are a couple of additional modes which may be used with
evaluated strings.
<p>
The first of these is the ability to bracket the word to be referenced.
This is done by following the <tt>%</tt> or <tt>$</tt> with either
<tt>(</tt> or <tt>{</tt> followed by the keyword, and then a corresponding
closing brace character.
<p>
As an example,
<pre>
FORENAME=Harold
FULL_NAME=%{FORENAME}123456
</pre>
<p>
The second mode available is that of specifying that a word should be
evaluated as a configuration file string (%) and if not present, to be
evaluated as an environment string, or vice-versa. This is done simply
by placing the two meta-characters one after the other in the required order.
i.e.
<pre>
LOG_DIR=/var/tmp
LOG_NAME=$%LOG_DIR/log_name
</pre>
will attempt to use the value of $LOG_DIR, and if not present use that
of %LOG_DIR.
<p><hr><p>
</body>
</html>

75
doc/cpustopwatch.html Normal file
View file

@ -0,0 +1,75 @@
<HTML>
<HEAD>
<TITLE> stopwatch - system times</TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> stopwatch - system times </h1>
<pre>
#include &lt;mplib1/stopwatch.h&gt;
struct cpu_stopwatch
{
struct stopwatch u_timing;
struct stopwatch s_timing;
char elps_str[100];
};
int init_cpu_stopwatch( struct cpu_stopwatch *cpu_p );
int start_cpu_stopwatch( struct cpu_stopwatch *cpu_p );
int stop_cpu_stopwatch( struct cpu_stopwatch *cpu_p );
int accrete_cpu_stopwatch( struct cpu_stopwatch *cpu_p_into,
struct cpu_stopwatch *cpu_p_from );
char *display_cpu_stopwatch( struct cpu_stopwatch *cpu_p, int mode );
</pre>
This set of routines provides a mechanism for measuring the user cpu time
and system cpu time of
an enclosed block of code. They currently give a displayed accuracy
to hundredths of a second. The cpu_stopwatch structure used contains a
pair of
<a href="stopwatch.html"> stopwatch </a>
entries which record the user and system timings and cumulatives,
and a string buffer for generating
ASCII representations of the cumulative data.
<p>
<i>init_cpu_stopwatch()</i> initialises a cpu_stopwatch structure, resetting
the user and system cumulative values, start values and the string buffer.
<P>
<i>start_cpu_stopwatch()</i> sets the start times of cpu_stopwatch user
and system structure.
<p>
<i>stop_cpu_stopwatch()</i> determines the difference between the current
times and those held in the start times, and adds them to the cumulative
times.
<p>
<i>accrete_cpu_stopwatch()</i> adds the cumulative times in the
<i>cpu_p_from</i>
structure into the cumulative times in the <i>cpu_p_into</i> structure.
<p>
<i>display_cpu_stopwatch()</i> returns a pointer to an ascii representation
of the cumulative times. Currently the only mode that is accepted is <b>0</b>
which gives a string like
<pre>
USR: 027.55 seconds CPU: 001.38 seconds
</pre>
or
<pre>
USR: 001529.04 seconds CPU: 001022.27 seconds
</pre>
depending on whether the number of seconds is greater than 999.
<p>
These routines behave in the same manner as the real-time elapsed stopwatch
routines.
<P>
<hr>
<p>
</BODY>
</HTML>

163
doc/daemon.html Normal file
View file

@ -0,0 +1,163 @@
<html>
<head>
<title> daemon.h - Daemon Process Utilities </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> daemon.h - Daemon Process Utilities </h1>
The daemon process utilities are designed to make it easy to create
a standard daemon process which interacts with signals and the standard
shared memory segment. Processes that utilise these routines properly
are also compatible with the
<a href="../util_doc/watchdog/watchdog.html"> watchdog </a>
utility that comes with the library.
<p>
<hr>
<h2> Initialising your daemon </h2>
The first action a daemon would perform is to disconnect from its
parent and controlling terminal and standard files.
<pre>
pid_t leavehome( void );
</pre>
This function performs the following sequence of actions.
<ol>
<li>Closes the current <b>stdin</b>, <b>stdout</b> &amp; <b>stderr</b>
files and re-opens them to configuration defined locations. This is done
via a call to
<a href="#restart_files"><i>restart_files</i></a>.
<li>performs a <i>fork</i> to disconnect from the parent.
<li>performs a <i>setsid</i> to disconnect from the process group.
</ol>
<p>
<hr>
<h2> <a name="restart_files"> restart_files </a> </h2>
<pre>
int restart_files( void );
int restart_these_files( const char *in_name,
const char *out_name,
const char *err_name );
</pre>
This pair of functions performs an <i>freopen</i> on the standard
I/O streams <b>stdin</b>, <b>stdout</b> &amp; <b>stderr</b>.
<p>
The <i>restart_files</i> function gets the filenames for the streams
by evaluating the configuration file parameters
<a href="../utildoc/common/STDIN.html"><b>STDIN</b></a>,
<a href="../utildoc/common/STDOUT.html"><b>STDOUT</b></a> &amp;
<a href="../utildoc/common/STDERR.html"><b>STDERR</b></a>.
If the evaluations produce
NULL or empty string then the default value of <i>/dev/null</i> is
used.
<p>
The <i>restart_these_files</i> function behaves as above with the
exception that the file names are explicitly provided. As with
<i>restart_files</i> should any parameter be NULL or an empty string
then the value <i>/dev/null</i> is used.
<p>
<hr>
<h2> Signal Handling </h2>
Daemon processes normally arrange for various signals to be trapped.
The following signall routines are provided as a basis.
<pre>
int init_signalling( void );
int check_signalling( void );
int allow_sysint( void );
int deny_sysint( void );
</pre>
The <i>init_signalling</i> routine sets up a standard handler for
the following signals
<ul>
<li>SIGINT
<li>SIGTERM
<li>SIGUSR1
<li>SIGUSR2
<li>SIGHUP
</ul>
The signal handler copies the value of signal received into a local
variable, and will usually re-start any system cal that was in progress
at the time.
<p>
The <i>check_signalling</i> routine returns the value of any stored
signal received. The value is also cleared.
<p>
The <i>allow_sysint</i> routine saves a copy of the signal handler
state for the above listed signals and puts in place copies with the
<b>SA_RESTART</b> flag cleared. This function only has effect once
unless the <i>deny_sysint</i> function is called.
<p>
The <i>deny_sysint</i> routine takes the previously saved state of the
signal handlers (saved via a call to <i>allow_sysint</i>) and restores
them.
<p>
<hr>
<h2> Waiting For An Event </h2>
<pre>
int mp_daemon_sleep( int how_long );
</pre>
This function provides the facility to sleep for the supplied
number of seconds, but also to be woken if an interrupt occurs, or
if a process pipe exists when a character is received. It uses a
<i>select</i> call along with <i>allow_sysint</i> &amp; <i>deny_sysint</i>.
<p>
<hr>
<h2> Simplifying The Main Loop </h2>
<pre>
int mp_daemon_loop( int(*poll_func)(int),
int(*u1_func)(int),
int(*u2_func)(int),
int(*int_func)(int),
int(*term_func)(int),
int flags );
</pre>
<This function simplifies the main loop of a daemon by performing
a number of usual tasks. It is a looping function which
only exits if one of the supplied functions returns a non-zero value.
<p>
The sequence it performs each time round its loop is as follows;
<ol>
<li>Get the current value of
<a href="../utildoc/common/POLL_PERIOD.html">POLL_PERIOD</a>
from the configuration file.
<li>Call the <i>check_signalling</i> function.
<ol>
<li>If the value is <b>SIGHUP</b> then the
<i>restart_files</i> routine is called. The value 0
is passed to the next major step.
<li> If the value returned is one of <b>SIGINT</b>, <b>SIGTERM</b>,
<b>SIGUSR1</b> or <b>SIGUSR2</b> and the corresponding
function parameter is non-NULL then the function is called
with the signal value as the sole parameter. The return value
of the function is saved for the next major step.
<li> If the value is one of <b>SIGINT</b>, <b>SIGTERM</b>,
but the corresponding function pointer is NULL then
the value is passed to the next major step.
<li> If the value is one of <b>SIGUSR1</b> or <b>SIGUSR2</b>
but the corresponding function pointer is NULL then
0 is passed to the next major step.
<li> If the value is zero or the signal is not one of the ones
mentioned above the poll routine is called with 0
as its parameter and the
return value saved for the next major step.
</ol>
<li>If the result of the <i>check_signalling</i> stage is zero, then the
<i>mp_daemon_sleep</i> routine is called with the value of the
<b>POLL_PERIOD</b>.
<li>If the result is non-zero the routine exits.
</ol>
<p>
The <b>poll_func</b> parameter must be a non-NULL pointer to a function
taking an integer parameter, and returning an integer.
<p>
The next four parameters, <b>u1_func</b>, <b>u2_func</b>,
<b>int_func</b> &amp; <b>term_func</b> are similar function pointers
but NULL may be supplied.
<p>
The <b>flags</b> parameter should be 0.
<p>
Note that because the functions are passed the value of the signal
or 0 it is possible to use the same function for all of the parameters.
<p>
</body>
</html>

27
doc/dl_add.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Double-Linked Lists - Occasional Add Functions</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Double-Linked Lists - Occasional Add Functions</h1>
<pre>
#include &lt;mplib1/dl_list.h&gt;
Node_t *Add_Node_After( Node_t *node1, Node_t *node2 );
Node_t *Add_Node_Before( Node_t *node1, Node_t *node2 );
</pre>
<tt>Add_Node_After</tt> adds <tt>node2</tt> after <tt>node1</tt>
in whatever list <tt>node1</tt> is.
<P>
<tt>Add_Node_Before</tt> adds <tt>node2</tt> before <tt>node1</tt>
in whatever list <tt>node1</tt> is.
<p>
Both functions return pointer to <tt>node2</tt>.
<p>
<hr>
<p>
</body>
</html>

27
doc/dl_find.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Double-Linked Lists - Occasional Find Function</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Double-Linked Lists - Occasional Find Function</h1>
<pre>
#include &lt;mplib1/dl_list.h&gt;
Node_t *Find_Node_By_Item( List_t *list, const void *item );
</pre>
In certain conditions it may well be that the the item refered to
in a list does not actually know which node references it in the list.
In this case it is possible to find the relevant node by calling this
function. It walk the list from the head until it reaches the first
node that points to the item. The node pointer is returned, or
<tt>NULL</tt> on failure.
<p>
In common with the other <tt>Find_</tt> functions, any found node
is not removed from the list.
<p>
<hr>
<p>
</body>
</html>

250
doc/dl_list.html Normal file
View file

@ -0,0 +1,250 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Double-Linked Lists </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Double-Linked Lists </h1>
<pre>
#include &lt;mplib1/dl_list.h&gt;
struct Node_struct
{
struct Node_struct *ln_Succ;
struct Node_struct *ln_Pred;
const char *ln_Name;
const void *ln_Item;
struct List_struct *ln_List;
};
struct List_struct
{
struct Node_struct ln_Head;
struct Node_struct ln_Tail;
int ln_Flags;
};
typedef struct Node_struct Node_t;
typedef struct List_struct List_t;
</pre>
The dl_list routines are a full suite of double-linked list functions.
<P>
Instead of the normal rigmarole of having to produce a set of
routines for each type of data
structure these routines provide a standard list header structure
and a node structure which is attached to the list. Nodes have two
properties which are used by the programmer, an item pointer and a
name pointer.
<p>
<hr>
<h3>Initialisation Routines</h3>
The <tt>List</tt> and <tt>Node</tt> must be initialised before they
can be used.
<pre>
List_t *Init_List ( List_t *list, int flags );
</pre>
This function initialises a list structure for subsequent use. The
flags parameter should be <tt>0</tt> or <tt>LN_IGNORECASE</tt>. This
affects whether the searches for items by name should be case-independant
or not.
<P>
<pre>
Node_t *Init_Node( Node_t *node,
const char *name,
const void *item );
</pre>
This function initialises a node structure for use in a list.
The name parameter should be either a name for search purposes
or <tt>NULL</tt>. The item pointer is normally the pointer to the
structure containing the user data and the node.
<p>
<hr>
<h3> Add functions </h3>
The two main add functions are as follows.
<pre>
Node_t *Add_Head( List_t *list, Node_t *node );
Node_t *Add_Tail( List_t *list, Node_t *node );
</pre>
These functions add the supplied node to the head and tail of the
supplied list respectively.
<P>
There are other add functions but they are for more complex situations
and would not normally be used. For details click
<a href="dl_add.html">here.</a>
<p>
<hr>
<h3>Remove Functions</h3>
There are three remove functions.
<pre>
void *Remove_Head_Item( List_t *list );
void *Remove_Tail_Item( List_t *list );
Node_t *Remove_Node( Node_t *node1 );
</pre>
The first two are related to the add functions above, except that
they return a pointer to the item as stored in the node structure.
<p>
The <tt>Remove_Node</tt> function is used to remove a given node from
a list.
<p>
As with the add functions there are some primitives that are not
commonly used. For details, click
<a href="dl_rem.html">here.</a>
<p>
<hr>
<h3>Find Functions</h3>
<pre>
void *Find_Item_By_Name( List_t *list, const char *name );
void *Find_Next_Item_By_Name( Node_t *node, const char *name );
</pre>
<tt>Find_Item_By_Name</tt> searchs the given list for an item with
the supplied name (matching according to the case flag set when
initialising the list). If it find it the item pointer is returned,
and if not found <tt>NULL</tt> is returned.
<p>
The <Find_Next_Item_By_Name</tt> function does a similar search to
that performed by <tt>Find_Item_By_Name</tt> except that it
starts from a given node. This would typically be the node
of an item previsouly found using one of the above functions.
The search actually commences from the node following the one
supplied.
<p>
Found items are not removed from the list.
<p>
Yet again, there is a a function that is not commonly used.
For details, click
<a href="dl_find.html">here.</a>
<p>
<hr>
<h3>Walk Functions</h3>
<pre>
typedef void (* Walk_List_t)( void *, void *);
typedef int (* Walk_List2_t)( void *, void *);
typedef int (* Walk_List_Name_t)( void *, void *);
typedef int (* Walk_List_Node_t)( Node_t *, void *);
int Walk_List( List_t *l_ptr,
Walk_List_t disp,
void *param );
int Walk_List2( List_t *l_ptr,
Walk_List2_t disp,
void *param );
int Walk_List_Name( List_t *l_ptr,
const char *name,
Walk_List_Name_t disp,
void *param );
int Walk_List_By_Node( List_t *l_ptr,
Walk_List_Node_t disp,
void *param );
</pre>
These functions walk the list provided and call the supplied function
with a pointer to each suitable item together with the user supplied
paramter.
<p>
The <tt>Walk_List</tt> function calls the <tt>disp</tt> routine
for every item in the list.
<p>
The <tt>Walk_List</tt> function calls the <tt>disp</tt> routine
for every item in the list whilst the <tt>disp</tt> routine returns
<tt>0</tt>. Should the <tt>disp</tt> routine return non-zero the
traversal of the list finishes and the non-zero value is returned
to the caller.
<p>
The <tt>Walk_List_Name</tt> function is similar to the <tt>Walk_List</tt>
routine except that the <tt>disp</tt> routine is only called for items
whose name matches that supplied (given the list's case matching rule).
<p>
The <tt>Walk_List_By_Node</tt> function is similar to the <tt>Walk_List</tt>
routine except that the <tt>disp</tt> routine is passed the Node pointer
of each member rather than the item pointer.
<p>
<b>Note</b>
In all the above <tt>Walk_</tt> routines.
<dl>
<dt><dd>
The <tt>Walk_</tt> routines do not remove any items from the list.
<P>
<dt><dd>
Whilst within the <tt>disp</tt> function the only possible
manipulation of the list being walked which is permitted is
to perform <tt>Remove_Node</tt> for the current item.
</dl>
<p>
<hr>
<h3>Sort Functions</h3>
<pre>
typedef int (* dl_sort_i_t)( const void *, const void *);
int dl_sort_i( List_t *sort_list, dl_sort_i_t compar );
int dl_sort_n( List_t *sort_list );
</pre>
These functions sort the supplied lists using either a supplied
comparison function or by name (taking into account the list's
matching rule). The sort algorithm is actually
<a rhef="lmsort.html">lmsort</a> but adapted for use with these
double linked lists.
<p>
<hr>
<h3>Miscelleaneous Functions</h3>
<pre>
int Transfer_Lists( List_t *from_list, List_t *to_list );
</pre>
This function simply transfers all items on the <tt>from_list</tt> onto the
<tt>to_list</tt>. It returns the number of items transferred.
<p>
<pre>
int Any_In_List( List_t *list );
</pre>
This function returns non-zero if there are any items in the
list or <tt>0</tt> if the list is empty.
<p>
<pre>
void dl_Free_List( List_t *list, int flags );
void dl_Free_Node( Node_t *node, int flags );
</pre>
where the flags are a bit-wise or of the following defines
<pre>
DL_REMOVE_NODES
DL_FREE_NODES
DL_FREE_ITEMS
DL_FREE_NAMES
</pre>
The <i>dl_Free_List</i> function provides a mechanism to free up the
various elements of items on a list. It is, not surprisingly, implemented
as a call to <i>Walk_List</i> with <i>dl_Free_Node</i> as the supplied
function.
<p>
The <i>dl_Free_Node</i> function takes a pointer to a node and a
set of flags. It then performs the following operations
<ol>
<li>If <b>DL_REMOVE_NODES</b> or <b>DL_FREE_NODES</b> is set the
node is removed from the list.
<li>If <b>DL_FREE_NAMES</b> is set any name pointed to by the
node is freed and the pointer cleared.
<li>If <b>DL_FREE_ITEMS</b> is set any item pointed to by the
node is freed and the pointer cleared.
<li>If <b>DL_FREE_NODES</b> is set the node is freed.
</ol>
<p>
<pre>
int dl_Free_List_Contents( List_t *fl_ptr );
</pre>
This deprecated function walks the given list, removing each Node in turn
and calling <tt>free()</tt> for each item pointer.
<p>
<hr>
<p>
</body>
</html>

382
doc/dl_lru.html Normal file
View file

@ -0,0 +1,382 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title> LRU Cache Routines </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> LRU Cache Routines </h1>
<pre>
#include &lt;mplib1/dl_lru.h&gt;
</pre>
The cache routines consist of six functions which provide the following functions
<dl>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
initialisation
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
setup
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
search
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
add
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
notify
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
report
</dl>
<p>
The normal program use would be to call the initialisation routine,
then to call the setup routine to tell it what the name of the list
will be, what fields it contains, and how many entries to have.
<p>
Then there would be multiple calls to the search routine, and probably
a number of calls to the add routine when the search fails and the data
was found by another method, and optionally a call to the notify routine
if the data was not found externally.
<p>
After the program has performed its main job, the report routine can
be called to give statistics on adds, hits & misses.
<p>
This can be best illustrated by the following pseudo-code.
<pre>
inititalise the cache routines
create the list required
while user gives input
search for required item in cache
if not found in cache
find item in database
if found in database
add to cache
print details
otherwise
notify cache
inform user
otherwise
print details (as returned by cache)
end while
print cache statistics
</pre>
<p>
In fact slightly more variations are possible, but we shall
examine these after looking at the actual functions in some
detail.
<p>
<hr>
<h2>Cache_Init</h2>
<pre>
int Cache_Init( int default_flags );
</pre>
This function should be called once at startup. The
value supplied will be used to provide the defaults
flags for Create_Cache_List where not included.
<p>
If any value other than CACHE_USE_DEFAULT is supplied
it should have only one bit set per mask group. For
example, in the cache mode group either CACHE_CACHE_ON
or CACHE_STAT_ONLY should be supplied.
<p>
The groups and their members are:
<pre>
Mode Group Cache or statistics
CACHE_CACHE_ON Cache items
CACHE_STAT_ONLY Statistics only
Case Group Should key values distinguish
between upper and lower case.
CACHE_IGNORE_CASE Ignore case in key values
CACHE_CHECK_CASE Check case in key values
Allocate Group Should the list be pre-allocated.
CACHE_PRE_ALLOCATE Preallocate space for items
CACHE_DEMAND_ALLOC Allocate space for items on demand
Miss Group Should complete miss value be stored.
CACHE_MISS_IGNORE Ignore complete miss finds
CACHE_MISS_CACHE Cache and return complete misses
on a find
</pre>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Create_Cache_List</h2>
<pre>
int Create_Cache_List( const char *list_name,
int max_items,
int list_flags,
int key_size,
const char *format_string,
const char *field_names );
</pre>
The list_name is a unique string to identify
which chain to put the data on.
<p>
The cache_max size specifies the maximum number of
items that will be created on the list before re-use occurs.
If this is 0 then the list will expand until it either
feels like it, or is unable to.
<p>
The list_flags specify how the cache should operate. If
the supplied value does not have a bit set in a particular
mask, the value will default to that provided to Cache_Init.
<p>
The key_size parameter if non-zero specifies the maximum
length of the key. This is used when pre-allocating
list items, and also allows for faster re-use when the
cache is full.
<p>
The format_string list is a string, similar to that used as
a format string in printf, which specifies the field types.
The current formats supported are string, character, integer,
double and varchar.
<pre>
%d decimal integer
%x hexadecimal integer
%c character
%f double
%s string
%S varchar
</pre>
The string and varchar types may be preceded by a width
specifier which if not present will default to 40.
<p>
The field_names parameter is a comma seperated list of
fields, which will be used to identify the fields in
the field type list.
<pre>
e.g. "stn_id,stn_name,gwy_live_stn"
</pre>
This function should be called once for each type of data set
that requires caching.
<p>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Add_Cache_Item</h2>
<pre>
int Add_Cache_Item( char *list_name,
char *list_key,
... );
</pre>
This function should be called to add a single set of data
items to a given cache list.
<p>
The list_name is the same string as specified in the
Create_Cache_List call.
<p>
The list_key value is a unique string to identify this
item in the list. It can usually be produced by performing
an sprintf of the actual key fields.
<p>
The list key value is then followed by a list of pointers
to the actual data fields. These data pointers should be
in exactly the same order as the fields specified in the
Create_Cache_List call, and should have the same number
of fields.
<p>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Find_Cache_Item</h2>
<pre>
int Find_Cache_Item( const char *list_name,
const char *list_key,
const char *field_list,
... );
</pre>
This function should be called to search (and return data if
found) a list for a given key value.
<p>
The list_name is the same string as specified in the
Create_Cache_List call.
<p>
The list_key value is the unique string to identify a
given item, generated in the same manner as would be done
by the Add_Cache_Item call.
<p>
The field_list, is a comma separated list of fields to be
returned. This list may contain any subset of the fields
specified in field_names in the Create_Cache_List call.
<p>
The field list is followed by a list of pointers to the
fields to filled in.
<p>
Return:
<pre>
CACHE_COMPLETE_MISS if not in cache and not in
external data source
CACHE_MISSED if not in the cache
CACHE_FOUND_ITEM if the item was found :-)
CACHE_FOUND_MANY if more than one item with
this key value was found.
</pre>
These values are in ascending sequence so that the return
check can be coded as simply or a complex as desired.
<p>
<hr>
<h2>Cache_Complete_Miss</h2>
<pre>
int Cache_Complete_Miss( const char *list_name,
const char *list_key );
</pre>
This function should be called when a given value being
searched for, is not found either in the cache list
(Find_Cache_Item) or in the external data source.
<p>
The list_name is the same string as specified in the
Create_Cache_List call.
<p>
The list key value is the unique string to identify a given
item, generated in the same manner as would be done by the
Add_Cache_Item call.
<p>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Cache_Flush</h2>
<pre>
int Cache_Flush( const char *list_name );
</pre>
This function causes all stored values, together with all
complete miss values to be freed.
<p>
The list_name is the same string as specified in the
Create_Cache_List call.
<p>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Cache_Stats</h2>
<pre>
int Cache_Stats( FILE *file_handle,
const char *list_name,
int contents );
</pre>
This function provides details of the data sizes,
and cache hit statistics.
<p>
The file_handle is that of the stream where the
report output is are desired.
<p>
The list_name is that for which statistics are desired,
or NULL if statistics are required for all lists.
<p>
Return: 0 on failure, 1 on success.
<p>
<hr>
<h2>Notes</h2>
The way the routines are designed, the only return value that must be
checked is that from Find_Cache_Item. If Cache_Init or Create_Cache_List
failed the only consequence of any given call to Find_Cache_Item will
be that CACHE_MISSED will always be returned.
<p>
The return codes from Find_Cache_Item are so arranged in ascending order
because it makes it possible to code the subsequent checking in a variety
of ways, but allowing simple code to work as well. For example, the
relevant section of the pseudo-code at the start of the document would
normally be coded as follows;
<pre>
rv=Find_Cache_Item( list_name, key_value, field_list, &amp;rf1, &amp;rf2 );
if ( rv <= CACHE_MISSED )
{
rv = Database_Check( key_value, &amp;rf1, &amp;rf2 );
if ( rv == FOUND )
{
Add_Cache_Item( list_name, key_value, &amp;rf1, &amp;rf2 );
/* display details .... */
}else
{
Cache_Complete_Miss( list_name, key_value );
/* inform user of error ... */
}
}
else
{
/* display details ... */
}
</pre>
But consider the case where the key value is one that will not be found
either in the cache or the database, and that this value has been checked
before. We would end up checking the cache and the database to gain the
same result, whereas if the cache knows something about complete failures
we can recode the above as follows;
<pre>
rv=Find_Cache_Item( list_name, key_value, field_list, &amp;rf1, &amp;rf2 );
if ( rv <= CACHE_COMPLETE_MISS )
{
Cache_Complete_Miss( list_name, key_value );
/* inform user of error ... */
}
else if ( rv <= CACHE_MISSED )
{
rv = Database_Check( key_value, &amp;rf1, &amp;rf2 );
if ( rv == FOUND )
{
Add_Cache_Item( list_name, key_value, &amp;rf1, &amp;rf2 );
/* display details .... */
}else
{
Cache_Complete_Miss( list_name, key_value );
/* inform user of error ... */
}
}
else
{
/* display details ... */
}
</pre>
The only item that should seem strange is the call to Cache_Complete_Miss
when Find_Cache_Item has just returned CACHE_COMPLETE_MISS. This is
because there may be some other action required, or this code may be
like the first example, in which case a complete miss would be recorded.
Let's just call it consistency.
<p>
Because of the nature of caching, and the design of the code it should not
be assumed that, just because an item has just been added that it will be
found on an immediately following search. The following example contains
this bad assumption.
<pre>
Add_Cache_Item( list_name, key_value, &amp;rf1, &amp;rf2 );
/* fiddle with values of rf1 & rf2 for some reason */
Find_Cache_Item( list_name, key_value, field_list, &amp;rf1, &amp;rf2 );
/* use rf1, rf2, WRONG !!! */
</pre>
The Add_Cache_Item call may have failed, the list may not exist, or it may
be running in statistics only mode.
<p>
<hr>
<p>
<h2>Additional Notes</h2>
Note:
<ol>
<li> Currently the cache code does not support multiple items for
a single key value. The overheads of providing this are still
under consideration.
</ol>
<p>
<hr>
<h3> "OK. So I'll go with the sales pitch. But how do I actually use the thing ?"</h3>
<p>
Your code should include dl_lru.h, this file contains the function
definitions for the cache routines, along with all the flag definitions.
<p><hr><p>
</body>
</html>

23
doc/dl_rem.html Normal file
View file

@ -0,0 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Double-Linked Lists - Occasional Remove Functions</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Double-Linked Lists - Occasional Remove Functions</h1>
<pre>
#include &lt;mplib1/dl_list.h&gt;
Node_t *Remove_Head( List_t *list );
Node_t *Remove_Tail( List_t *list );
</pre>
These functions remove the head and tail node from the supplied list
and return a pointer to that node. If there are no items on the list
the <tt>NULL</tt> is returned.
<p>
<hr>
<p>
</body>
</html>

45
doc/do_hex_dump.html Normal file
View file

@ -0,0 +1,45 @@
<html>
<head>
<title> do_hex_dump() </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> do_hex_dump() </h1>
<pre>
#include &lt;mplib1/dumphex.h&gt;
int do_hex_dump( FILE *fp, off_t curoff,
const char *where, int how_much );
</pre>
This function outputs to the requested file a given block of memory
in hexadecimal format, with and valid ASCII
characters also displayed.
<P>
The memory to be display is pointed to by the <tt>where</tt> pointer,
but the 'address' displayed will be based on the <tt>curoff</tt> parameter.
This is of most use when display the details of a shared memory block
like the
<a href="sodb.html"> SODB </a> code.
<P>
So, if there is a block of shared memory which starts at some address
pointed to by <tt>memblk</tt> and we want to display the contents
of some portion of the block.
<pre>
do_hex_dump( stdout, 0x708, memblk+0x708, 0x70 );
</pre>
The output would look like
<pre>
00000708 .. .. .. .. .. .. .. .. 00 00 07 54 00 00 06 c8 ' T '
00000710 00 00 07 24 00 00 07 04 00 00 06 c4 00 00 00 00 ' $ '
00000720 00 00 00 00 53 4f 44 42 20 42 61 73 65 00 00 00 ' SODB Base '
00000730 00 00 00 00 00 00 00 00 00 00 07 38 00 1e 7d 48 ' 8 }H'
00000740 00 00 0a b8 00 00 07 80 00 00 00 00 00 00 00 00 ' '
00000750 00 00 00 00 00 00 07 54 00 00 06 e4 00 00 07 04 ' T '
00000760 00 00 07 74 00 00 07 54 00 00 06 c4 00 00 00 00 ' t T '
00000770 00 00 07 38 73 68 61 6c .. .. .. .. .. .. .. .. ' 8shal '
</pre>
<p>
<hr>
<p>
</body>
</html>

22
doc/dumphex.html Normal file
View file

@ -0,0 +1,22 @@
<HTML>
<HEAD>
<TITLE> #include &lt;dumphex.h&gt; </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> #include &lt;mplib1/dumphex.h&gt; </h1>
This pair of functions provide the facility to dump the contents
of a block of memory in hexadecimal format, with printable ASCII
characters also displayed.
<p>
<dl>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="do_hex_dump.html"> do_hex_dump(); </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="hex_dump.html"> hex_dump(); </a>
</dl>
<P>
<hr>
<p>
</BODY>
</HTML>

68
doc/fgetline.html Normal file
View file

@ -0,0 +1,68 @@
<HTML>
<HEAD>
<TITLE> fgetline() </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> Line Get Functions </h1>
There are a pair of functions which get a line of data from a file.
There is a base fetch routine which knows nothing about the data
other than is a line worth. The other repeatedly reads lines until
it reaches one which does not have the standard
<a href="cfg_file.html">configuration file</a> comment characters
at the start.
<p>
<hr>
<h2> fgetline() </h2>
<pre>
#include &lt;mplib1/fgetline.h&gt;
int fgetline( FILE *fh, char *line_buf, int line_len );
</pre>
This function provides a simple way of reading a line from a file
into a buffer. Up to <tt>line_len-1</tt> characters will be read.
The routine strips any trailing newline characters from the buffer.
<p>
The function returns <tt>0</tt> on success and <tt>-1</tt> on failure.
<p>
A typical use would be look like.
<pre>
char tbuf[T_BUF_LEN];
FILE *fh;
....
while(fgetline(fh,tbuf,T_BUF_LEN)==0)
process_line( tbuf );
</pre>
<P>
<hr>
<h2> fgetline2() </h2>
<pre>
#include &lt;mplib1/fgetline.h&gt;
int fgetline2( FILE *fh, char *line_buf, int line_len );
</pre>
This function provides a simple way of reading a line from a file
into a buffer. Up to <tt>line_len-1</tt> characters will be read.
The routine strips any trailing newline characters from the buffer.
It also skips any lines which have '#' as their first non-blank character.
<p>
The function returns <tt>0</tt> on success and <tt>-1</tt> on failure.
<p>
A typical use would be look like.
<pre>
char tbuf[T_BUF_LEN];
FILE *fh;
....
while(fgetline2(fh,tbuf,T_BUF_LEN)==0)
process_line( tbuf );
</pre>
<P>
<hr>
<p>
</BODY>
</HTML>

103
doc/fprintfile.html Normal file
View file

@ -0,0 +1,103 @@
<html>
<head>
<title> fprintfile </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> fprintfile </h1>
<pre>
#include &lt;mplib1/fprintfile.h&gt;
</pre>
This file contains a number of function definitions,
the most popular of which is
<pre>
int fprintfile( FILE *fp, char *format, ... );
</pre>
The fprintfile function provides an extended version of <tt>fprintf</tt>
which prepends the resultant string with a timestamped log string
generated using
<a href="#make_log_str">make_log_str()</a>.
<p>
An example of the output of this routine would be
<pre>
fprintfile( stderr,"get_stn_name: &lt;%s&gt; failed. Error %d\n",
stn_name, SQLCODE );
</pre>
produces
<pre>
1996-12-31 13:45:56.78Z 22301 myname get_stn_name: &lt;ZZZC69&gt; failed. Error 3003
</pre>
<P>
<hr>
<a name="make_log_str">
<h1> make_log_str </h1></a>
<pre>
char *make_log_str( char *buffer );
</pre>
The make_log_str function generates a string suitable for placing in
a log file or outputting to a user.
<P>
The string consists of a high-resolution timestamp created by
<a href="#make_timestamp_str">make_timestamp_str()</a>,
the process id, and the process owner.
<p>
The buffer parameter specifies a data area in which to create this string.
If it is provided it should be at least 40 characters + the maximum
length of the user name. If the buffer parameter is NULL then the
routine uses an internal static buffer, the resultant
value should be used immediately or copied.
<P>
An example of the string created by this routine is
<pre>
"1996-12-31 13:45:56.78Z 22301 myname"
</pre>
<P>
<hr>
<a name="make_timestamp_str">
<h1> make_timestamp_str </h1></a>
<pre>
char * make_timestamp_str( char *buffer );
</pre>
The make_timestamp_str function generates a timestamp string
formatted to ISO 8601 / EN28601.
<p>
The timestamp is in UTC and
is formed using <tt>strftime()</tt> and
then adding hundredths of seconds and timezone offset.
<P>
The buffer parameter specifies a data area in which to create this string.
If it is provided it should be at least 24 characters long.
If the buffer parameter is NULL then the
routine uses an internal static buffer, the resultant
value should be used immediately or copied.
An example of the completed string is;
<pre>
"1996-12-31 13:45:56.78Z"
</pre>
<p>
<hr>
<a name="get_my_uname">
<h1>get_my_uname</h1></a>
<pre>
char *get_my_uname( void );
</pre>
The get_my_uname function returns a pointer to an buffer containing
the name of the user. This name is the one provided in the passwd
structure returned from <tt>getpwuid()</tt> library call.
<p>
<hr>
<h4> Revision note. </h4>
As of library version 2.5.0 the <tt>make_timestamp_str</tt> function
produces a string conforming to ISO 8601 / EN28601. Previously the
format was YYYY/MM/DD HH:MM:SS:DD which was a little confusing. The
new string is one character longer, but does not cause any buffer to
be overwritten if they were specified as being at least 24 characters
long.
</body>
</html>

BIN
doc/gpin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

28
doc/hex_dump.html Normal file
View file

@ -0,0 +1,28 @@
<HTML>
<HEAD>
<TITLE> hex_dump() </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> hex_dump() </h1>
<pre>
#include &lt;mplib1/dumphex.h&gt;
int hexdump( FILE *fp, char *where, int how_much );
</pre>
This function outputs to the requested file a given block of memory
in hexadecimal format, with any valid ASCII
characters also displayed.
<P>
The memory to be display is pointed to by the <tt>where</tt> pointer,
and the quantity of memory to be display is given by the
<tt>how_much</tt> parameter.
<P>
This function is actually just a wrapper for
<a href="do_hex_dump.html"> do_hex_dump() </a>
where the <tt>curoff</tt> parameter is zero.
<p>
<hr>
<p>
</BODY>
</HTML>

82
doc/index.html Normal file
View file

@ -0,0 +1,82 @@
<HTML>
<HEAD>
<TITLE> Utility Library - mplib1 </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> Utility Library - mplib1 </h1>
This library provides a range of routines covering the following
general areas.
<dl>
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
Private double-linked lists.
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
Simple configuration file access.
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
Optimal List-Merge sort.
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
Dynamically configurable memory display routines.
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
String parsing.
<dt><dd><img src="ypin.gif" align=bottom width=21 height=21>
Shared Memory Access/Manipulation/Management.
</dl>
<p>
<hr>
<h2> Routine Documentation </h2>
The various functions are now dealt with based on the particular
include file which contains the function definitions.
<dl>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="stricmp.html"> #include &lt;mplib1/stricmp.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="mpstrtok.html"> #include &lt;mplib1/mpstrtok.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="fgetline.html"> #include &lt;mplib1/fgetline.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="fprintfile.html"> #include &lt;mplib1/fprintfile.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="dumphex.html"> #include &lt;mplib1/dumphex.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="lock_file.html"> #include &lt;mplib1/lock_file.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="lmsort.html"> #include &lt;mplib1/lmsort.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="cfg_file.html"> #include &lt;mplib1/cfg_file.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="dl_list.html"> #include &lt;mplib1/dl_list.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="pid_check.html"> #include &lt;mplib1/pid_check.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="dl_lru.html"> #include &lt;mplib1/dl_lru.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="vre.html"> #include &lt;mplib1/vre.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="min_list.html"> #include &lt;mplib1/min_list.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="match_tok.html"> #include &lt;mplib1/match_tok.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="gdbm_util.html"> #include &lt;mplib1/gdbm_util.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="stopwatch.html"> #include &lt;mplib1/stopwatch.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="pid_check.html"> #include &lt;mplib1/pid_check.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="build_argv.html"> #include &lt;mplib1/build_argv.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="daemon.html"> #include &lt;mplib1/daemon.h&gt; </a>
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
<a href="bpo_intro.html"> Shared Memory Routines </a>
</dl>
<p>
<hr>
<p>
</body>
</html>

113
doc/lmsort.html Normal file
View file

@ -0,0 +1,113 @@
<HTML>
<HEAD>
<TITLE> lmsort </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> lmsort </h1>
<pre>
#include &lt;mplib1/lmsort.h&gt;
struct lmsortp
{
struct lmsortp *next;
void *dp;
};
typedef int lmsortp_t (const void *, const void *);
struct lmsortp *lmsort( struct lmsortp * start, lmsortp_t compar );
struct lmsortp *
lmsort_init( void* base, size_t nel, size_t width, struct lmsortp *dp );
void
lmsort_end( struct lmsortp *dp );
</pre>
This function provides an optimised list-merge sort which is capable
(as implemented) of sorting up to 33,554,430 records. Tests have
indicated that it is probabaly the fastest general purpose sort available.
<p>
This is a publically available routine, the documentation from which follows.
<p>
<h2 align=center>
Optimal list-merge sorting algorithm with exponential merge schedule.
</h2>
<h2 align=center>
Software Development International, Winter 1991.
</h2>
<h2 align=center>
This implementation by Jeremy Harris jgh@imptld.com
</h2>
<h2 align=center>
Adapted into toolkit by Martin Poole Martin.Poole@ukuug.org
</h2>
<h3> How to use these routines.</h3>
Consider how an array of elements would typically be sorted using qsort()
<pre>
struct some_struct them[ARRAY_SIZE];
int t;
qsort( &amp;them[0],
ARRAY_SIZE,
sizeof(struct some_struct),
some_struct_comparison_function );
for ( t=0; t&lt;ARRAY_SIZE; t++ )
some_struct_print_function( &amp;some_struct[t] );
</pre>
qsort works by shuffling the values around as determined by the
comparison function. This has the disadvantage of transferring a lot
of data, which is probably an unnecessary and large overhead if the
only use for the data is to print some part of it.
<p>
The lmsort routines behave differently because they do not shuffle
the data itself, only a linked list of pointers to the data.
To sort the above array using lmsort you need two extra variables, and
a pair of extra calls.
<p>
<pre>
struct some_struct them[ARRAY_SIZE];
struct lmsortp *lp1, *lp2;
lp1 = lmsort_init( &amp;them[0],
ARRAY_SIZE,
sizeof(struct some_struct),
NULL );
lp2 = lmsort( lp1, some_struct_comparison_function );
while (lp2)
{
some_struct_print_function( lp2-&gt;dp );
lp2 = lp2-&gt;next;
};
lmsort_end( lp1 );
</pre>
The three functions perform the following actions.
<dl>
<dt>
lmsort_init <dd> This routine allocates an array of lmsortp structures
and initialises the data pointers and link chain.
<dt>
lmsort <dd> This routine performs the sort, and returns a pointer to
the first lmsortp structure. Note that the value returned is not
necessarily the same as the supplied parameter.
<dt>
lmsort_end <dd> This routine simply frees up the array allocated by the
call to lmsort_init.
</dl>
It is not a requirement to use the _init and _end functions. If your
data structure has a sub-structure that is a struct lmsortp then all that
is required is that the -&gt;next list is initialised (with a NULL pointer
on the last item), and that the data pointers are set.
<P>
<hr>
<p>
</BODY>
</HTML>

25
doc/lock_file.html Normal file
View file

@ -0,0 +1,25 @@
<HTML>
<HEAD>
<TITLE> lock_file </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> lock_file </h1>
<pre>
#include &lt;mplib1/lock_file.h&gt;
int lock_file( const char *filename );
</pre>
This function provides a simple means of controlling access to a single
resource, or a method of ensuring that only instance of a program exists
at any one time.
<p>
The routine attempts to open the filename provided, lock it, truncate it,
write the current pid into it, and mark the file as
<i>close on exec</i>. If all of these succeeds, the function returns 1.
If any fail, the file is closed and the function returns 0.
<P>
<hr>
<p>
</BODY>
</HTML>

86
doc/match_tok.html Normal file
View file

@ -0,0 +1,86 @@
<html>
<head>
<title> match_tok.h() </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> match_tok.h </h1>
<pre>
#include &lt;mplib1/match_tok.h&gt;
int match_string ( const char *line_ptr,
const char *match_ptr,
char ** next_tok );
</pre>
This function returns a non-zero value if the buffer pointed to
by <tt>line_ptr</tt> contains the string pointed to by
<tt>match_ptr</tt>. It returns zero otherwise.
If the <tt>match_ptr</tt> string starts with
a <tt>^</tt> then the string comparision will be against <tt>match_ptr+1</tt>
and <tt>line_ptr</tt>.
<p>
If the <tt>next_tok</tt> parameter is non-NULL then value is set to
either the next non-space character following a match, or to the
<tt>line_ptr</tt> value.
<p>
<hr>
<pre>
struct match_token
{
int m_val;
const char *m_ptr;
};
int match_a_string( const char *line_ptr,
struct match_token *match_ptr,
char ** next_tok );
</pre>
This function takes an input line pointed to by the <tt>line_ptr</tt>
parameter and array of <tt>match_token</tt> structures pointed to by
<tt>match_ptr</tt> which is terminated by an entry with a NULL string
pointer, and an optional pointer to a character pointer.
<p>
The routine effectively performs a series of <tt>match_token</tt> calls
against each entry in the <tt>match_ptr</tt> array until it matches
and then returns the corresponding <tt>m_val</tt>. If there is no match
then the value returned is that of the terminating match token.
<p>
This function can be used to build a simple command parser as illustrated
by the following code.
<pre>
struct match_token my_tokens[] =
{
{ 1, "^help" },.
{ 2, "^quit" },
{ 3, "^details" },
{ 0, NULL }
};
void use_line( char *line_ptr )
{
char *next_cp;
switch( match_a_string( line_ptr, my_tokens, &next_cp ) )
{
1 :
printf("Help not available\n");
break;
2 :
printf("Thank you and goodbye\n");
exit(0);
3 : /* call detail function
and pass remainder of line for parameters
*/
print_details( next_cp );
break;
0 :
printf("Unrecognised command \"%s\"\n", line_ptr );
break;
}
return;
}
</pre>
<p>
</body>
</html>

70
doc/min_list.html Normal file
View file

@ -0,0 +1,70 @@
<html>
<head>
<title>Minimal Double-Linked Lists </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>Minimal Double-Linked Lists </h1>
<pre>
#include &lt;mplib1/min_list.h&gt;
struct Min_List
{
struct Min_Node ln_Head;
struct Min_Node ln_Tail;
};
struct Min_Node
{
struct Min_Node *ln_Succ;
struct Min_Node *ln_Pred;
};
</pre>
The min_list routines are a suite of minmal double-linked list functions
based on the same linkage principle as the standard
<a href="dl_list.html">double-linked list routines</a>.
<P>
<hr>
<h3>Initialisation Routines</h3>
The <tt>Min_List</tt> and <tt>Min_Node</tt> must be initialised before they
can be used.
<pre>
int Init_Min_List ( Min_List *list );
</pre>
This function initialises a Min_List structure for subsequent use.
<P>
<pre>
int Init_Min_Node( Min_Node *node );
</pre>
This function initialises a Min_Node structure for use in a Min_List.
<p>
<hr>
<h3> Add functions </h3>
The two main add functions are as follows.
<pre>
int Add_To_Min_Head( Min_List *list, Min_Node *node );
int Add_To_Min_Tail( Min_List *list, Min_Node *node );
</pre>
These functions add the supplied min_node to the head and tail of the
supplied min_list respectively.
<P>
There is another pair of add functions. These are for use when manipulating
items somewhere in the Min_List.
<pre>
int Add_Min_After( Min_Node *node1, Min_Node *node2 );
int Add_Min_Before( Min_Node *node1, Min_Node *node2 );
</pre>
This pair adds node2 to the list before and after node1 respectively.
<p>
<hr>
<h3>Remove Function</h3>
There is a single remove function.
<pre>
int Remove_Min_Node( Min_Node *node );
</pre>
<hr>
<p>
</body>
</html>

22
doc/mpbasename.html Normal file
View file

@ -0,0 +1,22 @@
<html>
<head>
<title> mpbasename.h </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> mpbasename.h </h1>
<pre>
#include &lt;mplib1/mpbasename.h&gt;
</pre>
This header file contains the definitions for two functions which deal
with process IDs.
<p>
<h2> mpbasename</h2>
<pre>
char *mpbasename( const char *full_name );
</pre>
This function returns a pointer to the non-directory portion
of the file name supplied.
<p>
</body>
</html>

66
doc/mpstrtok.html Normal file
View file

@ -0,0 +1,66 @@
<HTML>
<HEAD>
<TITLE> mpstrtok() </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> mpstrtok() </h1>
<pre>
#include &lt;mplib1/mpstrtok.h&gt;
char *mpstrtok( char *str, void **ftok, const char *seps );
</pre>
This function is a replacment for the standard <tt>strtok()</tt>
function, but which also for multiple strings to be parsed
concurrently. The standard <tt>strtok</tt> has the problem that
it uses a single internal static buffer which allows only a single
string to be parsed at any one time.
<P>
The ability to perform concurrent parsing is performed by means
of an extra parameter which holds for a given string,
the current token position, the next scan position
and the end of string position.
<p>
Use is almost identical to strtok apart from the extra parameter.
<p>
<pre>
char seps[]="\t ";
char string[]="a selection of strings";
char *cp;
void *tokptr;
cp=mpstrtok( string, &tokptr, seps );
while(cp)
{
printf("Token is <%s>\n",cp);
cp=mpstrtok( NULL, &tokptr, seps );
if (cp)
printf( "token: <%s>\n", cp );
};
(void)(mpstrtok( NULL, &tokptr, NULL );
</pre>
would produce the output
<pre>
token: &lt;a&gt;
token: &lt;selection&gt;
token: &lt;of&gt;
token: &lt;strings&gt;
</pre>
<p>
<b>NOTE:</b> the mpstrok routine allocates memory on the initial call
(when <tt>str</tt> is non-null). This memory is normally only freed
when the parse reaches the end of the string. When you wish to finish
parsing of the string, either due to reaching the end of the string,
or your program has collected enough tokens (No purchase neccessary :-),
then mpstrtok should be called with a NULL as the separators string
(as illustrated above).
<p>
Currently the routine automatically frees the allocated memory when failing
to find a token, thus this routine cannot be used to sequentially check
for alternate groups of seperators. This restriction may be removed in
a future release if the semantics are consistent.
<P>
<hr>
<p>
</BODY>
</HTML>

37
doc/pid_check.html Normal file
View file

@ -0,0 +1,37 @@
<HTML>
<HEAD>
<TITLE> pid_check.h </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> pid_check.h </h1>
<pre>
#include &lt;mplib1/pid_check.h&gt;
</pre>
This header file contains the definitions for two functions which deal
with process IDs.
<p>
<h2> gen_pid_str</h2>
<pre>
void gen_pid_str( char *buf, pid_t the_pid );
</pre>
The gen_pid_str function generates an ASCII string based on the supplied
program ID. The buffer should be at least <tt>PID_STR_LEN</tt>
bytes long.
<p>
<b>NB:</b> Previously, this function would return a string giving
the current pid if the parameter passed was (pid_t)0. This is no
longer the case. If (pid_t)0 is passed, the string will be <i>0</i>
<P>
<hr>
<h2> is_pid_dead </h2>
<pre>
extern int is_pid_dead( pid_t the_pid )
</pre>
The is_pid_dead function tests whether the supplied process is dead.
If it is the function returns a non-zero value, otherwise it returns
zero.
<p>
</BODY>
</HTML>

BIN
doc/ppin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

BIN
doc/rpin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

29
doc/safe_string.html Normal file
View file

@ -0,0 +1,29 @@
<html>
<head>
<title> safe_string.h </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> safe_string.h </h1>
<pre>
#include &lt;mplib1/safe_string.h&gt;
int Sstrlen( const char *str1 );
char *Sstrcpy( char *str1, const char *str2 );
</pre>
This pair of routine behaves exactly like the standard library
equivalents with the exception that they behave sanely in the case of
NULL pointers.
<p>
So, <tt>Sstrlen(NULL)</tt> returns 0, and <tt>SStrcpy(cp,NULL)</tt>
copies an empty string, and <tt>Sstrcpy(NULL,NULL)</tt>does nothing.
<p>
These routines are provided for architectures where there is no page
mapped at address 0 within a process. They primarily used internally
to avoid special-casing a number of actions.
<p>
<hr>
<p>
</body>
</html>

161
doc/stopwatch.html Normal file
View file

@ -0,0 +1,161 @@
<HTML>
<HEAD>
<TITLE> stopwatch </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> stopwatch </h1>
<pre>
#include &lt;mplib1/stopwatch.h&gt;
struct stopwatch
{
struct timeval start_time;
struct timeval cumulative_time;
char elps_str[40];
};
int init_stopwatch( struct stopwatch *stp );
int start_stopwatch( struct stopwatch *stp );
int stop_stopwatch( struct stopwatch *stp );
int accrete_stopwatch( struct stopwatch *stp_into,
struct stopwatch *stp_from );
char *display_stopwatch( struct stopwatch *stp, int mode );
</pre>
This set of routines provides a mechanism for timing the execution of
an enclosed block of code. They currently give a displayed accuracy
to hundredths of a second. The stopwatch structure used contains a time
structure for recording when something started, a time structure into which
elapsed times are accumulated, and a string buffer for generating
ASCII representations of the cumulative data.
<p>
<i>init_stopwatch()</i> initialises a stopwatch structure, resetting
the cumulative value, the start value and the string buffer.
<P>
<i>start_stopwatch()</i> sets the start time of stopwatch structure.
<p>
<i>stop_stopwatch()</i> determines the difference between the current time
and that held in the start time, and adds this value to the cumulative
time.
<p>
<i>accrete_stopwatch()</i> adds the cumulative time in the <i>stp_from</i>
structure into the cumulative time in the <i>stp_into</i> structure.
<p>
<i>display_stopwatch()</i> returns a pointer to an ascii representation
of the cumulative time. Currently the only mode that is accepted is <b>0</b>
which gives a string like
<pre>
027.55 seconds
</pre>
or
<pre>
001529.04 seconds
</pre>
depending on whether the number of seconds is greater than 999.
<p>
<hr>
<h3> How to use these routines.</h3>
Suppose we have a block of code we wish to time the execution of.
This can be done as follows.
<pre>
struct stopwatch this_timer;
init_stopwatch( &this_timer );
start_stopwatch( &this_timer );
/* do the block to be timed */
stop_stopwatch( &this_timer );
printf( "The block took %s to complete\n",
display_stopwatch( &this_timer, 0 ) );
</pre>
<p>
Now we can move on to a more complex example. In this, we wish to time
the various database access functions, to accumulate the database timings
and the total time elapsed.
<pre>
struct stopwatch db_time,total_db,complete_time;
init_stopwatch( &complete_time );
start_stopwatch( &complete_time );
init_stopwatch( &total_db );
init_stopwatch( &db_time );
start_stopwatch( &db_time );
fetch_driving_db_record( );
stop_stopwatch( &db_time );
printf( "fetch_driving_db_record took %s to complete\n",
display_stopwatch( &db_time, 0 ) );
accrete_time( &total_db, &db_time );
fetch_local_related_data( ); /* non db */
init_stopwatch( &db_time );
start_stopwatch( &db_time );
fetch_associated_db_records( );
stop_stopwatch( &db_time );
printf( "fetch_associated_db_records took %s to complete\n",
display_stopwatch( &db_time, 0 ) );
accrete_time( &total_db, &db_time );
generate_report_line_for_collected_data( ); /* non db */
stop_stopwatch( &complete_time );
printf( "Total time: %s DB time: %s\n",
display_stopwatch( &complete_time, 0 ),
display_stopwatch( &total_db, 0 ) );
</pre>
This will produce output in the following style
<pre>
fetch_driving_db_record took 014.71 to complete
fetch_associated_db_records took 007.22 to complete
Total time: 023.81 seconds DB time: 021.94 seconds
</pre>
Note that the total DB time is not the exact sum of the displayed parts.
This is because the time held internally is more precise.
<p>
Note also that if the individual timings were not required, then the
total_db structure is not needed as the database access timings are
accumulated in the db_time structure. The resultant code would look like...
<pre>
struct stopwatch db_time,complete_time;
init_stopwatch( &complete_time );
start_stopwatch( &complete_time );
init_stopwatch( &db_time );
start_stopwatch( &db_time );
fetch_driving_db_record( );
stop_stopwatch( &db_time );
fetch_local_related_data( ); /* non db */
start_stopwatch( &db_time );
fetch_associated_db_records( );
stop_stopwatch( &db_time );
generate_report_line_for_collected_data( ); /* non db */
stop_stopwatch( &complete_time );
printf( "Total time: %s DB time: %s\n",
display_stopwatch( &complete_time, 0 ),
display_stopwatch( &db_time, 0 ) );
</pre>
<P>
<hr>
<p>
</BODY>
</HTML>

23
doc/stricmp.html Normal file
View file

@ -0,0 +1,23 @@
<HTML>
<HEAD>
<TITLE> stricmp() </TITLE>
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
<h1> stricmp() </h1>
<pre>
#include &lt;mplib1/stricmp.h&gt;
int stricmp( const char *str1, const char *str2 );
</pre>
This function is provides a case-insensitive version of strcmp.
It is used by a number of other routines in this library
and is used rather than attempting to use the Berkeley routine
<tt>strcasecmp()</tt> which is usually either not available, or extremely
difficult to use on modern systems without using other incorrect
modules from the compatability library.
<P>
<hr>
<p>
</BODY>
</HTML>

86
doc/timestamp.html Normal file
View file

@ -0,0 +1,86 @@
<html>
<head>
<title> timestamp.h </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1> timestamp.h </h1>
<pre>
#include &lt;mplib1/timestamp.h&gt;
</pre>
<p>
<a name="make_timestamp_str">
<h2> make_timestamp_str </h2></a>
<pre>
char * make_timestamp_str( char *buffer );
</pre>
The make_timestamp_str function generates a timestamp string
from the current time from the
<a href="#get_current_timeval</t><i>get_current_timeval</i></a>
function and the
<a href="#build_timestamp_str"><i>build_timestamp_str</i></a>
function.
formatted to ISO 8601 / EN28601 based on the current time.
<p>
The timestamp is in UTC and
is formed using <tt>strftime()</tt> and
then adding hundredths of seconds and timezone offset.
<P>
The buffer parameter specifies a data area in which to create this string.
If it is provided it should be at least 24 characters long.
If the buffer parameter is NULL then the
routine uses an internal static buffer, the resultant
value should be used immediately or copied.
An example of the completed string is;
<pre>
"1996-12-31 13:45:56.78Z"
</pre>
This function is implemented using the following two functions.
<p>
<hr>
<a name="build_timestamp_str">
<h2> build_timestamp_str </h2>
<pre>
char *build_timestamp_str( struct timeval *tvp, char *buf );
</pre>
This function function generates a timestamp string
formatted to ISO 8601 / EN28601 based on the supplied <b>timeval</b>
structure.
<p>
The timestamp is in UTC and
is formed using <tt>strftime()</tt> and
then adding hundredths of seconds and timezone offset.
<P>
The buffer parameter specifies a data area in which to create this string.
If it is provided it should be at least 24 characters long.
If the buffer parameter is NULL then the
routine uses an internal static buffer, the resultant
value should be used immediately or copied.
An example of the completed string is;
<pre>
"1996-12-31 13:45:56.78Z"
</pre>
<p>
<hr>
<a name="get_current_timeval">
<h2> get_current_timeval </h2> </a>
<pre>
struct timeval *get_current_timeval( struct timeval * );
</pre>
This function gets the current time of day in UTC using the
system <i>gettimeofday</i> function. It is provided as a platform
independant variation of the system call because it varies between
implementations.
<hr>
<h4> Revision note. </h4>
As of library version 2.5.0 the <tt>build_timestamp_str</tt> function
produces a string conforming to ISO 8601 / EN28601. Previously the
format was YYYY/MM/DD HH:MM:SS:DD which was a little confusing. The
new string is one character longer, but does not cause any buffer to
be overwritten if they were specified as being at least 24 characters
long.
</body>
</html>

BIN
doc/ypin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

37
gen_html_index Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh
#
OFILE=index.html
echo "<html>\n<head>\n<title>File Index</title>\n</head>\n" >$OFILE
if [ -f include/body_part.html ]
then
cat include/body_part.html >>$OFILE
else
echo "<body bgcolor=\"#ffffff\" text=\"#000000\">\n" >>$OFILE
fi
echo "<h1>File Index</h1>\n\n<ul>\n" >>$OFILE
for i
do
if [ "$i" = "." ]
then
echo "<p>\n" >>$OFILE
else
echo "<li><a href=\"$i\"> $i </a>\n" >>$OFILE
fi
done
echo "</ul>\n<p>\n" >>$OFILE
if [ -f include/body_tail.html ]
then
cat include/body_tail.html >>$OFILE
else
echo "</body>\n" >>$OFILE
fi
echo "</html>\n" >>$OFILE

674
gpl-3.0.txt Normal file
View file

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

1
include/body_part.html Normal file
View file

@ -0,0 +1 @@
<body bgcolor="#ffffff" text="#000000">

View file

@ -0,0 +1,94 @@
#ifndef MPLIB1_BPO_ALLOC_PRIV
#define MPLIB1_BPO_ALLOC_PRIV
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifndef MPLIB1_CONFIG
#include <mplib1/mplib1_config.h>
#endif
#ifndef MPLIB1_BPO_LOCK
#include <mplib1/bpo_lock.h>
#endif
#ifndef MPLIB1_BPO_LIST
#include <mplib1/bpo_list.h>
#endif
#ifndef MPLIB1_BPO_INIT
#include <mplib1/bpo_init.h>
#endif
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#define MIN_SHALLOC_SIZE 32
#define MIN_SHALLOC_MASK 0xffffffe0
#define STD_NUM_TRACK_BLKS 100
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
struct shalloc_track_head
{
off_t lno_me;
off_t next_track_head;
size_t head_and_tracks;
size_t num_tracks;
size_t num_empty;
int sth_flags;
};
struct shalloc_track
{
off_t sh_off;
size_t sh_size;
};
struct shalloc_base
{
off_t lno_me;
size_t sh_size;
off_t lno_first_free;
off_t lno_first_used;
b_lock_t sb_lock;
struct shalloc_track emergency_used;
struct sodb_resource shalloc_resource;
char shalloc_name[10];
};
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
extern struct sodb_resource *
shalloc_init( void *seg_base, off_t shalloc_base_off, size_t shalloc_sz );
#endif
/* -- End of File -- */

142
include/bpo_init_internal.h Normal file
View file

@ -0,0 +1,142 @@
#ifndef MPLIB1_BPO_INIT_INTERNAL
#define MPLIB1_BPO_INIT_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifdef CXREF
#include <sys/types.h>
#include <sys/ipc.h>
#endif
#ifndef MPLIB1_CONFIG
#include <mplib1/mplib1_config.h>
#endif
#ifndef MPLIB1_DL_LIST
#include <mplib1/dl_list.h>
#endif
#ifndef MPLIB1_BPO_LOCK
#include <mplib1/bpo_lock.h>
#endif
#ifndef MPLIB1_BPO_LIST
#include <mplib1/bpo_list.h>
#endif
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#define SODB_MAGIC 0x536d6567
#define SODB_VERSION_1 1
#define SODB_VERSION_2 2
#define SODB_VERSION_4 4
#define SODB_CURRENT_VERSION SODB_VERSION_4
#define SODB_NAME_SIZE1 512
enum sodb_types
{
SODB_T_UNKNOWN,
SODB_T_MMAP,
SODB_T_IPC
};
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
struct sodb_resource
{
bpo_Node_t res_node;
off_t res_off;
};
struct sodb
{
int sodb_magic;
char sodb_use_name[SODB_NAME_SIZE1];
size_t sodb_size;
enum sodb_types sodb_type;
int sodb_version;
int sodb_flags;
struct stat mmap_stat;
int mmap_fd;
int mmap_prot;
int mmap_flags;
off_t mmap_off;
char mmap_name[SODB_NAME_SIZE1];
key_t ipc_key;
char ipc_path[SODB_NAME_SIZE1];
char ipc_tok_id;
int ipc_id;
struct bpo_pid_lock res_p_lock;
bpo_List_t sodb_resource_list;
struct sodb_resource sodb_resource;
char sodb_res_name[10]; /* this has "SODB Base" copied into it */
off_t shalloc_offset;
size_t shalloc_size;
};
struct sodb_track
{
dl_Node_t st_Node;
struct sodb *sodbp;
int mmap_fd;
const char *upper;
mode_t access_mode;
char fname[1];
};
struct sodb_res_find
{
struct sodb *sodbp;
const char *name;
void *ptr;
void *obj;
int flags;
int ierrno;
off_t rv;
};
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
extern void Init_SODB_Resources( struct sodb *sodbp );
#endif
/* -- End of File -- */

View file

@ -0,0 +1,50 @@
#ifndef MPLIB1_BPO_INIT_INTERNAL
#define MPLIB1_BPO_INIT_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#define GNNODE(n,off) ((bpo_Node_t *)GRPTR(n,off))
#define GANNODE(bp,off) (bpo_Node_t *)((char *)bp+off)
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
#endif
/* -- End of File -- */

183
include/bpo_lock_internal.h Normal file
View file

@ -0,0 +1,183 @@
#ifndef MPLIB1_BPO_LOCK_INTERNAL
#define MPLIB1_BPO_LOCK_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifndef MPLIB1_CONFIG
#include <mplib1/mplib1_config.h>
#endif
#ifndef MPLIB1_BPO_LOCK
#include <mplib1/bpo_lock.h>
#endif
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
/* Only one of the following ifdef blocks should be enabled */
#ifdef HAVE_PTHREADS
/* No explicit defines needed */
#endif
#ifdef HAVE_MSEM
/* XPG4 varient */
/*#define Xchg(a) msem_lock(a,0)*/
/*#define Clr(a) msem_unlock(a)*/
#endif
#ifdef HAVE_MUTEX
#define Xchg(a) acquire_lock(a)
#define Clr(a) release_lock(a)
#define Lckval(a) ((long)(a->abi_lock))
#endif
#ifdef HAVE_SYS_ATOMIC
#include <sys/atomic.h>
#define Xchg(a) atomic_xchg_long((long *)a,1)
#define Clr(a) atomic_xchg_long((long *)a,0)
#define Lckval(a) ((long)(*(long *)a))
#endif
#ifdef HAVE_GCC_I386
/* The following was swiped from <asm/bitops.h> in the linux distribution */
/*
* Some hacks to defeat gcc over-optimizations..
*/
struct __dummy { unsigned long a[100]; };
#define ADDR (*(struct __dummy *) addr)
__inline__ static int Xchg(volatile void * addr)
{
int oldbit;
__asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"r" (0));
return oldbit;
}
__inline__ static int Clr( volatile void * addr)
{
int oldbit;
__asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"r" (0));
return oldbit;
}
#define Lckval(a) ((long)(*a))
#endif
#ifdef HAVE_SVR4_I386
/* The following were grabbed from <sys/mp/mpmacros.h> on NCR 3000 */
asm int
Xchg(lp)
{
% mem lp;
movl lp,%eax
xchgl %eax,(%eax)
}
asm void
Clr(lp)
{
% mem lp;
movl lp,%eax
movl $0,(%eax)
% reg lp;
movl $0,(lp)
}
#define Lckval(a) ((long)(*a))
#endif
#ifdef HAVE_SVR4_I386B
/* The following was grabbed from <sys/atomic.h> on Sequent Ptx4.2.0 */
/*
* atomic_xchg_long
*
* Atomically exchange the specified value with that at the specified
* address, returning the old value.
* The only reason for having both atomic_xchg_*() and atomic_xchg_u*()
* primitives is to keep the compiler and lint happy without huge
* numbers of error-hiding casts.
*
* Parameters:
* long *longptr; Address of long to exchange
* long newval; New value to exchange into *longptr.
*/
#ifdef __STDC__
__asm long atomic_xchg_long(volatile long *const longptr, long const newval)
#else
asm long atomic_xchg_long(longptr, newval)
#endif
{
%con longptr, newval;
movl longptr, %ecx /* Get addr to known register. */
movl newval, %eax /* Get new value to known register. */
xchgl %eax, (%ecx) /* Perform the exchange. */
%con longptr; mem newval;
movl longptr, %ecx /* Get addr to known register. */
movl newval, %eax /* Get new value to known register. */
xchgl %eax, (%ecx) /* Perform the exchange. */
%mem longptr; con newval;
movl longptr, %ecx /* Get addr to known register. */
movl newval, %eax /* Get new value to known register. */
xchgl %eax, (%ecx) /* Perform the exchange. */
%mem longptr, newval;
movl longptr, %ecx /* Get addr to known register. */
movl newval, %eax /* Get new value to known register. */
xchgl %eax, (%ecx) /* Perform the exchange. */
}
#define Xchg(a) atomic_xchg_long((long *)a,1)
#define Clr(a) atomic_xchg_long((long *)a,0)
#define Lckval(a) ((long)(*(long *)a))
#endif
#endif
/* -- End of File -- */

156
include/bpo_proc_internal.h Normal file
View file

@ -0,0 +1,156 @@
#ifndef MPLIB1_BPO_PROC_INTERNAL
#define MPLIB1_BPO_PROC_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifdef CXREF
#include <sys/types.h>
#include <mplib1/dl_list.h>
#endif
#ifndef MPLIB1_CONFIG
#include <mplib1/mplib1_config.h>
#endif
#ifndef MPLIB1_BPO_LOCK
#include <mplib1/bpo_lock.h>
#endif
#ifndef MPLIB1_BPO_LIST
#include <mplib1/bpo_list.h>
#endif
#ifndef MPLIB1_BPO_INIT
#include <mplib1/bpo_init.h>
#endif
#ifndef MPLIB1_BPO_ALLOC
#include <mplib1/bpo_alloc.h>
#endif
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifndef BIT
#define BIT(n) (1<<(n))
#endif
#define SHM_INHERIT_GROUP BIT(0)
#define SHM_INHERIT_PROGRAM BIT(1)
#define SHM_AUTOMAGIC_PIPE BIT(2)
#define SHM_CHECK_ALL_PROCESSES 1
#define SHM_CHECK_THIS_PROCESS 2
#define SHM_CHECK_DEAD_PROCESSES 3
/* Return values to the validate processes inform call */
#define SHM_LEAVE_PROC 0
#define SHM_DELETE_PROC 1
#ifndef PID_STR_LEN
#define PID_STR_LEN 12
#endif
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
struct shm_proc_list
{
off_t lno_me;
int serial_nbr;
time_t update_tm;
bpo_List_t proc_List;
};
struct shm_process
{
off_t lno_me;
bpo_Node_t proc_Node;
pid_t pid;
time_t pid_start_tm;
bpo_List_t pid_resources;
char pid_str[PID_STR_LEN];
off_t pid_grp_o;
off_t pid_nm_o;
off_t pid_fifo_o;
};
struct shm_process_private
{
dl_Node_t spp_Node;
pid_t pid;
char pid_str[PID_STR_LEN];
char *pid_grp;
char *pid_nm;
char *pid_fifo;
int fifo_fd;
int fifo_created;
mode_t fifo_mode;
time_t pid_start_tm;
struct shm_process *spp;
};
struct cache_proc_list
{
dl_Node_t lnk_node;
char ptr_str[40];
unsigned long serial_nbr;
time_t update_tm;
struct shm_proc_list *splp;
dl_List_t proc_list;
dl_List_t old_proc_list;
};
typedef int (* Validate_Processes_t)( struct shm_process_private *shmpp,
void *param1 );
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
/* Allocate functions */
extern struct shm_process_private *
alloc_private_process( pid_t the_pid, const char *pid_grp,
const char *pid_nm, const char *pid_fifo );
extern void
free_private_process( struct shm_process_private *sppp );
#ifndef MPLIB1_BPO_PROC
extern struct shm_process_private * Get_My_Proc_Details( mode_t privs );
extern struct shm_process_private * Check_My_Proc_Details( void );
#endif
extern int
Validate_Processes( const void * hint, int which_procs,
Validate_Processes_t disp,
void *param1 );
extern struct shm_proc_list *Find_Proc_List( const void *hint );
extern struct cache_proc_list *Get_Cache_Procs( const void *hint );
#endif
/* -- End of File -- */

140
include/bpo_q_internal.h Normal file
View file

@ -0,0 +1,140 @@
#ifndef MPLIB1_BPO_Q_INTERNAL
#define MPLIB1_BPO_Q_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifdef CXREF
#include <sys/types.h>
#include <mplib1/dl_list.h>
#endif
#ifndef MPLIB1_CONFIG
#include <mplib1/mplib1_config.h>
#endif
#ifndef MPLIB1_BPO_LOCK
#include <mplib1/bpo_lock.h>
#endif
#ifndef MPLIB1_BPO_LIST
#include <mplib1/bpo_list.h>
#endif
#ifndef MPLIB1_BPO_INIT
#include <mplib1/bpo_init.h>
#endif
#ifndef MPLIB1_BPO_ALLOC
#include <mplib1/bpo_alloc.h>
#endif
#ifndef MPLIB1_BPO_PROC
#include <mplib1/bpo_proc.h>
#endif
#ifndef MPLIB1_BPO_QUEUE
#include <mplib1/bpo_queue.h>
#endif
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
structures
------------------------------------------------------------------ */
struct Q_Head
{
off_t lno_me;
bpo_List_t Qh_List;
};
struct bpo_Q_pid
{
bpo_Node_t Q_pid_Node;
pid_t Q_pid;
char Q_pidstr[PID_STR_LEN];
};
struct bpo_private_pid
{
dl_Node_t q_Node;
pid_t pid;
char pid_str[PID_STR_LEN];
};
struct bpo_private_q
{
dl_Node_t q_Node;
int Q_max_count;
int Q_Count;
int Q_notify;
int Q_flags;
pid_t Q_sole_pid;
dl_List_t private_pids;
unsigned long pid_ser_nbr;
dl_List_t old_pids;
struct bpo_Q *qp;
char Q_name[1];
};
struct cache_queue_list
{
dl_Node_t lnk_node;
char ptr_str[40];
unsigned long serial_nbr;
time_t update_tm;
struct Q_Head *qh;
dl_List_t q_list;
dl_List_t old_q_list;
};
typedef int (*Validate_Queues_t)(struct bpo_private_q *pqp, void *param1 );
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
extern struct Q_Head *
get_Q_resource( const void *hint );
extern struct cache_queue_list *
cache_queues( struct Q_Head *qh, const char *q_name );
extern void
free_q_stuff( struct bpo_Q *qp );
extern void
free_this_private_q( struct bpo_private_q *pqp );
extern int
Validate_Queues( const void *hint,
int p_which_queues,
Validate_Queues_t disp,
void *param1 );
#endif
/* -- End of File -- */

View file

@ -0,0 +1,82 @@
#ifndef MPLIB1_CFG_FILE_INTERNAL
#define MPLIB1_CFG_FILE_INTERNAL
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifdef CXREF
#include <sys/types.h>
#include <mplib1/dl_list.h>
#endif
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#define MAX_CONFIG_STR 200
#define MAX_CONFIG_FLAGS 100
/* ------------------------------------------------------------------
structure
------------------------------------------------------------------ */
struct config_list
{
dl_Node_t cl_Node;
dl_List_t cl_Items;
int cl_flags;
char cl_name[1];
};
struct config_item
{
dl_Node_t ci_Node;
char *ci_name;
char *eval_str;
char ci_val[1];
};
/* ------------------------------------------------------------------
function definitions
------------------------------------------------------------------ */
extern struct config_list *
get_config_list( const char *list_name, int create );
extern dl_List_t *
get_config_list_list( void );
extern struct config_item *
get_private_config( const char *list_name, const char *key );
#endif
/* -- End of File -- */

179
include/dl_lru_private.h Normal file
View file

@ -0,0 +1,179 @@
#ifndef MPLIB1_DL_LRU_PRIVATE_H
#define MPLIB1_DL_LRU_PRIVATE_H
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose : private definitions for the cache routines
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
#ifdef CXREF
#include <sys/types.h>
#include <mplib1/dl_list.h>
#include <mplib1/data_align.h>
#endif
struct Full_List
{
List_t fl_Search_List;
List_t fl_LRU_List;
const char *fl_Name;
};
#define FULL_LIST_SIZE sizeof(struct Full_List)
struct Cache_List
{
Node_t cl_Node; /* links us into the Master List */
char *cl_Name; /* Name of this list, (cursor name) */
List_t cl_Fields; /* List of fields (definitions) */
struct Full_List cl_Items; /* List of items */
List_t cl_Free; /* free items */
List_t cl_Free_cgi; /* free cgi items */
List_t cl_Build; /* build list for new items */
List_t cl_Missing; /* list for missing items */
int cl_flags; /* how we will check this list */
size_t cl_data_size; /* size of data block allocated for each item */
int cl_max_items; /* How many items allowed on list */
int cl_curr_items; /* how many so far */
int cl_max_field_num; /* current maximum field number */
int cl_cache_replaces; /* how many times did we re-use */
int cl_cache_hits; /* found an entry */
int cl_cache_misses; /* oh dear */
int cl_complete_misses; /* If they care to tell us */
int cl_expire_seconds; /* How long an item is allowed to live */
int cl_num_search_rules; /* How many rules in the next array */
struct full_search_rule *cl_search_rules; /* How to search */
time_t cl_create_time; /* when was this created */
int cl_expire_time; /* How many seconds till expiry */
};
struct Cache_Field
{
Node_t cf_Node; /* to link into cl_Field list */
char *cf_Name;
int cf_field_num;
int cf_field_type;
#define CF_INT 1
#define CF_DOUBLE 2
#define CF_CHAR 3
#define CF_STRING 4
#define CF_VARCHAR 5
#define CF_NUM_FIELD_TYPES 6
int cf_field_flags;
#define CF_FLG_IGNORECASE BIT(0)
int cf_f_offset; /* field offset from item base */
size_t cf_field_size; /* and length within data block */
};
struct Cache_Item
{
Node_t ci_S_Node; /* to link us into the cl_Items Search list */
Node_t ci_L_Node; /* to link us into the cl_Items LRU list */
char *ci_Name; /* index field */
size_t ci_data_size; /* size of allocated block */
size_t ci_str_size; /* size of the original string */
void *ci_Item; /* pointer to block containing data */
time_t ci_expire_time; /* When this item is to be aged */
};
struct Cache_Group_Item
{
struct Cache_Item cgi_Item; /* Allow for normal data */
struct Full_List cgi_Items; /* Next list for searching */
int cgi_Flags;
int cgi_cache_replaces; /* how many times did we re-use */
int cgi_cache_hits; /* found an entry */
int cgi_cache_misses; /* oh dear */
int cgi_complete_misses; /* If they care to tell us */
};
struct full_search_rule
{
struct Cache_Field *cf;
int comparison_method;
int (*cmpfunc)( void *, void * );
/*off_t cf_f_offset;*/
};
#define CGI_COMPLETE_MISS BIT(0)
#define CACHE_LIST_SIZE sizeof(struct Cache_List)
#define CACHE_FIELD_SIZE sizeof(struct Cache_Field)
#define CACHE_ITEM_SIZE STRUCT_PAD(sizeof(struct Cache_Item))
/* In dl_lru (normal caching) ------------------------------ */
extern struct Full_List *
Init_Full_List ( struct Full_List *list, const char *name, int flags );
extern void *
Find_Full_Item ( struct Full_List *flist, const char *name );
extern List_t *
Get_Cache_Master_List( void );
extern void *
Cache_Alloc_Lump( size_t sz, const char *name, char **new_name );
extern struct Cache_List *
New_Cache_List( const char *list_name, int max_items,
int flags, int defaults, int last_ditch );
extern int
Cache_Build_Field_List( struct Cache_List *cl,
const char *format_str,
const char *field_names );
extern struct Cache_Item *
Cache_Find_Simple_Item( struct Cache_List *cl,
const char *keys,
int *rv );
/* In dl_lru_range (range caching) ------------------------------ */
extern struct Cache_Item *
Cache_Find_Requested_Item( struct Cache_List *cl, const void *keys, int *rv );
extern struct Cache_Item *
Cache_Get_Item_From_Free( struct Cache_List *cl );
extern int
Cache_End_Of_Many( struct Cache_List *cl );
extern int
Range_Complete_Miss( struct Cache_List *cl, const void *keys );
extern int
Range_Flush( struct Cache_List *cl );
#endif
/* -- End of File -- */

34
include/index.html Normal file
View file

@ -0,0 +1,34 @@
<html>
<head>
<title>File Index</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>File Index</h1>
<ul>
<li><a href="bpo_alloc_private.h"> bpo_alloc_private.h </a>
<li><a href="bpo_init_internal.h"> bpo_init_internal.h </a>
<li><a href="bpo_list_internal.h"> bpo_list_internal.h </a>
<li><a href="bpo_lock_internal.h"> bpo_lock_internal.h </a>
<li><a href="bpo_proc_internal.h"> bpo_proc_internal.h </a>
<li><a href="bpo_q_internal.h"> bpo_q_internal.h </a>
<li><a href="cfg_file_internal.h"> cfg_file_internal.h </a>
<li><a href="dl_lru_private.h"> dl_lru_private.h </a>
</ul>
<p>
</body>
</html>

38
index.html Normal file
View file

@ -0,0 +1,38 @@
<hmtl>
<head>
<title> mplib1 </title>
</head>
<body bgcolor="#ffffff" text="#000000">
<img src="src_doc/library_mplib1.gif">
<p>
Welcome to the utility library "mplib1".
<dl>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="platform/PORTING.html"> Porting Notes</a><br>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="doc/index.html"> Programmer Use Notes</a><br>
<dt><dd><img src="util_doc/icons/rpin.gif">
Source Review
<dl>
<dt><dd><img src="util_doc/icons/ppin.gif">
<a href="libsrc/index.html"> function source</a><br>
<dt><dd><img src="util_doc/icons/ppin.gif">
<a href="mplib1/index.html"> public includes</a><br>
<dt><dd><img src="util_doc/icons/ppin.gif">
<a href="include/index.html"> private includes</a><br>
</dl>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="src_doc/mplib1.apdx.html"> Source Cross Reference</a><br>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="util/index.html"> Utility Source Review</a><br>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="src_doc/util.apdx.html"> Utility Cross Reference</a><br>
<dt><dd><img src="util_doc/icons/rpin.gif">
<a href="util_doc/index.html"> Utility Documentation</a><br>
</dl>
</body>
</html>

123
libsrc/Makefile Normal file
View file

@ -0,0 +1,123 @@
#
#
include ../make_include
MPLIB1=$(LIBDIR)/libmplib1.a
MPLIB1SO_BASE=libmplib1.so
MPLIB1SO=$(LIBDIR)/$(MPLIB1SO_BASE)
ifndef MAJOR_VERSION
MAJOR_VERSION=4
endif
ifndef MINOR_VERSION
MINOR_VERSION=1
endif
VERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
ifdef BUILD_SHARED
TARGETS=$(MPLIB1) $(MPLIB1SO)
else
TARGETS=$(MPLIB1)
endif
PUBHEADERS=$(wildcard $(LIBINC_DIR)/mplib1/*.h)
PUBHEADERS_BASE=$(patsubst $(LIBINC_DIR)/mplib1/%, %, $(PUBHEADERS))
PRIVATE_H=$(wildcard $(LIBINC_DIR)/include/*.h)
PRIVATE_H_BASE=$(patsubst $(LIBINC_DIR)/include/%, %, $(PRIVATE_H))
OBJECTS= \
safe_string.o \
time.o \
get_uname.o \
make_log_str.o \
fput_log_str.o \
fprintfile.o \
pidstr.o \
min_list.o \
dl_list.o \
mpstrtok.o \
cfg_file.o \
cfg_watch.o \
lock_file.o \
vre_alloc.o \
vre_disp.o \
vre_parse.o \
vre_loop.o \
fgetline.o \
fgetline2.o \
match_tok.o \
lmsort.o \
lmsort_m.o \
dl_sort_i.o \
dl_sort_n.o \
dumphex.o \
mpbasename.o \
build_argv.o \
inthand.o \
leavesub.o \
daemonloop.o \
daemonsleep.o \
stopwatch_c.o \
stopwatch.o \
cpustopwatch.o \
$(COMPAT_OBJS)
LIBOBJECTS=$(patsubst %.o,$(MPLIB1)(%.o),$(OBJECTS))
SO_OBJECTS=$(patsubst %.o,$(MPLIB1SO)(%.o),$(OBJECTS))
LIBSOURCE=$(patsubst %.o,%.c,$(OBJECTS))
LIBDEPEND=$(patsubst %.o,DEPENDS/%.d,$(OBJECTS))
all: $(TARGETS)
clean:
@rm -f $(TARGETS)
@rm -f $(OBJECTS)
@rm -f $(LIBDEPEND)
install:
cp $(MPLIB1) $(INSTALL_LIB)
@mkdir $(INSTALL_INCLUDE)
cp $(PUBHEADERS) $(INSTALL_INCLUDE)
ifdef BUILD_SHARED
cp $(MPLIB1SO) $(INSTALL_LIB)/$(MPLIB1SO_BASE).$(VERSION)
ln -s $(MPLIB1SO_BASE).$(VERSION) $(INSTALL_LIB)/$(MPLIB1SO_BASE)
ln -s $(MPLIB1SO_BASE).$(VERSION) $(INSTALL_LIB)/$(MPLIB1SO_BASE).$(MAJOR_VERSION)
endif
docs: docs_xref docs_src
docs_xref:
cxref $(LIBSOURCE) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -I$(LIBINC_DIR)
cxref $(PUBHEADERS) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -I$(LIBINC_DIR) -- -DCXREF
cxref $(PRIVATE_H) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -I$(LIBINC_DIR) -- -DCXREF
cxref $(LIBSOURCE) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -html -html-body include/body_part.html -I$(LIBINC_DIR)
cxref $(PUBHEADERS) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -html -html-body include/body_part.html -I$(LIBINC_DIR) -- -DCXREF
cxref $(PRIVATE_H) -xref-all -index-all -Osrc_doc -Nmplib1 -R.. -html -html-body include/body_part.html -I$(LIBINC_DIR) -- -DCXREF
docs_src:
../gen_html_index $(LIBSOURCE) . Makefile
(cd ../mplib1; ../gen_html_index $(PUBHEADERS_BASE) )
(cd ../include; ../gen_html_index $(PRIVATE_H_BASE) )
docs_clean:
rm -f ../src_doc/mplib1.*
rm -rf ../src_doc/mplib1 ../src_doc/include ../src_doc/libsrc
rm -f index.html ../mplib1/index.html ../include/index.html
$(MPLIB1): ../mplib1/mplib1_config.h $(LIBOBJECTS)
$(MPLIB1SO): $(OBJECTS)
$(CC) -shared -Wl,-soname,$(MPLIB1SO_BASE).$(MAJOR_VERSION) \
-o $(MPLIB1SO) \
$(OBJECTS)
ifndef DOING_CLEAN
include $(LIBDEPEND)
endif

211
libsrc/build_argv.c Normal file
View file

@ -0,0 +1,211 @@
/*
*******************************************************************************
* Copyright (c) 1997 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/build_argv.h>
#include <mplib1/mpstrtok.h>
#include <mplib1/cfg_file.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static struct argv_track *
init_argv_track( struct argv_track *argvtp )
{
if (argvtp==NULL)
argvtp = malloc( sizeof(struct argv_track) );
if (argvtp)
{
dl_Init_Node( &argvtp->v_node, NULL, argvtp );
dl_Init_List( &argvtp->m_track, 0 );
dl_Init_List( &argvtp->v_parts, 0 );
dl_Init_List( &argvtp->f_track, 0 );
argvtp->argv = NULL;
argvtp->argc = 0;
}
return(argvtp);
}
void
free_argv_track( struct argv_track *argvtp )
{
if (argvtp)
{
dl_Walk_List( &argvtp->m_track, (dl_Walk_List_t)free, NULL );
init_argv_track( argvtp );
free( argvtp );
}
return;
}
static int
track_this( struct argv_track *argvtp, dl_List_t *tlist, void *tp )
{
dl_Node_t *np;
int rv;
np = dl_Remove_Head( &argvtp->f_track );
if (np==NULL)
{
int t=5;
np = malloc( NODE_SIZE * (size_t)t );
if (np)
{
dl_Init_Node( np, NULL, np );
dl_Add_Tail( &argvtp->m_track, np++ );
while(--t)
{
dl_Init_Node( np, NULL, np );
dl_Add_Tail( &argvtp->f_track, np++ );
};
np = dl_Remove_Head( &argvtp->f_track );
};
}
if (np)
{
dl_Init_Node( np, NULL, tp );
dl_Add_Tail( tlist, np );
rv=1;
}
else
rv=0;
return(rv);
}
static int
split_this( struct argv_track *argvtp, char *raw )
{
char *cp;
int rv=0;
void *tokptr;
static char seps[]=" \t\n";
/* printf("parse: %s\n", raw );*/
cp = mpstrtok( raw, &tokptr, seps );
while( cp )
{
/* Now add this item to the v_part list */
/* printf("track: %s\n", cp );*/
/* First we expand the parameter if needed */
if (strchr(cp,'$') || strchr(cp,'%'))
{
cp = strdup( eval_config_default( NULL, cp ) );
track_this( argvtp, &argvtp->m_track, cp );
}
track_this( argvtp, &argvtp->v_parts, cp );
cp = mpstrtok( NULL, &tokptr, seps );
}
(void)mpstrtok( NULL, &tokptr, NULL );
return(rv);
}
static void
count_em( void *vp, int *nc )
{
*nc = *nc +1;
return;
}
static void
v_init( char *cp, char ***vp )
{
/* printf("v_add: %p=%s\n", *vp, cp);*/
**vp = cp;
*vp = *vp+1;
return;
}
static int
build_argv( struct argv_track *argvtp )
{
char **vp;
int rv=0;
/* Now count the number of elements */
argvtp->argc=0;
dl_Walk_List( &argvtp->v_parts, (dl_Walk_List_t)count_em, &argvtp->argc );
/* Add the terminating NULL pointer */
track_this( argvtp, &argvtp->v_parts, NULL );
/* Now allocate a suitable array of pointers */
vp = malloc( (size_t)(argvtp->argc+1) * sizeof(char *) );
if (vp)
{
/* printf("char pointer array: %p\n", vp );*/
track_this( argvtp, &argvtp->m_track, vp );
argvtp->argv = vp;
/* Looks good so far */
dl_Walk_List( &argvtp->v_parts, (dl_Walk_List_t)v_init, &vp );
rv=1;
}
return(rv);
}
struct argv_track *
build_argv_track( struct argv_track *argvtp, ... )
{
va_list ap;
char *cp,*rcp;
free_argv_track(argvtp);
argvtp = init_argv_track( argvtp );
if (argvtp)
{
va_start(ap,argvtp);
while ( (cp = va_arg(ap, char* )) )
{
/* dup, split, and add this string to the argv list */
rcp = strdup(cp);
track_this( argvtp, &argvtp->m_track, rcp );
split_this( argvtp, rcp );
};
va_end(ap);
build_argv( argvtp );
}
return(argvtp);
}
/* -- End of File -- */

573
libsrc/cfg_file.c Normal file
View file

@ -0,0 +1,573 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/safe_string.h>
#include <mplib1/fgetline.h>
#include <mplib1/dl_list.h>
#include <mplib1/cfg_file.h>
#include <mplib1/timestamp.h>
#include <include/cfg_file_internal.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
static char config_list[]="config_items";
static int done_init=0;
static struct config_list *def_list=NULL;
static dl_List_t current_lists;
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
struct config_list *
get_config_list( const char *list_name, int create )
{
struct config_list *clp;
if (!done_init)
{
done_init = 1;
(void)dl_Init_List( &current_lists, 0 );
}
if (list_name==NULL)
{
if (def_list)
return(def_list);
list_name = config_list;
}
clp = dl_Find_Item_By_Name( &current_lists, list_name );
if (clp==NULL && create)
{
clp = malloc( sizeof(struct config_list) + Sstrlen(list_name) );
if (clp)
{
if (list_name==config_list)
def_list = clp;
Sstrcpy( clp->cl_name, list_name );
clp->cl_flags=0;
(void)dl_Init_Node( &clp->cl_Node, clp->cl_name, clp );
(void)dl_Init_List( &clp->cl_Items, 0 );
(void)dl_Add_Head( &current_lists, &clp->cl_Node );
}
}
return(clp);
}
dl_List_t *
get_config_list_list( void )
{
if (!done_init)
{
done_init = 1;
(void)dl_Init_List( &current_lists, 0 );
}
return( &current_lists );
}
static struct config_item *
Alloc_Item( const char *key, const char *val )
{
struct config_item *cip;
size_t slen;
char *cp;
slen = Sstrlen(val) + 1;
cip = malloc( sizeof(struct config_item) + Sstrlen(key) + slen );
if (cip)
{
cp = cip->ci_val + slen;
Sstrcpy( cip->ci_val, val );
Sstrcpy( cp, key );
cip->eval_str=NULL;
(void)dl_Init_Node( &cip->ci_Node, cp, cip );
}
return(cip);
}
int
set_private_string( const char *list_name, const char *key, const char *val )
{
struct config_list *clp;
struct config_item *cip;
int rv=0;
clp = get_config_list( list_name, 1 );
if (clp)
{
cip = (struct config_item *)dl_Find_Item_By_Name( &clp->cl_Items, key );
if (cip==NULL || Sstrlen(cip->ci_val) < Sstrlen(val))
{
if (cip)
{
(void)dl_Remove_Node( &cip->ci_Node );
free( cip );
}
cip = Alloc_Item( key, val );
if (cip)
{
(void)dl_Add_Head( &clp->cl_Items, &cip->ci_Node );
rv=1;
}
}else
{
/* replace the existing text */
Sstrcpy( cip->ci_val, val );
rv=1;
}
}
return(rv);
}
int
read_private_string( const char *list_name, const char *line )
{
int rv=0;
char *newline,*cp=NULL,*szs=NULL;
static char cl_seps[]=",: \t=";
newline = strdup(line);
/* first we parse the line for various parameters */
if ( (cp=strtok(newline,cl_seps)) )
szs=strtok(NULL,"\015");
if (cp && *cp!='#' )
{
rv = set_private_string( list_name, cp, szs );
}
free(newline);
return(rv);
}
void
flush_item_eval( const char *list_name, const char *item )
{
struct config_list *clp;
struct config_item *cip;
if ( (clp = get_config_list( list_name, 0 ))
&& (cip = dl_Find_Item_By_Name( &clp->cl_Items, item ))
&& (cip->eval_str != NULL)
)
{
free(cip->eval_str);
cip->eval_str=NULL;
}
return;
}
static void
flush_this_eval( struct config_item *cip )
{
if (cip->eval_str)
{
free(cip->eval_str);
cip->eval_str=NULL;
}
return;
}
int
flush_list_evals( const char *list_name )
{
struct config_list *clp;
int rv=0;
clp = get_config_list( list_name, 0 );
if (clp)
{
dl_Walk_List( &clp->cl_Items,
(dl_Walk_List_t)flush_this_eval,
NULL );
rv=1;
}
return(rv);
}
static void
display_list_item( struct config_item *cip, FILE *fh )
{
fprintf( fh, "Item Key: %s\n", cip->ci_name );
fprintf( fh, " Value: %s\n", cip->ci_val );
if (cip->eval_str)
fprintf( fh, " Eval: %s\n", cip->eval_str );
return;
}
int
dump_private_contents( const char *list_name, FILE *fh )
{
struct config_list *clp;
int rv=0;
clp = get_config_list( list_name, 0 );
if (clp)
{
rv=1;
fprintf( fh, "List Name: %s\n", clp->cl_name );
fprintf( fh, " Time: %s\n", make_timestamp_str( NULL ) );
dl_Walk_List( &clp->cl_Items,
(dl_Walk_List_t)display_list_item,
fh );
}
return(rv);
}
/* FIXME - need to create structure with disp_func and param,
have a private copy in report_private_contents
populate on entry, they retrieve in display_list_item
*/
static void *t_param;
static void
report_private_item( struct config_item *cip,
config_disp_t disp_func )
{
(* disp_func)( cip->ci_name, cip->ci_val, cip->eval_str, t_param );
return;
}
int
report_private_contents( const char *list_name,
config_disp_t disp_func,
void *param )
{
struct config_list *clp;
int rv=0;
clp = get_config_list( list_name, 0 );
if (clp)
{
rv=1;
t_param = param;
dl_Walk_List( &clp->cl_Items,
(dl_Walk_List_t)report_private_item,
(void *)disp_func );
}
return(rv);
}
int
read_private_string_array( const char *list_name, const char *conf_str[] )
{
int carg = 0;
int rv=0;
while ( conf_str[carg] )
rv += read_private_string( list_name, conf_str[carg++] );
return(rv);
}
int
read_private_file( const char *list_name, const char *fname )
{
int rv=0;
char tbuf[500];
FILE *fh;
if ( (fh=fopen(fname,"r")) )
{
(void)flush_list_evals( list_name );
while(fgetline2(fh,tbuf,500)==0)
{
/* might mean something */
(void)read_private_string( list_name, tbuf );
};
(void)fclose(fh);
rv=1;
}
return(rv);
}
struct config_item *
get_private_config( const char *list_name, const char *key )
{
struct config_list *clp;
struct config_item *cip;
if ( (clp = get_config_list( list_name, 0 )) )
cip = dl_Find_Item_By_Name( &clp->cl_Items, key );
else
cip = NULL;
return(cip);
}
int
raw_private_string( const char *list_name, const char *key, char *value )
{
int rv=0;
struct config_item *cip;
if ( (cip = get_private_config( list_name, key )) )
{
rv = 1;
strcpy( value, cip->ci_val );
}
return(rv);
}
char *
get_private_string( const char *list_name, const char *key )
{
static char tbuf[MAX_CONFIG_STR];
char *rv=NULL;
struct config_item *cip;
if ( (cip = get_private_config( list_name, key )) )
{
strcpy( tbuf, cip->ci_val );
rv = tbuf;
}
return( rv );
}
int
get_private_int( const char *list_name, const char *key )
{
struct config_item *cip;
int rv=0;
if ( (cip = get_private_config( list_name, key )) )
{
rv = atoi( cip->ci_val );
}
return(rv);
}
double
get_private_double( const char *list_name, const char *key )
{
struct config_item *cip;
double rv=0.0;
if ( (cip = get_private_config( list_name, key )) )
{
rv = atof( cip->ci_val );
}
return(rv);
}
int
get_private_flag( const char *list_name, const char *key )
{
struct config_item *cip;
int rv=0;
if ( (cip = get_private_config( list_name, key ))
&& ( strcasecmp(cip->ci_val,"TRUE") == 0
|| strcasecmp(cip->ci_val,"ON") == 0
|| strcasecmp(cip->ci_val,"YES") == 0
|| strcasecmp(cip->ci_val,"AFFIRMATIVE") == 0
|| strcasecmp(cip->ci_val,"POSITIVE") == 0
|| strcasecmp(cip->ci_val,"DA") == 0
|| atoi(cip->ci_val) > 0
)
)
rv = 1;
return(rv);
}
int
set_private_int( const char *list_name, const char *key, int newval )
{
char tbuf[20];
sprintf( tbuf, "%d", newval );
return( set_private_string( list_name, key, tbuf ) );
}
int
set_private_double( const char *list_name, const char *key, double newval )
{
char tbuf[20];
sprintf( tbuf, "%f", newval );
return( set_private_string( list_name, key, tbuf ) );
}
int
set_private_flag( const char *list_name, const char *key, int newval )
{
return( set_private_string( list_name, key,
(newval)?"TRUE":"FALSE" ) );
}
int
get_list_flags( const char *list_name )
{
struct config_list *clp;
int rv;
if ( (clp = get_config_list( list_name, 0 )) )
rv = clp->cl_flags;
else
rv=0;
return(rv);
}
int
set_list_flags( const char *list_name, int new_val )
{
struct config_list *clp;
int rv;
if ( (clp = get_config_list( list_name, 0 )) )
{
rv = clp->cl_flags;
clp->cl_flags=new_val;
}
else
rv=0;
return(rv);
}
char *
eval_private_str( const char *list_name, const char *from )
{
static char tbuf[500];
char buf2[500];
char *rto = tbuf;
char *ep, *ep2;
int do_getenv,fallback_env,fallback_config;
while ( *from )
{
if ( *from == '$' || *from == '%' )
{
do_getenv = ( *from == '$' );
/* something to do */
from++;
fallback_env = fallback_config = 0;
if ( *from == '$' && !do_getenv )
{
fallback_env = 1;
from++;
}else if ( *from == '%' && do_getenv )
{
fallback_config = 1;
from++;
}
/* we are now pointing at the environment name,
we copy all characters [a-zA-z_-\.:] into the
enquire string
*/
ep = buf2;
if (*from == '(' || *from == '{')
{
char close;
close = (*from == '(')?')':'}';
from++;
/* read until corresponding close char */
while ( *from && *from != close )
*ep++ = *from++;
from++;
}else
{
while ( *from &&
( isalpha(*from) || isdigit(*from) ||
strchr( "-_.:", *from )
)
)
*ep++ = *from++;
}
*ep = '\0';
/* now get the value from the environment */
if (do_getenv)
ep2 = getenv( buf2 );
else
ep2 = get_private_string( list_name, buf2 );
if ((!ep2 || !*ep2) && (fallback_env || fallback_config) )
{
if (fallback_env)
ep2 = getenv( buf2 );
else
ep2 = get_private_string( list_name, buf2 );
}
if (ep2)
while ( *ep2 )
*rto++ = *ep2++;
}else
while ( *from && *from != '$' && *from != '%' )
*rto++ = *from++;
}
/* And terminate the buffer */
*rto = '\0';
return(tbuf);
}
char *
eval_private_default( const char *list_name,
const char *config_name,
const char *def_name )
{
char *cp;
struct config_item *cip;
if ( (cip = get_private_config( list_name, config_name )) )
{
if (cip->eval_str)
cp = cip->eval_str;
else
{
cp = eval_private_str( list_name, cip->ci_val );
if (BITTST(get_list_flags(list_name), CONFIG_NO_EVAL)==0)
{
cip->eval_str = strdup(cp);
if (cip->eval_str)
cp = cip->eval_str;
}
}
}else if ( def_name )
{
cp = eval_private_str( list_name, def_name );
}else
cp = NULL;
return( cp );
}
/* -- End of File -- */

97
libsrc/cfg_watch.c Normal file
View file

@ -0,0 +1,97 @@
/*
*******************************************************************************
* Copyright (c) 1997 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/cfg_file.h>
#include <mplib1/fprintfile.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
static char *cfg_name=NULL;
static struct stat config_stat;
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
watch_cfg_file( const char *config_name )
{
int rv=1;
if (cfg_name)
free(cfg_name);
cfg_name = strdup(config_name);
if (cfg_name)
{
config_stat.st_mtime = (time_t)0;
rv = stat( cfg_name, &config_stat );
}
return(rv);
}
int
check_cfg_file( int force )
{
struct stat tstat;
int reread=0;
if (cfg_name)
{
if ( stat(cfg_name, &tstat)==0
&& tstat.st_mtime > config_stat.st_mtime
)
{
read_config_file( cfg_name );
memcpy( &config_stat, &tstat, sizeof(struct stat) );
fprintfile( stderr, "Config file change read\n" );
reread=1;
}else if (force)
{
read_config_file( cfg_name );
fprintfile( stderr, "Config file read (force)\n" );
reread=1;
}
}
return(reread);
}
/* -- End of File -- */

123
libsrc/cpustopwatch.c Normal file
View file

@ -0,0 +1,123 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#ifdef RUSAGE_IN_UCBLIB
#include </usr/ucbinclude/sys/resource.h>
#else
#include <sys/resource.h>
#endif
#include <mplib1/mplib1_config.h>
#include <mplib1/stopwatch.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifndef RUSAGE_SELF
/* Last ditch variation, in case nothing else works */
#define RUSAGE_SELF 1
#define RUSAGE_CHILDREN 2
struct rusage {
struct timeval ru_utime;
struct timeval ru_stime;
};
#endif
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
init_cpu_stopwatch( struct cpu_stopwatch *cpu_p )
{
if (cpu_p)
memset( cpu_p, '\0', sizeof(struct cpu_stopwatch) );
return(0);
}
int
start_cpu_stopwatch( struct cpu_stopwatch *cpu_p )
{
struct rusage start_usage;
getrusage( RUSAGE_SELF, &start_usage );
memcpy( &cpu_p->u_timing.start_time,
&start_usage.ru_utime,
sizeof(struct timeval) );
memcpy( &cpu_p->s_timing.start_time,
&start_usage.ru_stime,
sizeof(struct timeval) );
return(0);
}
int
stop_cpu_stopwatch( struct cpu_stopwatch *cpu_p )
{
struct rusage end_usage;
getrusage( RUSAGE_SELF, &end_usage );
accum_stop_timevals( &cpu_p->u_timing, &end_usage.ru_utime );
accum_stop_timevals( &cpu_p->s_timing, &end_usage.ru_stime );
return(0);
}
int
accrete_cpu_stopwatch( struct cpu_stopwatch *cpu_p_into,
struct cpu_stopwatch *cpu_p_from )
{
add_timevals( &cpu_p_into->u_timing.cumulative_time,
&cpu_p_from->u_timing.cumulative_time );
add_timevals( &cpu_p_into->s_timing.cumulative_time,
&cpu_p_from->s_timing.cumulative_time );
return(0);
}
char *
display_cpu_stopwatch( struct cpu_stopwatch *cpu_p, int mode )
{
display_stopwatch( &cpu_p->u_timing, mode );
display_stopwatch( &cpu_p->s_timing, mode );
sprintf( cpu_p->elps_str, "USR: %s CPU: %s",
cpu_p->u_timing.elps_str,
cpu_p->s_timing.elps_str );
return(0);
}
/* -- End of File -- */

114
libsrc/daemonloop.c Normal file
View file

@ -0,0 +1,114 @@
/*
*******************************************************************************
* Copyright (c) 1997 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <mplib1/cfg_file.h>
#include <mplib1/daemon.h>
/* ------------------------------------------------------------------
structures / defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
mp_daemon_loop( int poll_fd,
int(*poll_func)(int),
int(*u1_func)(int),
int(*u2_func)(int),
int(*int_func)(int),
int(*term_func)(int),
int flags )
{
int rv=0,t,poll_period;
/* This function provides a standard daemon loop.
It sleeps for the specified period (unless awoken early),
and then calls the relevant dispatch function.
Any dispatch function that returns non-zero causes the loop
to exit. The dispatch function called will have two parameters.
The first if the signal that caused the call (or zero), the
second, the return value from the sleep call
*/
do
{
poll_period = get_config_int( "POLL_PERIOD" );
if (poll_period<1)
poll_period=60;
switch(t=check_signalling())
{
case SIGINT :
if (int_func)
rv = (*int_func)( t );
else
rv = t;
break;
case SIGTERM :
if (term_func)
rv = (*term_func)( t );
else
rv = t;
break;
case SIGUSR1 :
if (u1_func)
rv = (*u1_func)( t );
else
rv = 0;
break;
case SIGUSR2 :
if (u2_func)
rv = (*u2_func)( t );
else
rv = 0;
break;
case SIGHUP :
restart_files();
break;
default :
rv = poll_func( 0 );
break;
}
if (rv==0)
t = mp_daemon_sleep( poll_fd, poll_period );
}while (rv==0);
return(rv);
}
/* -- End of File -- */

98
libsrc/daemonsleep.c Normal file
View file

@ -0,0 +1,98 @@
/*
*******************************************************************************
* Copyright (c) 1997 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <mplib1/mplib1_config.h>
#ifdef INCLUDE_SYS_SELECT
#include <sys/select.h>
#endif
#include <mplib1/dl_list.h>
#include <mplib1/bpo_proc.h>
#include <mplib1/daemon.h>
/* ------------------------------------------------------------------
structures / defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
mp_daemon_sleep( int poll_fd, int how_long )
{
struct timeval sleep_period;
fd_set readset;
int rv;
if (poll_fd != -1)
{
FD_ZERO( &readset );
FD_SET( poll_fd, &readset );
sleep_period.tv_sec = how_long;
sleep_period.tv_usec = 0;
allow_sysint( );
rv = select( poll_fd+1, &readset, NULL, NULL, &sleep_period );
if(rv==1)
{
/* read the byte from the fifo */
char tc;
read( poll_fd, &tc, 1 );
}
deny_sysint( );
}else
{
sleep_period.tv_sec = how_long;
sleep_period.tv_usec = 0;
allow_sysint( );
rv = select( 0, NULL, NULL, NULL, &sleep_period );
deny_sysint( );
}
return(rv);
}
/* -- End of File -- */

428
libsrc/dl_list.c Normal file
View file

@ -0,0 +1,428 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose : Double-linked list handling
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/dl_list.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
dl_Node_t *
dl_Init_Node( dl_Node_t *node, const char *name, const void *item )
{
node->ln_Succ = NULL;
node->ln_Pred = NULL;
node->ln_Name = (char *)(size_t)name;
node->ln_Item = (void *)(size_t)item;
node->ln_List = NULL;
return(node);
}
dl_List_t *
dl_Init_List( dl_List_t *list, int flags )
{
if (list)
{
(void)dl_Init_Node( &list->ln_Head, NULL, NULL );
(void)dl_Init_Node( &list->ln_Tail, NULL, NULL );
list->ln_Head.ln_List = list;
list->ln_Tail.ln_List = list;
list->ln_Flags = flags;
list->ln_Head.ln_Pred = NULL;
list->ln_Head.ln_Succ = &list->ln_Tail;
list->ln_Tail.ln_Pred = &list->ln_Head;
list->ln_Tail.ln_Succ = NULL;
}
return(list);
}
dl_Node_t *
dl_Remove_Node( dl_Node_t *node1 )
{
if (node1)
{
if (node1->ln_Succ && node1->ln_Succ->ln_Pred == node1)
node1->ln_Succ->ln_Pred = node1->ln_Pred;
if (node1->ln_Pred && node1->ln_Pred->ln_Succ == node1)
node1->ln_Pred->ln_Succ = node1->ln_Succ;
node1->ln_Succ = NULL;
node1->ln_Pred = NULL;
}
return(node1);
}
dl_Node_t *
dl_Remove_Head( dl_List_t *list )
{
dl_Node_t *node=NULL;
if (list->ln_Head.ln_Succ != &list->ln_Tail)
node = dl_Remove_Node(list->ln_Head.ln_Succ);
return(node);
}
dl_Node_t *
dl_Remove_Tail( dl_List_t *list )
{
dl_Node_t *node=NULL;
if (list->ln_Tail.ln_Pred != &list->ln_Head)
node = dl_Remove_Node(list->ln_Tail.ln_Pred);
return(node);
}
dl_Node_t *
dl_Add_Node_After( dl_Node_t *node1, dl_Node_t *node2 )
{
node2->ln_Succ = node1->ln_Succ;
node2->ln_Pred = node1;
node1->ln_Succ->ln_Pred = node2;
node1->ln_Succ = node2;
return(node2);
}
dl_Node_t *
dl_Add_Node_Before( dl_Node_t *node1, dl_Node_t *node2 )
{
node2->ln_Succ = node1;
node2->ln_Pred = node1->ln_Pred;
node1->ln_Pred->ln_Succ = node2;
node1->ln_Pred = node2;
return(node2);
}
dl_Node_t *
dl_Add_Head( dl_List_t *list, dl_Node_t *node )
{
(void)dl_Remove_Node(node);
(void)dl_Add_Node_After( &list->ln_Head, node );
node->ln_List = list;
return(node);
}
dl_Node_t *
dl_Add_Tail( dl_List_t *list, dl_Node_t *node )
{
(void)dl_Remove_Node(node);
(void)dl_Add_Node_Before( &list->ln_Tail, node );
node->ln_List = list;
return(node);
}
void *
dl_Find_Item_By_Name( dl_List_t *list, const char *name )
{
void *item=NULL;
dl_Node_t *node;
if (name && *name)
{
node = list->ln_Head.ln_Succ;
/* walk the list until we find the matching entry */
while (node->ln_Succ && item == NULL)
{
if ( node->ln_Name
&& (strcmp(name,node->ln_Name)==0)
)
item = (void *)node->ln_Item;
node = node->ln_Succ;
};
}
return(item);
}
void *
dl_Find_Next_Item_By_Name( dl_Node_t *node, const char *name )
{
void *item=NULL;
if (name && *name)
{
node = node->ln_Succ;
/* walk the list until we find the matching entry */
while (node->ln_Succ && item == NULL)
{
if ( node->ln_Name
&& (strcmp(name,node->ln_Name)==0)
)
item = (void *)node->ln_Item;
node = node->ln_Succ;
};
}
return(item);
}
dl_Node_t *
dl_Find_Node_By_Item( dl_List_t *list, const void *item )
{
dl_Node_t *node,*rnode=NULL;
node = list->ln_Head.ln_Succ;
while (node->ln_Succ && rnode == NULL)
{
if (node->ln_Item == item)
rnode = node;
node = node->ln_Succ;
};
return(rnode);
}
void *
dl_Remove_Head_Item( dl_List_t *list )
{
dl_Node_t *node=NULL;
if (list->ln_Head.ln_Succ != &list->ln_Tail)
node = dl_Remove_Node(list->ln_Head.ln_Succ);
return( (void *)((node)?node->ln_Item:NULL) );
}
void *
dl_Remove_Tail_Item( dl_List_t *list )
{
dl_Node_t *node=NULL;
if (list->ln_Tail.ln_Pred != &list->ln_Head)
node = dl_Remove_Node(list->ln_Tail.ln_Pred);
return( (void *)((node)?node->ln_Item:NULL) );
}
int
dl_Walk_List( dl_List_t *l_ptr,
dl_Walk_List_t disp,
void *param )
{
dl_Node_t *n_ptr,*nn_ptr;
n_ptr = l_ptr->ln_Head.ln_Succ;
while (n_ptr->ln_Succ)
{
/* save the next pointer just in case they mash the list */
nn_ptr = n_ptr->ln_Succ;
(*disp)( (void *)n_ptr->ln_Item, param );
if (n_ptr == nn_ptr)
break;
n_ptr = nn_ptr;
};
return(0);
}
int
dl_Walk_List_Name( dl_List_t *l_ptr,
const char *name,
dl_Walk_List_Name_t disp,
void *param )
{
dl_Node_t *n_ptr,*nn_ptr;
int rv=0;
n_ptr = l_ptr->ln_Head.ln_Succ;
while (n_ptr->ln_Succ && rv==0 )
{
/* save the next pointer just in case they mash the list */
nn_ptr = n_ptr->ln_Succ;
if ( n_ptr->ln_Name
&& (strcmp(name,n_ptr->ln_Name)==0)
)
rv = (*disp)( (void *)n_ptr->ln_Item, param );
if (n_ptr == nn_ptr)
break;
n_ptr = nn_ptr;
};
return(rv);
}
int
dl_Transfer_Lists( dl_List_t *fl_ptr, dl_List_t *tl_ptr )
{
dl_Node_t *n_ptr, *np2=NULL;
int rv=0;
while( (n_ptr=dl_Remove_Head( fl_ptr )) )
{
if (np2==n_ptr)
break; /* Problem with list */
np2=n_ptr;
(void)dl_Add_Tail( tl_ptr, n_ptr );
rv++;
}
return(rv);
}
int
dl_Any_In_List( dl_List_t *list )
{
return( (list->ln_Head.ln_Succ->ln_Succ != NULL) );
}
int
dl_Walk_List_By_Node( dl_List_t *l_ptr,
dl_Walk_List_Node_t disp,
void *param )
{
dl_Node_t *n_ptr,*nn_ptr;
int rv=0;
n_ptr = l_ptr->ln_Head.ln_Succ;
while (n_ptr->ln_Succ && rv==0)
{
/* save the next pointer just in case they mash the list */
nn_ptr = n_ptr->ln_Succ;
rv = (*disp)( n_ptr, param );
n_ptr = nn_ptr;
};
return(rv);
}
int
dl_Free_List_Contents( dl_List_t *fl_ptr )
{
dl_Node_t *n_ptr, *np2=NULL;
int rv=0;
while( (n_ptr=dl_Remove_Head( fl_ptr )) )
{
if (np2==n_ptr)
break; /* Problem with list */
if( n_ptr->ln_Item )
free( (void *)n_ptr->ln_Item );
else
free( n_ptr );
np2=n_ptr;
rv++;
}
return(rv);
}
int
dl_Walk_List2( dl_List_t *l_ptr,
dl_Walk_List2_t disp,
void *param )
{
dl_Node_t *n_ptr,*nn_ptr;
int rv = 0;
n_ptr = l_ptr->ln_Head.ln_Succ;
while (n_ptr->ln_Succ && rv==0 )
{
/* save the next pointer just in case they mash the list */
nn_ptr = n_ptr->ln_Succ;
rv = (*disp)( (void *)n_ptr->ln_Item, param );
if (n_ptr==nn_ptr)
break;
n_ptr = nn_ptr;
};
return(rv);
}
static void
dl_Free_Node_private( dl_Node_t *nptr, int *flags )
{
if ( (*flags & DL_FREE_NODES )
|| (*flags & DL_REMOVE_NODES)
)
dl_Remove_Node( nptr );
if ( (*flags & DL_FREE_NAMES)
&& nptr->ln_Name
)
{
free( (void *)nptr->ln_Name );
nptr->ln_Name = NULL;
}
if ( (*flags & DL_FREE_ITEMS)
&& nptr->ln_Item
)
{
void *vp; /* just in case the node is in the item */
vp = nptr->ln_Item;
nptr->ln_Item = NULL;
free( vp );
}
if ( *flags & DL_FREE_NODES )
{
free( nptr );
}
return;
}
void
dl_Free_Node( dl_Node_t *nptr, int flags )
{
dl_Free_Node_private( nptr, &flags );
return;
}
void
dl_Free_List( dl_List_t *fl_ptr, int flags )
{
dl_Walk_List( fl_ptr, (dl_Walk_List_t)dl_Free_Node_private, (void *)&flags );
return;
}
/* -- End of File -- */

940
libsrc/dl_lru.c Normal file
View file

@ -0,0 +1,940 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/mpstrtok.h>
#include <mplib1/dl_list.h>
#include <mplib1/dl_lru.h>
#include <mplib1/data_align.h>
#include "../include/dl_lru_private.h"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
struct vchar_gen
{
unsigned short len;
unsigned char arr[1];
};
typedef struct vchar_gen *vchar_ptr;
struct cps
{
struct Cache_List *cl;
int nrl;
struct full_search_rule *srp;
void **sv;
struct Cache_Item *ci;
struct Cache_Item *si;
struct Cache_Item *rv;
};
/* ------------------------------------------------------------------
Some static variables
------------------------------------------------------------------ */
static List_t *Master_List=NULL;
static int default_flags=CACHE_USE_DEFAULT;
#ifdef CACHE_DEBUG
static int cache_debug=0;
#endif
#define SEARCH_MISSING_LIST BIT(0)
#define SEARCH_FREE_LIST BIT(1)
#define SEARCH_LRU_LIST BIT(2)
#define SEARCH_ALL_LISTS (SEARCH_MISSING_LIST|SEARCH_FREE_LIST|SEARCH_LRU_LIST)
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
struct Full_List *
Init_Full_List ( struct Full_List *list, const char *name, int flags )
{
size_t ms=(size_t)0;
char *mp=NULL;
if ( list==NULL )
ms += FULL_LIST_SIZE;
if ( name )
ms += (size_t)(strlen(name) + 1);
if ( ms
&& ( mp = (char *)malloc( ms )) == NULL
)
return(NULL);
if ( list==NULL )
{
list = (struct Full_List *) mp;
mp += FULL_LIST_SIZE;
}
if ( name )
{
strcpy( mp , name );
name = mp;
}
Init_List( &list->fl_Search_List, flags );
Init_List( &list->fl_LRU_List, flags );
list->fl_Name = name;
return(list);
}
void *
Find_Full_Item ( struct Full_List *flist, const char *name )
{
void *item;
dl_Node_t *node;
if ( (item = Find_Item_By_Name( &flist->fl_Search_List, name )) )
{
if( (node = Find_Node_By_Item( &flist->fl_LRU_List, item )) )
{
Add_Head( &flist->fl_LRU_List, node );
}
}
return(item);
}
static int
Local_Cache_Init( List_t **cml )
{
List_t *ml=*cml;
int rv=0;
static int init_done=0;
if ( (ml == NULL)
&& (ml = (List_t *)malloc(LIST_SIZE))
)
{
*cml = ml;
Init_List ( ml, 0 );
init_done = 1;
rv=1;
}
return(rv);
}
List_t *
Get_Cache_Master_List( void )
{
Local_Cache_Init(&Master_List);
return( Master_List );
}
static int
Cache_Flag_Gen( int new_flags, int alt_flags )
{
int cl_flags=CACHE_USE_DEFAULT;
int t_flags;
/* the object here is to generate a set of cache flags
that is the composite of the default and the new
and that there is a bit set in each grouping
In order for the lines to read simply (and since they
are just variations of each other) a macro will now be
defined
*/
#define C_MODE(r,n,a,t,m,d) {t= (n & m) ? (n & m) : (a & m);if (t==m) t= (d & m); r |= t;}
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_MODE_MASK,CACHE_DEFAULTS);
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_CASE_MASK,CACHE_DEFAULTS);
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_ALLOC_MASK,CACHE_DEFAULTS);
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_MISS_MASK,CACHE_DEFAULTS);
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_INSERT_MASK,CACHE_DEFAULTS);
C_MODE(cl_flags,new_flags,alt_flags,t_flags,CACHE_FLUSH_MASK,CACHE_DEFAULTS);
return(cl_flags);
}
int Cache_Init( int def_flags)
{
if (default_flags == CACHE_USE_DEFAULT)
{
default_flags = Cache_Flag_Gen( def_flags, CACHE_DEFAULTS );
#ifdef CACHE_DEBUG
if (def_flags & 0x40000000)
{
cache_debug=1;
fprintf(stderr,"cache debug is on\n");
}
#endif
}
return(Local_Cache_Init(&Master_List));
}
struct Cache_Item *
Cache_Find_Simple_Item( struct Cache_List *cl, const char *list_key, int *rv )
{
struct Cache_Item *ci;
ci = (struct Cache_Item *) Find_Full_Item( &cl->cl_Items, list_key );
if (ci)
{
*rv = CACHE_FOUND_ITEM;
}else
{
/* check the complete miss list */
ci = (struct Cache_Item *) Find_Item_By_Name( &cl->cl_Missing, list_key );
*rv = (ci) ? CACHE_COMPLETE_MISS : CACHE_MISSED;
ci=NULL;
}
return(ci);
}
int
Find_Cache_Item( const char *list_name,
const void *list_key,
const char *field_list, ... )
{
int rv=CACHE_MISSED;
struct Cache_List *cl;
struct Cache_Item *ci;
struct Cache_Field *cf;
va_list ap;
void *vp,*ftok1;
char *cp;
char *field_list_copy;
vchar_ptr vcp1,vcp2;
static char sep_list[]=" \t\r\n,";
if (Master_List==NULL)
Local_Cache_Init(&Master_List); /* just in case we haven't done it before */
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Find_Cache_Item: <%s> <%p> ", list_name, list_key );
#endif
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if (cl)
{
if ( cl->cl_search_rules != NULL )
{
ci = Cache_Find_Requested_Item( cl, list_key, &rv );
}else
{
ci = Cache_Find_Simple_Item( cl, list_key, &rv );
/* ci = (struct Cache_Item *) Find_Full_Item( &cl->cl_Items, list_key );*/
}
if ( ci != NULL )
{
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Found\n");
#endif
/* now to transfer the relevant fields
we do this by parsing the field list using strtok,
and then finding the named field in the cf list,
and then finding the item field with the corresponding field_num
the value is then returned into the next vararg
*/
cl->cl_cache_hits++;
if (cl->cl_flags & CACHE_CACHE_ON)
{
field_list_copy = strdup(field_list);
va_start(ap,field_list);
cp=mpstrtok(field_list_copy,&ftok1,sep_list);
while (cp)
{
vp = va_arg(ap, void* );
/* find this in the cf list */
cf = (struct Cache_Field *)Find_Item_By_Name( &cl->cl_Fields, cp );
if (cf)
{
/* now generate a pointer to the data in the data segment */
cp = (char *)(ci->ci_Item) + cf->cf_f_offset;
/* we know where it is and what it is, so copy it */
switch(cf->cf_field_type)
{
case CF_INT :
*((int *)vp) = *((int *)cp);
break;
case CF_DOUBLE :
*((double *)vp) = *((double *)cp);
break;
case CF_CHAR :
*((char *)vp) = *cp;
break;
case CF_STRING :
strcpy( (char *)vp, cp );
break;
case CF_VARCHAR :
vcp1 = (vchar_ptr)vp;
vcp2 = (vchar_ptr)cp;
vcp1->len = vcp2->len;
memcpy(vcp1->arr, vcp2->arr, vcp2->len );
break;
}
}
rv=CACHE_FOUND_ITEM;
cp = mpstrtok( NULL, &ftok1, sep_list);
};
(void)mpstrtok( NULL, &ftok1, NULL );
va_end( ap );
}
}else
{
cl->cl_cache_misses++;
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Not Found\n");
#endif
}
}
#ifdef CACHE_DEBUG
else if (cache_debug)
fprintf(stderr," List not Found\n");
#endif
return(rv);
}
static int
Init_Item( struct Cache_Item *ci,
struct Cache_List *cl,
char *new_name,
size_t name_len )
{
if (ci && cl)
{
/* inititalise the various parts of this beast */
Init_Node( &ci->ci_S_Node, new_name, ci );
Init_Node( &ci->ci_L_Node, new_name, ci );
ci->ci_Name = new_name;
ci->ci_str_size = name_len;
ci->ci_Item = (void *) (((char *)ci) + CACHE_ITEM_SIZE);
/* cl->cl_curr_items++;*/
/* Add_Head( &cl->cl_Items.fl_LRU_List, &ci->ci_L_Node );*/
/* Add_Head( &cl->cl_Items.fl_Search_List, &ci->ci_S_Node );*/
}
return(0);
}
void *
Cache_Alloc_Lump( size_t sz, const char *name, char **new_name )
{
void *vp;
char *np;
size_t osz = sz;
if (name)
sz += (size_t)(strlen(name) + 1);
vp = (void *)malloc( sz );
if (vp)
{
memset( vp, '\0', sz );
if (name)
{
np = (char *)vp + osz;
strcpy(np,name);
if (new_name)
*new_name = np;
}
}
return(vp);
}
static int
Alloc_Many( struct Cache_List *cl, size_t key_size )
{
struct Cache_Item *ci;
size_t osz,asz;
int ni,rv=0;
char *cp,*np;
if ( cl->cl_max_items > 0 )
{
if (key_size < 1)
key_size = 40;
osz = CACHE_ITEM_SIZE + cl->cl_data_size + key_size + 1;
osz += (osz & 1); /* adjust object size to next word boundary */
asz = osz * cl->cl_max_items;
if ( (cp=malloc(asz)) )
{
memset( cp, '\0', asz );
/* now init each item and store on list */
ni = cl->cl_max_items;
while(ni--)
{
ci = (struct Cache_Item *)cp;
np = cp + CACHE_ITEM_SIZE + cl->cl_data_size;
Init_Item( ci, cl, np, key_size );
Add_Head( &cl->cl_Free, &ci->ci_S_Node );
cp += osz;
};
}
}
return(rv);
}
struct Cache_List *
New_Cache_List( const char *list_name, int max_items,
int flags, int defaults, int last_ditch )
{
struct Cache_List *cl;
char *new_name;
cl = Cache_Alloc_Lump( CACHE_LIST_SIZE, list_name, &new_name );
if (cl)
{
/* inititalise the various parts of this beast */
Init_Node( &cl->cl_Node, new_name, cl );
cl->cl_Name = new_name;
/* now generate the cl-flags */
cl->cl_flags = Cache_Flag_Gen( Cache_Flag_Gen( flags, defaults ), last_ditch );
Init_List( &cl->cl_Fields, (cl->cl_flags & CACHE_IGNORE_CASE)?LN_IGNORECASE:0 );
Init_List( &cl->cl_Free, 0 );
Init_List( &cl->cl_Free_cgi, 0 );
Init_List( &cl->cl_Build, 0 );
Init_List( &cl->cl_Missing, 0 );
Init_Full_List( &cl->cl_Items, NULL,
((cl->cl_flags & CACHE_IGNORE_CASE)?LN_IGNORECASE:0) );
cl->cl_max_field_num = 0;
cl->cl_max_items = max_items;
cl->cl_curr_items = 0;
cl->cl_cache_replaces = 0;
cl->cl_cache_hits = 0;
cl->cl_cache_misses = 0;
cl->cl_complete_misses = 0;
cl->cl_data_size = 0;
cl->cl_search_rules = NULL;
}
return(cl);
}
int
Cache_Build_Field_List( struct Cache_List *cl,
const char *format_str,
const char *field_names )
{
int rv=0;
struct Cache_Field *cf;
char *fnames = NULL;
char *fstr = NULL;
char *cp,*cp2;
void *ftok1,*ftok2;
static char fs_sep[]="%";
static char fn_sep[]=",";
int dsz=0; /* count up the space used by the data */
int psz; /* parameter size so far */
int ft; /* field type */
int flags; /* Various flags. eg Ignore case when matching? */
int align;
if ( (fstr = strdup(format_str))
&& (fnames = strdup(field_names))
)
{
/* Now parse and allocate Field structures */
cp = mpstrtok( fstr, &ftok1, fs_sep );
cp2 = mpstrtok( fnames, &ftok2, fn_sep );
while (cp && cp2)
{
/* grab any size specifier */
psz = 0;
ft = 0;
flags = 0;
align=0;
while(isdigit(*cp))
psz = psz * 10 + (*cp++ & 0x0f);
if (*cp=='i' || *cp=='I')
{
flags |= CF_FLG_IGNORECASE;
cp++;
}
switch(*cp)
{
case 's' :
ft = CF_STRING;
if (psz == 0)
psz = 40;
break;
case 'c' :
ft = CF_CHAR;
psz = sizeof(char);
flags &= ~CF_FLG_IGNORECASE;
align=MPLIB_ALIGN_SPC_CHAR;
break;
case 'd' :
case 'x' :
ft = CF_INT;
psz = sizeof(int);
flags &= ~CF_FLG_IGNORECASE;
align=MPLIB_ALIGN_SPC_INT;
break;
case 'f' :
ft = CF_DOUBLE;
psz = sizeof(double);
flags &= ~CF_FLG_IGNORECASE;
align=MPLIB_ALIGN_SPC_DOUBLE;
break;
case 'S' :
ft = CF_VARCHAR;
if (psz == 0)
psz = 40;
psz += sizeof(unsigned short);
break;
}
if ( ft
&& (cf = Cache_Alloc_Lump( CACHE_FIELD_SIZE, cp2, &cp ))
)
{
/* do something with this */
Init_Node( &cf->cf_Node, cp, cf );
cf->cf_Name = cp;
cf->cf_field_num = cl->cl_max_field_num++;
cf->cf_field_type = ft;
if (align && (dsz & (align-1)))
{
/* Adjust data position to ensure correct alignment */
dsz = (dsz + align -1) & ~(align-1);
}
cf->cf_f_offset = dsz;
cf->cf_field_size = psz;
cf->cf_field_flags = flags;
dsz += ( (psz + 1) & ~1); /* adjust size to next word boundary */
cl->cl_data_size = dsz;
Add_Tail( &cl->cl_Fields, &cf->cf_Node );
rv = 1;
}else
{
/* Something wrong, throw everything away and return error */
while ( (cf=Remove_Head_Item(&cl->cl_Fields)) )
free(cf);
rv = 0;
break;
}
cp = mpstrtok( NULL, &ftok1, fs_sep );
cp2 = mpstrtok( NULL, &ftok2, fn_sep );
};
(void) mpstrtok( NULL, &ftok1, NULL );
(void) mpstrtok( NULL, &ftok2, NULL );
}
if (fstr)
free(fstr);
if (fnames)
free(fnames);
return(rv);
}
int
Create_Cache_List( const char *list_name, int max_items,
int list_flags, size_t key_size,
const char *format_str, const char *field_names )
{
int rv=0;
struct Cache_List *cl;
Local_Cache_Init(&Master_List); /* just in case we haven't done it before */
#ifdef CACHE_DEBUG
if (cache_debug)
{
fprintf(stderr,"Create_Cache_List: <%s> <%d> <%s> <%s> ",
list_name,max_items,format_str,field_names);
fflush(stderr);
}
#endif
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if ( cl == NULL
&& (cl=New_Cache_List( list_name, max_items,list_flags, default_flags, CACHE_DEFAULTS ))
)
{
rv = Cache_Build_Field_List( cl, format_str, field_names );
if (rv==1 && (cl->cl_flags & CACHE_PRE_ALLOCATE) && cl->cl_max_items > 0 )
{
/* time to pre-allocate the cache items */
Alloc_Many( cl, key_size );
}
if (rv==1)
Add_Head( Master_List, &cl->cl_Node );
}
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"%s\n",(rv)?"successful":"failed");
#endif
return(rv);
}
static struct Cache_Item *
New_Cache_Item( struct Cache_List *cl, char *item_name )
{
struct Cache_Item *ci;
char *new_name;
ci = Cache_Alloc_Lump( CACHE_ITEM_SIZE + cl->cl_data_size, item_name, &new_name );
if (ci)
{
/* inititalise the various parts of this beast */
Init_Item( ci, cl, new_name, strlen(new_name) );
}
return(ci);
}
static struct Cache_Item *
Obtain_Cache_Item( struct Cache_List *cl, const char *list_key,
List_t *L_List, int i_flags )
{
struct Cache_Item *ci=NULL;
/* anything on the free queue? */
if ( (i_flags & SEARCH_MISSING_LIST)
&& (cl->cl_search_rules==NULL)
&& list_key
)
ci = Find_Item_By_Name( &cl->cl_Missing, list_key );
if ( ci==NULL && (i_flags & SEARCH_FREE_LIST) )
ci = Remove_Head_Item( &cl->cl_Free );
if (ci)
{
/* adjust ? */
cl->cl_curr_items++;
if (list_key && strlen(list_key) > ci->ci_str_size )
{
cl->cl_curr_items--;
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
ci = NULL;
}else
{
if (list_key)
strcpy(ci->ci_Name, list_key);
memset(ci->ci_Item, '\0', ci->ci_data_size );
}
}
/* alloc new item or re-use */
if ( ci==NULL
&& L_List
&& (i_flags & SEARCH_LRU_LIST)
&& cl->cl_max_items
&& cl->cl_curr_items >= cl->cl_max_items
)
{
/* Re-Use last on LRU chain */
ci = Remove_Tail_Item( L_List );
if (ci)
{
cl->cl_cache_replaces++;
Remove_Node( &ci->ci_S_Node ); /* and remove from search chain */
if ( strlen(list_key) > ci->ci_str_size )
{
cl->cl_curr_items--;
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
ci = NULL;
}else
{
/* re-using, so adjust name */
if (list_key)
strcpy(ci->ci_Name, list_key);
memset(ci->ci_Item, '\0', ci->ci_data_size );
}
}
}
if (ci==NULL)
{
ci = New_Cache_Item( cl, list_key );
}
return(ci);
}
int
Add_Cache_Item( const char *list_name, const void *list_key, ... )
{
struct Cache_List *cl;
struct Cache_Item *ci;
struct Cache_Field *cf;
void *vp;
vchar_ptr vcp1,vcp2;
int rv=0;
va_list ap;
Local_Cache_Init(&Master_List); /* just in case we haven't done it before */
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Add_Cache_Item: <%s> <%p> ", list_name, list_key );
#endif
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if (cl)
{
if (list_key == CACHE_ONE_OF_ONE)
{
/* get an item and be ready to use it */
ci = Cache_Get_Item_From_Free( cl );
}else
if (list_key == CACHE_END_OF_MANY)
{
/* time to link all those created so far into the real list */
return( Cache_End_Of_Many( cl ) );
}
else if (list_key == CACHE_ONE_OF_MANY)
{
/* get an item and be ready to use it */
ci = Cache_Get_Item_From_Free( cl );
}else
{
ci = Find_Full_Item( &cl->cl_Items, list_key );
if (ci==NULL)
{
ci = Obtain_Cache_Item( cl, list_key,
&cl->cl_Items.fl_LRU_List,
(SEARCH_ALL_LISTS) );
if (ci)
{
/* If we got an item, it is hanging free so...
Put it on the relevant lists
*/
Add_Head( &cl->cl_Items.fl_LRU_List, &ci->ci_L_Node );
Add_Head( &cl->cl_Items.fl_Search_List, &ci->ci_S_Node );
cl->cl_curr_items++;
}
}
}
if (ci)
{
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Added\n");
#endif
/* now insert the new values */
cf = (struct Cache_Field *)cl->cl_Fields.ln_Head.ln_Succ;
va_start(ap, list_key );
while (cf->cf_Node.ln_Succ)
{
switch( cf->cf_field_type )
{
case CF_INT :
/* fprintf(stderr,"Fetch int ");*/
*(int *)((char *)ci->ci_Item + cf->cf_f_offset) = (int)va_arg(ap, int );
/* fprintf(stderr,"- done\n");*/
break;
case CF_DOUBLE :
/* fprintf(stderr,"Fetch double ");*/
*(double *)((char *)ci->ci_Item + cf->cf_f_offset) = (double)va_arg(ap, double );
/* fprintf(stderr,"- done\n");*/
break;
case CF_CHAR :
/* fprintf(stderr,"Fetch char ");*/
*(char *)((char *)ci->ci_Item + cf->cf_f_offset) = (char)va_arg(ap, char );
/* fprintf(stderr,"- done\n");*/
break;
case CF_STRING :
/* fprintf(stderr,"Fetch string ");*/
vp = va_arg(ap, void* );
strcpy( (char *)ci->ci_Item + cf->cf_f_offset, (char *)vp );
/* fprintf(stderr,"- done\n");*/
break;
case CF_VARCHAR :
/* fprintf(stderr,"Fetch varchar ");*/
vp = va_arg(ap, vchar_ptr );
vcp1 = (vchar_ptr)((char *)ci->ci_Item + cf->cf_f_offset);
vcp2 = (vchar_ptr)vp;
vcp1->len = vcp2->len;
memcpy(vcp1->arr, vcp2->arr, vcp2->len );
/* fprintf(stderr,"- done\n");*/
break;
}
cf = (struct Cache_Field *)cf->cf_Node.ln_Succ;
rv=1;
};
va_end(ap);
if (list_key == CACHE_ONE_OF_ONE)
{
/* get an item and be ready to use it */
rv = Cache_End_Of_Many( cl );
}
/*hex_dump(stderr, ci->ci_Item, cl->cl_data_size );*/
}
#ifdef CACHE_DEBUG
else
if (cache_debug)
fprintf(stderr,"not added\n");
#endif
}
#ifdef CACHE_DEBUG
else
if (cache_debug)
fprintf(stderr,"List not found\n");
#endif
return(rv);
}
int
Cache_Complete_Miss( const char *list_name, const void* list_key )
{
struct Cache_List *cl;
struct Cache_Item *ci;
Node_t *node;
Local_Cache_Init(&Master_List); /* just in case we haven't done it before */
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Cache_Complete_Miss: ");
#endif
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if (cl)
{
cl->cl_complete_misses ++;
if ( cl->cl_search_rules != NULL )
{
Range_Complete_Miss( cl, list_key );
}else
{
ci = Find_Item_By_Name( &cl->cl_Missing, list_key );
if (ci)
{
node = Find_Node_By_Item( &cl->cl_Missing, ci );
Remove_Node( node );
Add_Head( &cl->cl_Missing, node );
}
else
{
/* Allocate a node and add it to the missing chain */
ci = Remove_Head_Item( &cl->cl_Free );
if (ci==NULL)
ci = Remove_Head_Item( &cl->cl_Missing );
if (ci==NULL)
{
/* allocate one ? */
}
if (ci)
{
/* put on complete miss list */
Add_Head( &cl->cl_Missing, &ci->ci_S_Node );
}
}
}
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"OK\n");
#endif
}
#ifdef CACHE_DEBUG
else
if (cache_debug)
fprintf(stderr,"Failed\n");
#endif
return(1);
}
int
Cache_Flush( const char *list_name )
{
struct Cache_List *cl;
struct Cache_Item *ci;
int rv=0;
Local_Cache_Init(&Master_List); /* just in case we haven't done it before */
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"Cache_Flush: ");
#endif
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if (cl && (cl->cl_flags & CACHE_FLUSHABLE) )
{
if ( cl->cl_search_rules != NULL )
{
rv = Range_Flush( cl );
}else
{
while ( (ci = Remove_Head_Item( &cl->cl_Items.fl_Search_List )) )
{
Remove_Node( &ci->ci_L_Node );
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
};
while( (ci = Remove_Head_Item( &cl->cl_Missing )) )
{
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
}
cl->cl_curr_items = 0;
rv = 1;
}
}
#ifdef CACHE_DEBUG
else
if (cache_debug)
fprintf(stderr,"Failed\n");
#endif
return(rv);
}
/* -- End of File -- */

739
libsrc/dl_lru_range.c Normal file
View file

@ -0,0 +1,739 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/data_align.h>
#include <mplib1/dl_list.h>
#include <mplib1/dl_lru.h>
#include "../include/dl_lru_private.h"
#include <mplib1/stricmp.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifndef NULL
#define NULL ((void *)0)
#endif
struct vchar_gen
{
unsigned short len;
unsigned char arr[1];
};
typedef struct vchar_gen *vchar_ptr;
struct cps
{
struct Cache_List *cl;
int nrl;
struct full_search_rule *srp;
void **sv;
struct Cache_Item *ci;
struct Cache_Item *si;
struct Cache_Item *rv;
};
/* ------------------------------------------------------------------
Some static variables
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static int
vcharcmp( vchar_ptr vp1, vchar_ptr vp2 )
{
int t,rv=0;
unsigned char *cp;
static char estr[]="\0";
t=vp1->len;
if (vp2->len != t)
{
if (vp2->len < t)
{
t=vp2->len;
cp=vp1->arr + t;
}else
{
cp=vp2->arr + t;
}
rv = memcmp( vp1->arr, vp2->arr, (size_t)t );
if (rv==0)
{
/* Check remainder */
rv=memcmp( cp, estr, 1 );
}
}else
{
/* same length, may be equal, have to check */
rv = memcmp( vp1->arr, vp2->arr, (size_t)t );
}
return(rv);
}
static int
vcharcasecmp( vchar_ptr vp1, vchar_ptr vp2 )
{
return(0);
}
static int fail( void *vp1, void *vp2 ) { return(0); }
#define COMP_FUNC(a,b,c) static int a##_##b (void *p1, void *p2){return( *(a *)p1 c *(a *)p2 ); }
#define COMP_FFUNC(a,b,c,d,e) static int a##_##b (void *p1, void *p2){return( d ( p1, p2 ) c e ); }
COMP_FUNC( int, eq, == )
COMP_FUNC( int, gt, > )
COMP_FUNC( int, ge, >= )
COMP_FUNC( int, lt, < )
COMP_FUNC( int, le, <= )
COMP_FUNC( int, ne, != )
COMP_FUNC( double, eq, == )
COMP_FUNC( double, gt, > )
COMP_FUNC( double, ge, >= )
COMP_FUNC( double, lt, < )
COMP_FUNC( double, le, <= )
COMP_FUNC( double, ne, != )
COMP_FUNC( char, eq, == )
COMP_FUNC( char, gt, > )
COMP_FUNC( char, ge, >= )
COMP_FUNC( char, lt, < )
COMP_FUNC( char, le, <= )
COMP_FUNC( char, ne, != )
COMP_FFUNC( string, eq, ==, strcmp, 0 )
COMP_FFUNC( string, gt, >, strcmp, 0 )
COMP_FFUNC( string, ge, >=, strcmp, 0 )
COMP_FFUNC( string, lt, <, strcmp, 0 )
COMP_FFUNC( string, le, <=, strcmp, 0 )
COMP_FFUNC( string, ne, !=, strcmp, 0 )
COMP_FFUNC( casestring, eq, ==, stricmp, 0 )
COMP_FFUNC( casestring, gt, >, stricmp, 0 )
COMP_FFUNC( casestring, ge, >=, stricmp, 0 )
COMP_FFUNC( casestring, lt, <, stricmp, 0 )
COMP_FFUNC( casestring, le, <=, stricmp, 0 )
COMP_FFUNC( casestring, ne, !=, stricmp, 0 )
COMP_FFUNC( varchar, eq, ==, vcharcmp, 0 )
COMP_FFUNC( varchar, gt, >, vcharcmp, 0 )
COMP_FFUNC( varchar, ge, >=, vcharcmp, 0 )
COMP_FFUNC( varchar, lt, <, vcharcmp, 0 )
COMP_FFUNC( varchar, le, <=, vcharcmp, 0 )
COMP_FFUNC( varchar, ne, !=, vcharcmp, 0 )
COMP_FFUNC( casevarchar, eq, ==, vcharcasecmp, 0 )
COMP_FFUNC( casevarchar, gt, >, vcharcasecmp, 0 )
COMP_FFUNC( casevarchar, ge, >=, vcharcasecmp, 0 )
COMP_FFUNC( casevarchar, lt, <, vcharcasecmp, 0 )
COMP_FFUNC( casevarchar, le, <=, vcharcasecmp, 0 )
COMP_FFUNC( casevarchar, ne, !=, vcharcasecmp, 0 )
/* Sorry about putting a data structure here, but I didn't want to
have to type in all the function definitions again
*/
static (* comp_funcs[NUM_SEARCH_COMPS][CF_NUM_FIELD_TYPES*2])(void *,void *) =
{
{ fail, int_eq, double_eq, char_eq, string_eq, varchar_eq,
fail, int_eq, double_eq, char_eq, casestring_eq, casevarchar_eq },
{ fail, int_ge, double_ge, char_ge, string_ge, varchar_ge,
fail, int_ge, double_ge, char_ge, casestring_ge, casevarchar_ge },
{ fail, int_gt, double_gt, char_gt, string_gt, varchar_gt,
fail, int_gt, double_gt, char_gt, casestring_gt, casevarchar_gt },
{ fail, int_le, double_le, char_le, string_le, varchar_le,
fail, int_le, double_le, char_le, casestring_le, casevarchar_le },
{ fail, int_lt, double_lt, char_lt, string_lt, varchar_lt,
fail, int_lt, double_lt, char_lt, casestring_lt, casevarchar_lt },
{ fail, int_ne, double_ne, char_ne, string_ne, varchar_ne,
fail, int_ne, double_ne, char_ne, casestring_ne, casevarchar_ne }
};
static int
multi_match( struct Cache_Item *ci,
struct cps *cpsp )
{
struct full_search_rule *srp;
int nrl;
int rv=1;
nrl = cpsp->nrl;
srp = cpsp->srp;
/* fprintf(stderr,"multi_match: entry\n");*/
while (nrl && rv)
{
/* fprintf(stderr,"matching: multi_match: %s\n", search_rule_strs[srp->comparison_method] );*/
/* hex_dump( stderr, (char *)(ci->ci_Item) + srp->cf->cf_f_offset, srp->cf->cf_field_size );*/
/* hex_dump( stderr, (char *)(cpsp->si->ci_Item) + srp->cf->cf_f_offset, srp->cf->cf_field_size );*/
rv = (* srp->cmpfunc)( (char *)(ci->ci_Item) + srp->cf->cf_f_offset,
(char *)(cpsp->si->ci_Item) + srp->cf->cf_f_offset
);
nrl--;
srp++;
};
if (rv)
cpsp->rv = ci;
return(rv);
}
static int
Find_This_Item( struct Cache_Item *ci,
struct cps *cpsp )
{
int rv=0;
/* fprintf(stderr,"matching: Find_This_Item\n");*/
/* hex_dump( stderr, (char *)(ci->ci_Item) + cpsp->srp->cf->cf_f_offset, cpsp->srp->cf->cf_field_size );*/
/* hex_dump( stderr, (char *)(cpsp->si->ci_Item) + cpsp->srp->cf->cf_f_offset, cpsp->srp->cf->cf_field_size );*/
rv = (* cpsp->srp->cmpfunc)( (char *)(ci->ci_Item) + cpsp->srp->cf->cf_f_offset,
(char *)(cpsp->si->ci_Item) + cpsp->srp->cf->cf_f_offset
);
if (rv)
cpsp->rv = ci;
return(rv);
}
static int
Init_This_Item( struct Cache_Item *ci,
size_t data_size,
void *data_item,
int expire_time
)
{
Init_Node( &ci->ci_S_Node, NULL, ci );
Init_Node( &ci->ci_L_Node, NULL, ci );
ci->ci_data_size = data_size;
ci->ci_str_size = 0;
ci->ci_Item = data_item;
/*fprintf(stderr,"Init Item: %p,%p\n", ci, ci->ci_Item );*/
ci->ci_Name = NULL;
ci->ci_expire_time = (expire_time)
? time(NULL) + expire_time
: 0;
return(1);
}
static struct Cache_Group_Item *
New_CGI( struct Cache_List *cl, size_t data_size )
{
struct Cache_Group_Item *cgi;
if ( (cgi = Remove_Head_Item( &cl->cl_Free_cgi )) ==NULL )
{
cgi = malloc( sizeof(struct Cache_Group_Item) + data_size );
}
return(cgi);
}
static struct Cache_Group_Item *
Find_CGI( struct Cache_List *cl,
struct Full_List *flp,
struct full_search_rule *fsrp,
struct Cache_Item *ci,
size_t data_size,
int expire_time )
{
struct cps my_cps;
struct Cache_Group_Item *cgi;
my_cps.ci = NULL;
my_cps.srp = fsrp;
my_cps.rv = NULL;
my_cps.si = ci;
/*fprintf(stderr,"About to search %p for %p - First = %p\n", flp, ci, flp->fl_Search_List.ln_Head.ln_Succ );*/
Walk_List2( &flp->fl_Search_List, (Walk_List2_t)Find_This_Item, &my_cps );
if (my_cps.rv==NULL)
{
/* Doesn't exist. allocate this one */
cgi = New_CGI( cl, data_size );
if (cgi!=NULL)
{
/* init this cgi */
Init_This_Item( &cgi->cgi_Item, data_size,
cgi + 1, expire_time );
Init_Full_List( &cgi->cgi_Items, NULL, 0 );
/*hex_dump( stderr, ci->ci_Item, data_size );*/
memcpy( cgi+1, ci->ci_Item, data_size );
Add_Head( &flp->fl_Search_List, &cgi->cgi_Item.ci_S_Node );
Add_Head( &flp->fl_LRU_List, &cgi->cgi_Item.ci_L_Node );
cgi->cgi_Flags = 0;
}
}else
{
cgi = (struct Cache_Group_Item *)my_cps.rv;
/*fprintf(stderr, "cgi already exists\n");*/
}
return(cgi);
}
static struct Cache_Item *
Build_Search_Item( struct Cache_List *cl, void **keys )
{
struct Cache_Item *sci;
struct full_search_rule *srp;
int nrl;
char *tp;
sci = malloc( CACHE_ITEM_SIZE + cl->cl_data_size );
/*fprintf(stderr,"search item: %p %d %d\n", sci, CACHE_ITEM_SIZE, cl->cl_data_size );*/
if (sci)
{
/* copy the various fields */
Init_This_Item( sci, cl->cl_data_size, sci + 1, cl->cl_expire_time );
srp = cl->cl_search_rules;
nrl = cl->cl_num_search_rules;
tp = (char *)(sci +1);
while(nrl--)
{
/* copy each field in turn */
memcpy( tp + srp->cf->cf_f_offset, *keys++, srp->cf->cf_field_size );
/*hex_dump( stderr, tp + srp->cf->cf_f_offset, srp->cf->cf_field_size );*/
srp++;
};
}
return(sci);
}
struct Cache_Item *
Cache_Find_Requested_Item( struct Cache_List *cl, const void *keys, int *rv )
{
char *single_key;
struct Cache_Item *ci;
struct Cache_Item *sci;
struct Cache_Group_Item *cgi;
int nrl;
struct full_search_rule *srp;
struct Full_List *flp;
*rv = CACHE_MISSED;
if (cl->cl_num_search_rules == 0)
{
/* Ah, an old style enquiry. */
single_key = keys;
ci = (struct Cache_Item *)Find_Full_Item( &cl->cl_Items, single_key );
*rv = (ci) ? CACHE_FOUND_ITEM : CACHE_MISSED;
}else
{
sci = Build_Search_Item( cl, (void **)keys );
if (sci==NULL)
return(NULL);
/* time to search done multiple lists */
nrl = cl->cl_num_search_rules;
srp = cl->cl_search_rules;
flp = &cl->cl_Items;
ci = NULL;
/* Now, we walk each list in turn, checking each equality item */
do
{
cgi = Find_CGI( cl, flp, srp, sci,
cl->cl_data_size, cl->cl_expire_time );
nrl--;
srp++;
flp = &cgi->cgi_Items;
}
while ( nrl
&& srp->comparison_method == SEARCH_EQ
&& cgi
);
if (cgi && (nrl==0 || srp->comparison_method != SEARCH_EQ) )
{
if (cgi->cgi_Flags & CGI_COMPLETE_MISS)
{
/*fprintf(stderr,"cgi (%p) marked as complete miss\n",cgi);*/
*rv = CACHE_COMPLETE_MISS;
}
else
if (nrl==0)
{
ci = Remove_Head_Item( &cgi->cgi_Items.fl_Search_List );
Add_Head( &cgi->cgi_Items.fl_Search_List, &ci->ci_S_Node );
*rv = CACHE_FOUND_ITEM;
}
else
{
/* Time to do partial check */
struct cps my_cps;
my_cps.nrl = nrl;
my_cps.srp = srp;
my_cps.si = sci;
my_cps.rv = NULL;
if (Walk_List2( &flp->fl_Search_List, (Walk_List2_t)multi_match, &my_cps ))
{
*rv = CACHE_FOUND_ITEM;
ci = my_cps.rv;
}else
{
ci = Remove_Head_Item( &flp->fl_Search_List );
if (ci)
Add_Head( &flp->fl_Search_List, &ci->ci_S_Node );
*rv = ((cl->cl_flags & CACHE_INSERT_MANY) && ci )
? CACHE_COMPLETE_MISS : CACHE_MISSED;
ci = NULL;
}
}
}
/*else fprintf(stderr,"cannot find cgi before end of search\n");*/
/*fprintf(stderr,"Freeing: %p\n", sci );*/
free(sci);
}
return(ci);
}
static int
Build_Search_Rules( struct Cache_List *cl, struct search_rule *srulep )
{
int rv=0;
/* struct Cache_Field *cf;*/
struct search_rule *trulep;
struct full_search_rule *fsrp,*tfsrp;
int num_rules=0,toff;
#ifdef CACHE_DEBUG
/* fprintf(stderr, "Build_Search_Rules: Entry\n" );*/
#endif
trulep = srulep;
while (trulep->field_name)
{
trulep++;
num_rules++;
};
#ifdef CACHE_DEBUG
/* fprintf(stderr, "Build_Search_Rules: %d number of rules\n", num_rules );*/
#endif
/* Now allocate the correct number of full rules */
fsrp = malloc( num_rules * sizeof(struct full_search_rule) );
if (fsrp)
{
#ifdef CACHE_DEBUG
/* fprintf(stderr, "Build_Search_Rules: rules: <%p>\n", fsrp );*/
#endif
tfsrp = fsrp;
/* Now initialise each rule */
while(srulep->field_name)
{
tfsrp->cf = Find_Item_By_Name( &cl->cl_Fields, srulep->field_name );
if (tfsrp->cf == NULL)
{
free( fsrp );
return(0);
}
#ifdef CACHE_DEBUG
/* fprintf(stderr, "Build_Search_Rules: <%s> <%p> <%d>\n",*/
/* srulep->field_name, tfsrp->cf, srulep->comparison_method );*/
#endif
tfsrp->comparison_method = srulep->comparison_method;
if ( tfsrp->comparison_method < 0
|| tfsrp->comparison_method >= NUM_SEARCH_COMPS
)
{
/* bad vbalue */
free( fsrp );
return(0);
}
toff = (tfsrp->cf->cf_field_flags & CF_FLG_IGNORECASE) ? CF_NUM_FIELD_TYPES:0;
tfsrp->cmpfunc = comp_funcs[srulep->comparison_method]
[tfsrp->cf->cf_field_type + toff];
srulep++;
tfsrp++;
};
cl->cl_search_rules = fsrp;
cl->cl_num_search_rules = num_rules;
rv = 1;
}
#ifdef CACHE_DEBUG
/* fprintf(stderr, "Build_Search_Rules: returns %d\n", rv );*/
#endif
return(rv);
}
int
Create_Range_Cache( const char *list_name, int max_items,
int list_flags, struct search_rule *srulep,
const char *format_str, const char *field_names )
{
int rv=0;
struct Cache_List *cl;
List_t *Master_List;
Master_List = Get_Cache_Master_List();
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if ( cl == NULL
&& (cl=New_Cache_List( list_name, max_items, list_flags,
CACHE_RANGE_DEFAULTS, CACHE_RANGE_DEFAULTS ))
)
{
/*fprintf(stderr, "flags: %x %x %x\n", cl->cl_flags,*/
/* list_flags, CACHE_RANGE_DEFAULTS );*/
/* Build the field list */
rv = Cache_Build_Field_List( cl, format_str, field_names );
/* Now parse the search rules */
if (rv==1)
rv = Build_Search_Rules( cl, srulep );
if (rv==1)
Add_Head( Master_List, &cl->cl_Node );
}
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr,"%s\n",(rv)?"successfull":"failed");
#endif
return(rv);
}
struct Cache_Item *
Cache_Get_Item_From_Free( struct Cache_List *cl )
{
struct Cache_Item *ci;
ci = Remove_Head_Item( &cl->cl_Free );
if ( ci == NULL )
{
/* Need a new one so allocate */
ci = malloc( CACHE_ITEM_SIZE + cl->cl_data_size );
#ifdef CACHE_DEBUG
fprintf(stderr, "malloc item %p (from %d & %d)\n", ci, CACHE_ITEM_SIZE, cl->cl_data_size );
#endif
Init_This_Item( ci, cl->cl_data_size, ci + 1, cl->cl_expire_time );
#ifdef CACHE_DEBUG
fprintf(stderr, "inited\n" );
#endif
}
if (ci)
{
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr, "About to add to build list\n" );
#endif
/* clear this one out */
Add_Tail( &cl->cl_Build, &ci->ci_S_Node );
#ifdef CACHE_DEBUG
if (cache_debug)
fprintf(stderr, "added to build list\n" );
#endif
}
return(ci);
}
int
Cache_End_Of_Many( struct Cache_List *cl )
{
struct Cache_Item *ci;
/* struct Cache_Field *cf;*/
struct Cache_Group_Item *cgi;
struct full_search_rule *fsrp;
struct Full_List *flp;
int nrl;
/*fprintf(stderr,"End_Of_Many: starting\n");*/
ci = Remove_Head_Item( &cl->cl_Build );
if (ci==NULL)
return(0);
Add_Head( &cl->cl_Build, &ci->ci_S_Node );
/*fprintf(stderr," There are items to add\n");*/
while( (ci = Remove_Head_Item( &cl->cl_Build )) )
{
flp = &cl->cl_Items;
fsrp = cl->cl_search_rules;
nrl = cl->cl_num_search_rules;
while ( nrl
&& fsrp->comparison_method == SEARCH_EQ
)
{
cgi = Find_CGI( cl, flp, fsrp, ci, cl->cl_data_size, cl->cl_expire_time );
/*fprintf(stderr,"Found cgi %p\n", cgi );*/
if (cgi==NULL)
{
/* big problem. Can't allocate cgi for adding this list, so
return items on build list to free list and return failure
*/
while( (ci = Remove_Head_Item( &cl->cl_Build )) )
{
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
};
return(0);
}
flp = &cgi->cgi_Items;
cgi->cgi_Flags &= ~CGI_COMPLETE_MISS;
nrl--;
fsrp++;
};
/*fprintf(stderr,"About to add items to CGI %p\n", cgi );*/
/* We now have the cgi which will take the current item from the build list */
cgi->cgi_Flags &= ~CGI_COMPLETE_MISS;
cl->cl_curr_items++;
Add_Tail( &cgi->cgi_Items.fl_Search_List, &ci->ci_S_Node );
Add_Head( &cgi->cgi_Items.fl_LRU_List, &ci->ci_L_Node );
};
return( 1 );
}
int
Range_Complete_Miss( struct Cache_List *cl, const void *keys )
{
struct Cache_Item *ci;
struct Cache_Item *sci;
struct Cache_Group_Item *cgi;
int nrl;
struct full_search_rule *srp;
struct Full_List *flp;
sci = Build_Search_Item( cl, (void **)keys );
if (sci==NULL)
return(0);
/* time to search done multiple lists */
nrl = cl->cl_num_search_rules;
srp = cl->cl_search_rules;
flp = &cl->cl_Items;
ci = NULL;
/* Now, we walk each list in turn, checking each equality item */
do
{
cgi = Find_CGI( cl, flp, srp, sci,
cl->cl_data_size, cl->cl_expire_time );
nrl--;
srp++;
flp = &cgi->cgi_Items;
}
while ( nrl
&& srp->comparison_method == SEARCH_EQ
&& cgi
);
if (cgi && (nrl==0 || srp->comparison_method != SEARCH_EQ) )
cgi->cgi_Flags |= CGI_COMPLETE_MISS;
return(1);
}
static void
Flush_Items( struct Cache_Item *ci,
struct Cache_List *cl )
{
Remove_Node( &ci->ci_S_Node );
Remove_Node( &ci->ci_L_Node );
Add_Tail( &cl->cl_Free, &ci->ci_S_Node );
return;
}
static void
Flush_CGI( struct Cache_Group_Item *cgi,
struct cps *cpsp )
{
struct cps my_cps;
struct full_search_rule *srp;
srp = cpsp->srp;
memcpy( &my_cps, cpsp, sizeof(struct cps) );
srp++;
my_cps.nrl--;
my_cps.srp = srp;
if (my_cps.nrl==0 || srp->comparison_method != SEARCH_EQ)
{
/* End of the line */
Walk_List( &cgi->cgi_Items.fl_Search_List,
(Walk_List_t)Flush_Items, cpsp->cl );
}else
{
Walk_List( &cgi->cgi_Items.fl_Search_List,
(Walk_List_t)Flush_CGI, &my_cps );
}
/* whichever varient it is, this cgi is now redundant */
Remove_Node( &cgi->cgi_Item.ci_S_Node );
Remove_Node( &cgi->cgi_Item.ci_L_Node );
Add_Tail( &cpsp->cl->cl_Free_cgi, &cgi->cgi_Item.ci_S_Node );
return;
}
int
Range_Flush( struct Cache_List *cl )
{
struct Cache_Item *ci;
int nrl;
struct full_search_rule *srp;
struct Full_List *flp;
struct cps my_cps;
/* time to search done multiple lists */
nrl = cl->cl_num_search_rules;
srp = cl->cl_search_rules;
flp = &cl->cl_Items;
ci = NULL;
if (srp->comparison_method == SEARCH_EQ)
{
/* Time to walk each cgi list until we meet real items */
my_cps.cl = cl;
my_cps.nrl = nrl;
my_cps.srp = srp;
Walk_List( &flp->fl_Search_List, (Walk_List_t)Flush_CGI, &my_cps );
}else
{
Walk_List( &flp->fl_Search_List, (Walk_List_t)Flush_Items, cl );
}
return(1);
}
/* -- End of File -- */

285
libsrc/dl_lru_rep.c Normal file
View file

@ -0,0 +1,285 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/dl_list.h>
#include <mplib1/dl_lru.h>
#include "../include/dl_lru_private.h"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifndef NULL
#define NULL ((void *)0)
#endif
struct vchar_gen
{
unsigned short len;
unsigned char arr[1];
};
typedef struct vchar_gen *vchar_ptr;
struct cache_stat
{
struct Cache_List *cl;
struct Cache_Group_Item *cgi;
struct Cache_Item *ci;
struct Cache_Field *cf;
int num_search_rules;
struct full_search_rule *fsrp;
FILE *fp;
};
/* ------------------------------------------------------------------
Some static variables
------------------------------------------------------------------ */
static const char *search_rule_strs[]=
{ "==", ">=", ">", "<=", "<", "!=" };
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static void
Print_Field( void *vp1, void *vp2 )
{
struct Cache_Field *cf;
struct cache_stat *cs;
char *cp;
vchar_ptr vp;
char cbuf[240];
cf = vp1;
cs = vp2;
cp = (char *)(cs->ci->ci_Item) + cf->cf_f_offset;
memset( cbuf, '\0', 240 );
switch(cf->cf_field_type)
{
case CF_INT :
fprintf( cs->fp, " %d", *((int *)cp) );
break;
case CF_DOUBLE :
fprintf( cs->fp, " %f", *((double *)cp) );
break;
case CF_CHAR :
fprintf( cs->fp, " %c", *cp );
break;
case CF_STRING :
fprintf( cs->fp, " %*.*s", cf->cf_field_size,
(int)cf->cf_field_size, cp );
break;
case CF_VARCHAR :
vp = (vchar_ptr)cp;
fprintf( cs->fp, " <%d>", vp->len );
memcpy(cbuf,&vp->arr[0],vp->len);
cbuf[vp->len]='\0';
fprintf( cs->fp, " %s", cbuf );
break;
}
return;
}
static void
Print_CI( struct Cache_Item *ci,
struct cache_stat *cs )
{
cs->ci = ci;
if (ci->ci_Name)
fprintf( cs->fp, " Item: %s\n", ci->ci_Name );
Walk_List( &cs->cl->cl_Fields, (Walk_List_t)Print_Field, cs );
fprintf( cs->fp, "\n" );
return;
}
static void
Print_Rules( FILE *fp, struct full_search_rule *frsp, int num_rules )
{
fprintf( fp, "Search Rules:\n" );
while (num_rules--)
{
fprintf( fp, " : <%s> %s\n",
frsp->cf->cf_Name, search_rule_strs[frsp->comparison_method] );
frsp++;
};
return;
}
static void
Print_CGI_Header( FILE *fp, struct full_search_rule *frsp, int num_rules )
{
if (frsp->comparison_method== SEARCH_EQ)
{
fprintf( fp, " CGI List: <%s> %s\n",
frsp->cf->cf_Name, search_rule_strs[frsp->comparison_method] );
}else
{
while (num_rules--)
{
fprintf( fp, " CGI List: <%s> %s\n",
frsp->cf->cf_Name, search_rule_strs[frsp->comparison_method] );
frsp++;
};
}
return;
}
static void
Print_CGI( struct Cache_Group_Item *cgi,
struct cache_stat *cs )
{
cs->cgi = cgi;
fprintf( cs->fp, " CGI: %x %d ", cgi->cgi_Flags, cs->num_search_rules );
cs->ci = &cgi->cgi_Item;
Print_Field( cs->fsrp->cf, cs );
fprintf( cs->fp, "\n" );
cs->num_search_rules--;
cs->fsrp++;
if (cs->num_search_rules==0 || cs->fsrp->comparison_method != SEARCH_EQ)
Walk_List( &cgi->cgi_Items.fl_Search_List, (Walk_List_t)Print_CI, cs );
else
{
Print_CGI_Header( cs->fp, cs->fsrp, cs->num_search_rules );
Walk_List( &cgi->cgi_Items.fl_Search_List, (Walk_List_t)Print_CGI, cs );
}
cs->num_search_rules++;
cs->fsrp--;
return;
}
static void
Print_Fields( struct Cache_Field *cf,
FILE *fp )
{
fprintf( fp, " <%-40.40s> <%d> <%d> <%d> <%d>\n",
cf->cf_Name, cf->cf_field_type,
cf->cf_field_size, cf->cf_field_num,
cf->cf_f_offset );
return;
}
static void
Cache_List_Stat( FILE *fp, struct Cache_List *cl, int contents )
{
struct cache_stat my_stat;
fprintf( fp, "List: \"%s\"\n\n", cl->cl_Name );
fprintf( fp, " Max: %8d\tCurr: %8d\n", cl->cl_max_items, cl->cl_curr_items );
fprintf( fp, " Size: %8d\tFlags: %8d\n", cl->cl_data_size, cl->cl_flags );
fprintf( fp, " Mode: %s\n", (cl->cl_flags & CACHE_CACHE_ON)?"Caching":"Statistics");
fprintf( fp, " Case: %s\n", (cl->cl_flags & CACHE_IGNORE_CASE)?"Ignore":"Check");
fprintf( fp, " Alloc: %s\n", (cl->cl_flags & CACHE_DEMAND_ALLOC)?"Demand":"Pre-Allocate");
fprintf( fp, " Flush: %s\n", (cl->cl_flags & CACHE_FLUSHABLE)?"Flushable":"NOT Flushable");
if (cl->cl_search_rules)
fprintf( fp, " Insert: %s\n", (cl->cl_flags & CACHE_INSERT_MANY)?"Many":"Single");
fprintf( fp, " Hit: %8d\tMiss: %8d\n", cl->cl_cache_hits, cl->cl_cache_misses );
fprintf( fp, " Rep: %8d\tFail: %8d\n", cl->cl_cache_replaces, cl->cl_complete_misses );
fprintf( fp, " Fields\n" );
Walk_List( &cl->cl_Fields, (Walk_List_t)Print_Fields, fp );
if ( contents )
{
if ( cl->cl_search_rules==NULL
|| cl->cl_search_rules->comparison_method!=SEARCH_EQ
)
{
my_stat.cl = cl;
my_stat.fp = fp;
Walk_List( &cl->cl_Items.fl_Search_List,
(Walk_List_t)Print_CI,
&my_stat );
}else
{
my_stat.cl = cl;
my_stat.fp = fp;
my_stat.fsrp = cl->cl_search_rules;
my_stat.num_search_rules = cl->cl_num_search_rules;
Print_Rules( fp, my_stat.fsrp, my_stat.num_search_rules );
Print_CGI_Header( fp, my_stat.fsrp, my_stat.num_search_rules );
Walk_List( &cl->cl_Items.fl_Search_List,
(Walk_List_t)Print_CGI,
&my_stat );
}
}
fprintf( fp, "\n" );
return;
}
int
Cache_Stats( FILE *fp, const char *list_name, int contents )
{
struct Cache_List *cl;
List_t *Master_List;
Master_List = Get_Cache_Master_List();
if (list_name)
{
cl = (struct Cache_List *)Find_Item_By_Name( Master_List, list_name );
if (cl)
Cache_List_Stat( fp, cl, contents );
}
else
{
cl = (struct Cache_List *)Master_List->ln_Head.ln_Succ;
while (cl->cl_Node.ln_Succ)
{
Cache_List_Stat( fp, cl, contents );
cl = (struct Cache_List *)cl->cl_Node.ln_Succ;
};
}
return(0);
}
/* -- End of File -- */

253
libsrc/dl_sort_i.c Normal file
View file

@ -0,0 +1,253 @@
/*
*
* Optimal list-merge sorting algorithm with exponential merge schedule.
*
* From: Software Development International, Winter 1991.
*
* This implementation by Jeremy Harris jgh@imptld.com
*
* Adapted into toolkit by Martin Poole mpoole@cix.compulink.co.uk
*
* And now adapted for Amiga style double linked lists.
*
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* $Source$
* $Author$
* $Date$
* $Revision$
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifdef TRACE
#undef TRACE
#define TRACE(x) printf x
#else
#define NO_TRACE
#define TRACE(x) /*empty*/
#endif
#define MAXHOOKS 24 /* permits merging up to 33,554,430 records */
#define KEYVAL(dataitem) dataitem
#define GETKEY(datapp) (datapp->ln_Item)
/* ------------------------------------------------------------------
includes
------------------------------------------------------------------ */
#include <sys/types.h>
#ifdef NO_TRACE
#include <stdio.h>
#endif
#include <mplib1/mplib1_config.h>
#include <mplib1/dl_list.h>
/* ------------------------------------------------------------------
variables
------------------------------------------------------------------ */
static int (*compare)( const void *, const void *);
/* ------------------------------------------------------------------
code starts here
------------------------------------------------------------------ */
static dl_Node_t *
binmerge( register dl_Node_t * datap_a,
register dl_Node_t * datap_b )
{
register dl_Node_t * tail;
dl_Node_t * start;
/* Initialisation */
if( (*compare)( datap_a->ln_Item, datap_b->ln_Item ) > 0 )
{
start= datap_b;
goto b_wins;
}
start= datap_a;
a_wins: do
{
tail= datap_a;
if( !(datap_a= datap_a->ln_Succ) )
{
tail->ln_Succ= datap_b;
return(start);
}
} while( (*compare)( datap_a->ln_Item, datap_b->ln_Item ) <= 0 );
tail->ln_Succ= datap_b;
b_wins: do
{
tail= datap_b;
if( !(datap_b= datap_b->ln_Succ) )
{
tail->ln_Succ= datap_a;
return(start);
}
} while( (*compare)( datap_a->ln_Item, datap_b->ln_Item ) >= 0 );
tail->ln_Succ= datap_a;
goto a_wins;
/*NOTREACHED*/
}
int
dl_sort_i( dl_List_t *sort_list, int (*compar)(const void *, const void *) )
{
int k;
dl_Node_t * temp;
dl_Node_t * this_one;
dl_Node_t * next_one;
dl_Node_t * runhook[MAXHOOKS];
if (sort_list->ln_Head.ln_Succ->ln_Succ)
{
/* Initialisation */
compare = compar;
for( k= 0; k < MAXHOOKS; k++ )
runhook[k]= NULL;
/* And now knock out the last forward pointer so we can
use a simple test to finish */
sort_list->ln_Tail.ln_Pred->ln_Succ=NULL;
this_one= sort_list->ln_Head.ln_Succ;
while( this_one )
{
temp= this_one;
next_one= this_one->ln_Succ;
if( next_one )
{
/* Run Linker */
if( (*compare)( this_one->ln_Item, next_one->ln_Item ) <= 0 )
{
/* Non-descending-order run */
TRACE( ("linker: run up\n%p", GETKEY(this_one) ) );
do /* no need to relink default */
{
TRACE( (" %d", GETKEY(next_one)) );
this_one= next_one;
next_one= this_one->ln_Succ;
} while( next_one
&& (*compare)( this_one->ln_Item, next_one->ln_Item ) <= 0 );
this_one->ln_Succ= 0; /* terminate run up */
TRACE( ("\n") );
}
else
{
/* Descending-order run */
TRACE( ("linker: run down\n%d", GETKEY(this_one) ) );
this_one->ln_Succ= 0; /* terminate run down */
do /* relink backwards */
{
TRACE( (" %d", GETKEY(next_one)) );
temp= next_one;
next_one= next_one->ln_Succ;
temp->ln_Succ= this_one;
this_one= temp;
} while( next_one
&& (*compare)( this_one->ln_Item, next_one->ln_Item ) >= 0 );
TRACE( ("\n") );
}
}
/* "temp" is now the head of a non-descending run */
/* Merge Scheduler */
TRACE( ("Merge Scheduler\n") );
k= 0;
do /* Put the sublist on a hook */
{
TRACE( ("hook %d", k) );
if( runhook[k] )
{
/* Hook is occupied; merge and retry at hook k+1. */
TRACE( (" was in use; merging\n") );
temp= binmerge( runhook[k], temp );
runhook[k]= 0;
}
else
{
TRACE( (" was free\n") );
runhook[k]= temp;
temp= 0; /* flag for loop exit */
}
k++;
} while( temp );
this_one= next_one;
}
/*
* Run Collector.
* At this point the eof has been found, so the runs in
* runhook must be collected from the bottom up to keep it stable.
*/
TRACE( ("Collector\n") );
k= 0;
while( !runhook[k] )
{
TRACE( ("hook %d free\t", k) );
k++;
}
TRACE( ("list on hook %d\n", k) );
temp= runhook[k];
while( ++k < MAXHOOKS )
if( runhook[k] )
{
TRACE( ("merging with list on hook %d\n", k) );
temp= binmerge( runhook[k], temp );
}
else
TRACE( ("hook %d free\t", k) );
/* At this point, the first Node is pointed to by start,
attach this to the Head of the list, and then walk the list
correcting the back pointers
*/
TRACE( ("\nAdjust List\n") );
sort_list->ln_Head.ln_Succ = temp;
this_one = temp;
temp = &sort_list->ln_Head;
while(this_one)
{
TRACE( ("Adjust pred of %p\n", this_one) );
this_one->ln_Pred = temp;
temp = this_one;
this_one = this_one->ln_Succ;
};
temp->ln_Succ = &sort_list->ln_Tail;
sort_list->ln_Tail.ln_Pred = temp;
TRACE( ("finished\n") );
}
return( 0 );
}
/* -- End of File -- */

251
libsrc/dl_sort_n.c Normal file
View file

@ -0,0 +1,251 @@
/*
*
* Optimal list-merge sorting algorithm with exponential merge schedule.
*
* From: Software Development International, Winter 1991.
*
* This implementation by Jeremy Harris jgh@imptld.com
*
* Adapted into toolkit by Martin Poole mpoole@cix.compulink.co.uk
*
* And now adapted for Amiga style double linked lists.
*
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* $Source$
* $Author$
* $Date$
* $Revision$
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifdef TRACE
#undef TRACE
#define TRACE(x) printf x
#else
#define NO_TRACE
#define TRACE(x) /*empty*/
#endif
#define MAXHOOKS 24 /* permits merging up to 33,554,430 records */
#define KEYVAL(dataitem) dataitem
#define GETKEY(datapp) (datapp->ln_Name)
/* ------------------------------------------------------------------
includes
------------------------------------------------------------------ */
#include <sys/types.h>
#ifdef NO_TRACE
#include <stdio.h>
#endif
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/dl_list.h>
/* ------------------------------------------------------------------
variables
------------------------------------------------------------------ */
static int (*compare)( const char *, const char *);
/* ------------------------------------------------------------------
code starts here
------------------------------------------------------------------ */
static dl_Node_t *
binmerge( register dl_Node_t * datap_a,
register dl_Node_t * datap_b )
{
register dl_Node_t *tail;
dl_Node_t *start;
/* Initialisation */
if( (*compare)( datap_a->ln_Name, datap_b->ln_Name ) > 0 )
{
start= datap_b;
goto b_wins;
}
start= datap_a;
a_wins: do
{
tail= datap_a;
if( !(datap_a= datap_a->ln_Succ) )
{
tail->ln_Succ= datap_b;
return(start);
}
} while( (*compare)( datap_a->ln_Name, datap_b->ln_Name ) <= 0 );
tail->ln_Succ= datap_b;
b_wins: do
{
tail= datap_b;
if( !(datap_b= datap_b->ln_Succ) )
{
tail->ln_Succ= datap_a;
return(start);
}
} while( (*compare)( datap_a->ln_Name, datap_b->ln_Name ) >= 0 );
tail->ln_Succ= datap_a;
goto a_wins;
/*NOTREACHED*/
}
int
dl_sort_n( dl_List_t *sort_list )
{
int k;
dl_Node_t * temp;
dl_Node_t * this_one;
dl_Node_t * next_one;
dl_Node_t * runhook[MAXHOOKS];
if (sort_list->ln_Head.ln_Succ->ln_Succ)
{
compare = strcmp;
for( k= 0; k < MAXHOOKS; k++ )
runhook[k]= NULL;
/* And now knock out the last forward pointer so we can
use a simple test to finish */
sort_list->ln_Tail.ln_Pred->ln_Succ=NULL;
this_one= sort_list->ln_Head.ln_Succ;
while( this_one )
{
temp= this_one;
next_one= this_one->ln_Succ;
if( next_one )
{
/* Run Linker */
if( (*compare)( this_one->ln_Name, next_one->ln_Name ) <= 0 )
{
/* Non-descending-order run */
TRACE( ("linker: run up\n%p", GETKEY(this_one) ) );
do /* no need to relink default */
{
TRACE( (" %d", GETKEY(next_one)) );
this_one= next_one;
next_one= this_one->ln_Succ;
} while( next_one
&& (*compare)( this_one->ln_Name, next_one->ln_Name ) <= 0 );
this_one->ln_Succ= 0; /* terminate run up */
TRACE( ("\n") );
}
else
{
/* Descending-order run */
TRACE( ("linker: run down\n%d", GETKEY(this_one) ) );
this_one->ln_Succ= 0; /* terminate run down */
do /* relink backwards */
{
TRACE( (" %d", GETKEY(next_one)) );
temp= next_one;
next_one= next_one->ln_Succ;
temp->ln_Succ= this_one;
this_one= temp;
} while( next_one
&& (*compare)( this_one->ln_Name, next_one->ln_Name ) >= 0 );
TRACE( ("\n") );
}
}
/* "temp" is now the head of a non-descending run */
/* Merge Scheduler */
TRACE( ("Merge Scheduler\n") );
k= 0;
do /* Put the sublist on a hook */
{
TRACE( ("hook %d", k) );
if( runhook[k] )
{
/* Hook is occupied; merge and retry at hook k+1. */
TRACE( (" was in use; merging\n") );
temp= binmerge( runhook[k], temp );
runhook[k]= 0;
}
else
{
TRACE( (" was free\n") );
runhook[k]= temp;
temp= 0; /* flag for loop exit */
}
k++;
} while( temp );
this_one= next_one;
}
/*
* Run Collector.
* At this point the eof has been found, so the runs in
* runhook must be collected from the bottom up to keep it stable.
*/
TRACE( ("Collector\n") );
k= 0;
while( !runhook[k] )
{
TRACE( ("hook %d free\t", k) );
k++;
}
TRACE( ("list on hook %d\n", k) );
temp= runhook[k];
while( ++k < MAXHOOKS )
if( runhook[k] )
{
TRACE( ("merging with list on hook %d\n", k) );
temp= binmerge( runhook[k], temp );
}
else
TRACE( ("hook %d free\t", k) );
/* At this point, the first Node is pointed to by start,
attach this to the Head of the list, and then walk the list
correcting the back pointers
*/
TRACE( ("\nAdjust List\n") );
sort_list->ln_Head.ln_Succ = temp;
this_one = temp;
temp = &sort_list->ln_Head;
while(this_one)
{
TRACE( ("Adjust pred of %p\n", this_one) );
this_one->ln_Pred = temp;
temp = this_one;
this_one = this_one->ln_Succ;
};
temp->ln_Succ = &sort_list->ln_Tail;
sort_list->ln_Tail.ln_Pred = temp;
TRACE( ("finished\n") );
}
return( 0 );
}
/* -- End of File -- */

107
libsrc/dumphex.c Normal file
View file

@ -0,0 +1,107 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* System :
* Subsystem :
* Module :
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <mplib1/dumphex.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static char *find_eos( char *where )
{
return(where+strlen(where));
}
int
do_hex_dump( FILE *fp, off_t curoff, const char *where, int how_much )
{
char linebuf[80];
char charbuf[20];
int count16,i;
char *eos;
/*fprintf(fp, "hex_dump: %p %d\n", where, how_much );*/
count16 = ((int)curoff & 0x0f);
while (how_much || count16)
{
sprintf( linebuf, "%08x ", (int)curoff );
for (i=0;i<16;i++)
{
eos = find_eos(linebuf);
charbuf[i] = ' ';
if (i<count16)
{
/* blank area */
sprintf(eos, ".. " );
}else
{
/* output the normal stuff */
if (how_much)
{
sprintf(eos,"%02x ", *where & 0xff );
if (*where >= ' ' && *where<0x7f)
{
charbuf[i] = *where;
}
how_much--;
}else
sprintf(eos, ".. " );
where++;
count16++;
curoff++;
count16 &= 0x0f;
}
}
charbuf[16] = '\0';
fprintf(fp, "%s '%s'\n", linebuf, charbuf );
};
return(1);
}
int
hex_dump( FILE *fp, const char *where, int how_much )
{
return(do_hex_dump( fp, 0, where, how_much ));
}
/* -- End of File -- */

101
libsrc/fgetline.c Normal file
View file

@ -0,0 +1,101 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <string.h>
#include <mplib1/fgetline.h>
/* ------------------------------------------------------------------
Defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Structure definitions
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Global variables
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Function prototypes
------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------
Function : fget_line
Summary : This function returns a line from a file, having
: removed the trailing EOL character
Input Parameters : FILE pointer
: Pointer to line buffer
: length of line buffer
Output Parameters : None
Global Variables : None
Return Value : 0 = success, <> 0 failure (of some description)
--------------------------------------------------------------------------*/
int
fgetline( FILE *fh, char *line_buf, int line_len )
{
int rv;
char *cp;
if (fgets(line_buf,line_len,fh) != NULL)
{
/* remove any trailing newline characters */
if (strlen(line_buf))
{
cp = line_buf + strlen(line_buf) - 1;
while ( cp >= line_buf && *cp == '\n')
*cp-- = '\0';
}
rv = 0;
}else
rv = -1;
return(rv);
}
/* -- End of File -- */

91
libsrc/fgetline2.c Normal file
View file

@ -0,0 +1,91 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <string.h>
#include <mplib1/fgetline.h>
/* ------------------------------------------------------------------
Defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Structure definitions
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Global variables
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Function prototypes
------------------------------------------------------------------ */
int
fgetline2( FILE *fh, char *line_buf, int line_len )
{
int rv,do_again;
char *cp;
do
{
rv = fgetline( fh, line_buf, line_len );
do_again=0;
if (rv==0)
{
cp = line_buf;
/* skip past spaces */
while ( *cp=='\t' || *cp==' ' )
cp++;
if (*cp=='\0' || *cp=='#')
do_again=1;
}
}while (do_again);
return(rv);
}
/* -- End of File -- */

70
libsrc/fprintfile.c Normal file
View file

@ -0,0 +1,70 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pwd.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <memory.h>
#include <malloc.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/timestamp.h>
#include <mplib1/fprintfile.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
fprintfile( FILE *fp, const char *format, ... )
{
int rv;
va_list ap;
/* put the time string on the front */
fput_log_str( fp );
/* now send the rest of the string */
va_start( ap, format );
rv = vfprintf( fp, format, ap );
va_end( ap );
return( rv );
}
/* -- End of File -- */

69
libsrc/fput_log_str.c Normal file
View file

@ -0,0 +1,69 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* $Log$
*
*******************************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pwd.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <memory.h>
#include <malloc.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/timestamp.h>
#include <mplib1/pid_check.h>
#include <mplib1/fprintfile.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
fput_log_str( FILE *fh )
{
char pid_str[PID_STR_LEN];
int rv;
gen_pid_str( pid_str, getpid() );
rv = fprintf( fh, "%s %s %s ",
make_timestamp_str( NULL ),
pid_str,
get_my_uname() );
return(rv);
}
/* -- End of File -- */

79
libsrc/get_uname.c Normal file
View file

@ -0,0 +1,79 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pwd.h>
#include <time.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/timestamp.h>
#include <mplib1/pid_check.h>
#include <mplib1/fprintfile.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
static char unknown[]="UNKNOWN";
static char *me_name=NULL;
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
char *
get_my_uname( void )
{
struct passwd *pwd;
if (me_name==NULL)
{
pwd = getpwuid(getuid());
if (pwd)
{
me_name = strdup( pwd->pw_name );
}else
{
me_name = malloc( PID_STR_LEN + 2 );
if (me_name)
sprintf( me_name, "[%d]", (int)getuid() );
}
if (me_name==NULL)
me_name = unknown;
}
return(me_name);
}
/* -- End of File -- */

286
libsrc/index.html Normal file
View file

@ -0,0 +1,286 @@
<html>
<head>
<title>File Index</title>
</head>
<body bgcolor="#ffffff" text="#000000">
<h1>File Index</h1>
<ul>
<li><a href="safe_string.c"> safe_string.c </a>
<li><a href="stricmp.c"> stricmp.c </a>
<li><a href="time_1.c"> time_1.c </a>
<li><a href="time_2.c"> time_2.c </a>
<li><a href="time_3.c"> time_3.c </a>
<li><a href="get_uname.c"> get_uname.c </a>
<li><a href="make_log_str.c"> make_log_str.c </a>
<li><a href="fput_log_str.c"> fput_log_str.c </a>
<li><a href="fprintfile.c"> fprintfile.c </a>
<li><a href="pidstr.c"> pidstr.c </a>
<li><a href="min_list.c"> min_list.c </a>
<li><a href="dl_l_001.c"> dl_l_001.c </a>
<li><a href="dl_l_002.c"> dl_l_002.c </a>
<li><a href="dl_l_003.c"> dl_l_003.c </a>
<li><a href="dl_l_004.c"> dl_l_004.c </a>
<li><a href="dl_l_005.c"> dl_l_005.c </a>
<li><a href="dl_l_006.c"> dl_l_006.c </a>
<li><a href="dl_l_007.c"> dl_l_007.c </a>
<li><a href="dl_l_008.c"> dl_l_008.c </a>
<li><a href="dl_l_009.c"> dl_l_009.c </a>
<li><a href="dl_l_010.c"> dl_l_010.c </a>
<li><a href="dl_l_011.c"> dl_l_011.c </a>
<li><a href="dl_l_012.c"> dl_l_012.c </a>
<li><a href="dl_l_013.c"> dl_l_013.c </a>
<li><a href="dl_l_014.c"> dl_l_014.c </a>
<li><a href="dl_l_015.c"> dl_l_015.c </a>
<li><a href="dl_l_016.c"> dl_l_016.c </a>
<li><a href="dl_l_017.c"> dl_l_017.c </a>
<li><a href="dl_l_018.c"> dl_l_018.c </a>
<li><a href="dl_l_019.c"> dl_l_019.c </a>
<li><a href="dl_l_020.c"> dl_l_020.c </a>
<li><a href="dl_l_021.c"> dl_l_021.c </a>
<li><a href="mpstrtok.c"> mpstrtok.c </a>
<li><a href="cfg_f_001.c"> cfg_f_001.c </a>
<li><a href="cfg_f_002.c"> cfg_f_002.c </a>
<li><a href="cfg_f_003.c"> cfg_f_003.c </a>
<li><a href="cfg_f_004.c"> cfg_f_004.c </a>
<li><a href="cfg_f_005.c"> cfg_f_005.c </a>
<li><a href="cfg_f_006.c"> cfg_f_006.c </a>
<li><a href="cfg_f_007.c"> cfg_f_007.c </a>
<li><a href="cfg_f_008.c"> cfg_f_008.c </a>
<li><a href="cfg_f_009.c"> cfg_f_009.c </a>
<li><a href="cfg_f_010.c"> cfg_f_010.c </a>
<li><a href="cfg_f_011.c"> cfg_f_011.c </a>
<li><a href="cfg_f_012.c"> cfg_f_012.c </a>
<li><a href="cfg_f_013.c"> cfg_f_013.c </a>
<li><a href="cfg_f_014.c"> cfg_f_014.c </a>
<li><a href="cfg_f_015.c"> cfg_f_015.c </a>
<li><a href="cfg_f_016.c"> cfg_f_016.c </a>
<li><a href="cfg_f_017.c"> cfg_f_017.c </a>
<li><a href="cfg_f_018.c"> cfg_f_018.c </a>
<li><a href="cfg_f_019.c"> cfg_f_019.c </a>
<li><a href="cfg_f_020.c"> cfg_f_020.c </a>
<li><a href="cfg_f_021.c"> cfg_f_021.c </a>
<li><a href="cfg_watch.c"> cfg_watch.c </a>
<li><a href="lock_file.c"> lock_file.c </a>
<li><a href="bpo_nap.c"> bpo_nap.c </a>
<li><a href="bpo_lock.c"> bpo_lock.c </a>
<li><a href="bpo_lock_rw.c"> bpo_lock_rw.c </a>
<li><a href="bpo_lock_pid.c"> bpo_lock_pid.c </a>
<li><a href="bpo_lock_flg.c"> bpo_lock_flg.c </a>
<li><a href="bpo_l_001.c"> bpo_l_001.c </a>
<li><a href="bpo_l_002.c"> bpo_l_002.c </a>
<li><a href="bpo_l_003.c"> bpo_l_003.c </a>
<li><a href="bpo_l_004.c"> bpo_l_004.c </a>
<li><a href="bpo_l_005.c"> bpo_l_005.c </a>
<li><a href="bpo_l_006.c"> bpo_l_006.c </a>
<li><a href="bpo_l_007.c"> bpo_l_007.c </a>
<li><a href="bpo_l_008.c"> bpo_l_008.c </a>
<li><a href="bpo_l_009.c"> bpo_l_009.c </a>
<li><a href="bpo_l_010.c"> bpo_l_010.c </a>
<li><a href="bpo_l_011.c"> bpo_l_011.c </a>
<li><a href="bpo_l_012.c"> bpo_l_012.c </a>
<li><a href="bpo_l_013.c"> bpo_l_013.c </a>
<li><a href="bpo_l_014.c"> bpo_l_014.c </a>
<li><a href="bpo_l_015.c"> bpo_l_015.c </a>
<li><a href="bpo_l_016.c"> bpo_l_016.c </a>
<li><a href="bpo_l_017.c"> bpo_l_017.c </a>
<li><a href="bpo_l_018.c"> bpo_l_018.c </a>
<li><a href="bpo_l_019.c"> bpo_l_019.c </a>
<li><a href="bpo_l_020.c"> bpo_l_020.c </a>
<li><a href="bpo_l_021.c"> bpo_l_021.c </a>
<li><a href="bpo_l_022.c"> bpo_l_022.c </a>
<li><a href="bpo_l_023.c"> bpo_l_023.c </a>
<li><a href="bpo_l_024.c"> bpo_l_024.c </a>
<li><a href="bpo_l_025.c"> bpo_l_025.c </a>
<li><a href="bpo_l_026.c"> bpo_l_026.c </a>
<li><a href="bpo_l_027.c"> bpo_l_027.c </a>
<li><a href="bpo_l_028.c"> bpo_l_028.c </a>
<li><a href="bpo_init.c"> bpo_init.c </a>
<li><a href="bpo_resource.c"> bpo_resource.c </a>
<li><a href="bpo_res_2.c"> bpo_res_2.c </a>
<li><a href="bpo_val_res.c"> bpo_val_res.c </a>
<li><a href="bpo_alloc.c"> bpo_alloc.c </a>
<li><a href="bpo_proc_me.c"> bpo_proc_me.c </a>
<li><a href="bpo_proc.c"> bpo_proc.c </a>
<li><a href="bpo_proc_cln.c"> bpo_proc_cln.c </a>
<li><a href="bpo_val_proc.c"> bpo_val_proc.c </a>
<li><a href="bpo_queue.c"> bpo_queue.c </a>
<li><a href="bpo_msg.c"> bpo_msg.c </a>
<li><a href="bpo_val_q.c"> bpo_val_q.c </a>
<li><a href="bpo_attach.c"> bpo_attach.c </a>
<li><a href="vre_alloc.c"> vre_alloc.c </a>
<li><a href="vre_disp.c"> vre_disp.c </a>
<li><a href="vre_parse.c"> vre_parse.c </a>
<li><a href="vre_loop.c"> vre_loop.c </a>
<li><a href="fgetline.c"> fgetline.c </a>
<li><a href="fgetline2.c"> fgetline2.c </a>
<li><a href="match_tok.c"> match_tok.c </a>
<li><a href="lmsort.c"> lmsort.c </a>
<li><a href="lmsort_m.c"> lmsort_m.c </a>
<li><a href="dl_sort_i.c"> dl_sort_i.c </a>
<li><a href="dl_sort_n.c"> dl_sort_n.c </a>
<li><a href="bpo_sort_i.c"> bpo_sort_i.c </a>
<li><a href="bpo_sort_n.c"> bpo_sort_n.c </a>
<li><a href="dl_lru.c"> dl_lru.c </a>
<li><a href="dl_lru_rep.c"> dl_lru_rep.c </a>
<li><a href="dl_lru_range.c"> dl_lru_range.c </a>
<li><a href="dumphex.c"> dumphex.c </a>
<li><a href="bpo_val_list.c"> bpo_val_list.c </a>
<li><a href="bpo_val_lst2.c"> bpo_val_lst2.c </a>
<li><a href="gdbm_util.c"> gdbm_util.c </a>
<li><a href="gdbm_util2.c"> gdbm_util2.c </a>
<li><a href="mpbasename.c"> mpbasename.c </a>
<li><a href="build_argv.c"> build_argv.c </a>
<li><a href="inthand.c"> inthand.c </a>
<li><a href="leavesub.c"> leavesub.c </a>
<li><a href="daemonloop.c"> daemonloop.c </a>
<li><a href="daemonsleep.c"> daemonsleep.c </a>
<li><a href="stopwatch_c.c"> stopwatch_c.c </a>
<li><a href="stopwatch.c"> stopwatch.c </a>
<li><a href="cpustopwatch.c"> cpustopwatch.c </a>
<p>
<li><a href="Makefile"> Makefile </a>
</ul>
<p>
</body>
</html>

152
libsrc/inthand.c Normal file
View file

@ -0,0 +1,152 @@
/*
*******************************************************************************
* Copyright (c) 1994 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* System :
* Subsystem :
* Module :
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <mplib1/daemon.h>
/* ------------------------------------------------------------------
structures / defines
------------------------------------------------------------------ */
static int been_signalled=0;
static struct sigaction my_sigaction1;
static struct sigaction my_sigaction2;
static struct sigaction my_sigaction3;
static struct sigaction my_sigaction4;
static struct sigaction my_sigaction5;
static int set_sysint=0;
static struct sigaction save_sigaction1;
static struct sigaction save_sigaction2;
static struct sigaction save_sigaction3;
static struct sigaction save_sigaction4;
static struct sigaction save_sigaction5;
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static void
myint_handler( int sig )
{
been_signalled = sig;
return;
}
static void
set_thisint( int this_sig, struct sigaction *sigactp )
{
memset( sigactp, '\0', sizeof(struct sigaction) );
sigactp->sa_flags = SA_RESTART;
sigactp->sa_handler = myint_handler;
(void)sigaction( this_sig, sigactp, NULL );
return;
}
void
init_signalling( void )
{
set_thisint( SIGINT, &my_sigaction1 );
set_thisint( SIGTERM, &my_sigaction2 );
set_thisint( SIGUSR1, &my_sigaction3 );
set_thisint( SIGUSR2, &my_sigaction4 );
set_thisint( SIGHUP, &my_sigaction5 );
signal( SIGCHLD, SIG_IGN );
return;
}
int
check_signalling( void )
{
int rv;
rv = been_signalled;
been_signalled = 0;
return(rv);
}
static void
allow_thisint( int this_sig, struct sigaction *sigactp )
{
int rv;
struct sigaction prep_sigaction;
rv = sigaction( this_sig, NULL, sigactp );
memcpy( &prep_sigaction, sigactp, sizeof(struct sigaction) );
prep_sigaction.sa_flags &= ~SA_RESTART;
rv = sigaction( this_sig, &prep_sigaction, NULL );
return;
}
int
allow_sysint( void )
{
if (set_sysint==0)
{
allow_thisint( SIGINT, &save_sigaction1 );
allow_thisint( SIGTERM, &save_sigaction2 );
allow_thisint( SIGUSR1, &save_sigaction3 );
allow_thisint( SIGUSR2, &save_sigaction4 );
allow_thisint( SIGHUP, &save_sigaction5 );
set_sysint=1;
}
return(0);
}
int
deny_sysint( void )
{
if (set_sysint==1)
{
(void)sigaction( SIGINT, &save_sigaction1, NULL );
(void)sigaction( SIGTERM, &save_sigaction2, NULL );
(void)sigaction( SIGUSR1, &save_sigaction3, NULL );
(void)sigaction( SIGUSR2, &save_sigaction4, NULL );
(void)sigaction( SIGHUP, &save_sigaction5, NULL );
set_sysint=0;
}
return(0);
}
/* -- End of File -- */

131
libsrc/leavesub.c Normal file
View file

@ -0,0 +1,131 @@
/*
*******************************************************************************
* Copyright (c) 1995 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* System :
* Subsystem :
* Module :
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <mplib1/cfg_file.h>
#include <mplib1/daemon.h>
/* ------------------------------------------------------------------
structures / defines / variables
------------------------------------------------------------------ */
static char stdin_name[]="STDIN";
static char stdout_name[]="STDOUT";
static char stderr_name[]="STDERR";
static char def_name[]="/dev/null";
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static char *
get_one_name( const char *from )
{
char *cp;
cp = eval_config_default( from, (char *)NULL );
if (cp==NULL || *cp=='\0')
cp = def_name;
return(cp);
}
int
restart_files( void )
{
freopen( get_one_name( stdin_name ), "r", stdin );
freopen( get_one_name( stdout_name ), "a", stdout );
freopen( get_one_name( stderr_name ), "a", stderr );
setbuf( stderr, NULL );
return(1);
}
static const char *
get_some_name( const char *from )
{
if (from==NULL || *from=='\0')
from = def_name;
return(from);
}
int
restart_these_files( const char *in_name,
const char *out_name,
const char *err_name )
{
freopen( get_some_name( in_name ), "r", stdin );
freopen( get_some_name( out_name ), "a", stdout );
freopen( get_some_name( err_name ), "a", stderr );
setbuf( stderr, NULL );
return(1);
}
pid_t
leavehome( void )
{
pid_t t;
/* In this function we will attempt to disconnect ourselves from the
outside world.
1. We close all standard files, and open supplied ones instead.
2. We fork. The parent dies, and the child continues.
3. We setsid() to make ourselves moderately bullet-proof.
*/
restart_files( );
/* Now fork */
t = fork();
if (t > (pid_t)0)
{
/* We are the parent, so time to die */
exit(0);
}else if (t == (pid_t)0)
{
/* Time to setsid */
setsid();
}else
{
/* oh dear */
}
return(t);
}
/* -- End of File -- */

226
libsrc/lmsort.c Normal file
View file

@ -0,0 +1,226 @@
/*
*
* Optimal list-merge sorting algorithm with exponential merge schedule.
*
* From: Software Development International, Winter 1991.
*
* This implementation by Jeremy Harris jgh@imptld.com
*
* Adapted into toolkit by Martin Poole mpoole@cix.compulink.co.uk
*
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* $Source$
* $Author$
* $Date$
* $Revision$
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifdef TRACE
#undef TRACE
#define TRACE(x) printf x
#else
#define NO_TRACE
#define TRACE(x) /*empty*/
#endif
#define MAXHOOKS 24 /* permits merging up to 33,554,430 records */
#define KEYVAL(dataitem) dataitem
#define GETKEY(datapp) KEYVAL(*(datapp)->dp)
/* ------------------------------------------------------------------
includes
------------------------------------------------------------------ */
#include <sys/types.h>
#ifdef NO_TRACE
#include <stdio.h>
#endif
#include <mplib1/mplib1_config.h>
#include <mplib1/lmsort.h>
/* ------------------------------------------------------------------
variables
------------------------------------------------------------------ */
static int (*compare)( const void *, const void *);
/* ------------------------------------------------------------------
code starts here
------------------------------------------------------------------ */
static struct lmsortp *
binmerge( register struct lmsortp * datap_a,
register struct lmsortp * datap_b )
{
register struct lmsortp * tail;
struct lmsortp * start;
/* Initialisation */
if( (*compare)( datap_a->dp, datap_b->dp ) > 0 )
{
start= datap_b;
goto b_wins;
}
start= datap_a;
a_wins: do
{
tail= datap_a;
if( !(datap_a= datap_a->next) )
{
tail->next= datap_b;
return(start);
}
} while( (*compare)( datap_a->dp, datap_b->dp ) <= 0 );
tail->next= datap_b;
b_wins: do
{
tail= datap_b;
if( !(datap_b= datap_b->next) )
{
tail->next= datap_a;
return(start);
}
} while( (*compare)( datap_a->dp, datap_b->dp ) >= 0 );
tail->next= datap_a;
goto a_wins;
/*NOTREACHED*/
}
struct lmsortp *
lmsort( struct lmsortp * start, int (*compar)(const void *, const void *) )
{
int k;
struct lmsortp * temp;
struct lmsortp * this_one;
struct lmsortp * next_one;
struct lmsortp * runhook[MAXHOOKS];
/* Initialisation */
compare = compar;
for( k= 0; k < MAXHOOKS; k++ )
runhook[k]= 0;
this_one= start;
while( this_one )
{
temp= this_one;
next_one= this_one->next;
if( next_one )
{
/* Run Linker */
if( (*compare)( this_one->dp, next_one->dp ) <= 0 )
{
/* Non-descending-order run */
TRACE( ("linker: run up\n%d", GETKEY(this_one) ) );
do /* no need to relink default */
{
TRACE( (" %d", GETKEY(next_one)) );
this_one= next_one;
next_one= this_one->next;
} while( next_one && (*compare)( this_one->dp, next_one->dp ) <= 0 );
this_one->next= 0; /* terminate run up */
TRACE( ("\n") );
}
else
{
/* Descending-order run */
TRACE( ("linker: run down\n%d", GETKEY(this_one) ) );
this_one->next= 0; /* terminate run down */
do /* relink backwards */
{
TRACE( (" %d", GETKEY(next_one)) );
temp= next_one;
next_one= next_one->next;
temp->next= this_one;
this_one= temp;
} while( next_one && (*compare)( this_one->dp, next_one->dp ) >= 0 );
TRACE( ("\n") );
}
}
/* "temp" is now the head of a non-descending run */
/* Merge Scheduler */
TRACE( ("Merge Scheduler\n") );
k= 0;
do /* Put the sublist on a hook */
{
TRACE( ("hook %d", k) );
if( runhook[k] )
{
/* Hook is occupied; merge and retry at hook k+1. */
TRACE( (" was in use; merging\n") );
temp= binmerge( runhook[k], temp );
runhook[k]= 0;
}
else
{
TRACE( (" was free\n") );
runhook[k]= temp;
temp= 0; /* flag for loop exit */
}
k++;
} while( temp );
this_one= next_one;
}
/*
* Run Collector.
* At this point the eof has been found, so the runs in
* runhook must be collected from the bottom up to keep it stable.
*/
TRACE( ("Collector\n") );
k= 0;
while( !runhook[k] )
{
TRACE( ("hook %d free\t", k) );
k++;
}
TRACE( ("list on hook %d\n", k) );
start= runhook[k];
while( ++k < MAXHOOKS )
if( runhook[k] )
{
TRACE( ("merging with list on hook %d\n", k) );
start= binmerge( runhook[k], start );
}
else
TRACE( ("hook %d free\t", k) );
TRACE( ("finished\n") );
return( start );
}
/* -- End of File -- */

88
libsrc/lmsort_m.c Normal file
View file

@ -0,0 +1,88 @@
/*
*
* Optimal list-merge sorting algorithm with exponential merge schedule.
*
* From: Software Development International, Winter 1991.
*
* This implementation by Jeremy Harris jgh@imptld.com
*
* Adapted into toolkit by Martin Poole mpoole@cix.compulink.co.uk
*
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* $Source$
* $Author$
* $Date$
* $Revision$
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
includes
------------------------------------------------------------------ */
#include <sys/types.h>
#include <stdlib.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/lmsort.h>
/* ------------------------------------------------------------------
variables
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
code starts here
------------------------------------------------------------------ */
struct lmsortp *
lmsort_init( void* base, size_t nel, size_t width, struct lmsortp *dp )
{
struct lmsortp *dp2;
int i;
if (dp==NULL)
dp = malloc( nel * sizeof(struct lmsortp) );
if (dp)
{
/* we can only sort if there is enough memory */
dp2=dp;
for (i=0; i<nel; i++)
{
dp2->next = dp2+1;
dp2->dp = base;
dp2++;
base = (void *)( ((char *)base) + width );
}
dp2--;
dp2->next=NULL;
}
return(dp);
}
void
lmsort_end( struct lmsortp *dp )
{
if (dp)
{
free(dp);
}
return;
}
/* -- End of File -- */

93
libsrc/lock_file.c Normal file
View file

@ -0,0 +1,93 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/pid_check.h>
#include <mplib1/fprintfile.h>
#include <mplib1/lock_file.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
lock_reg( int fd, int cmd, short type, off_t offset, short whence, off_t len )
{
struct flock lock;
lock.l_type = type;
lock.l_start = offset;
lock.l_whence = whence;
lock.l_len = len;
return( fcntl( fd, cmd, &lock ) );
}
int
lock_file( const char *filename )
{
int fd,val;
int rv = 0;
char buf[PID_STR_LEN];
if ( (fd = open( filename, O_WRONLY | O_CREAT, 0644 )) >= 0)
{
gen_pid_str( buf, getpid() );
if ( (write_lock( fd, 0, SEEK_SET, 0) >= 0)
&& (ftruncate(fd, 0) >= 0)
&& (write(fd,buf,strlen(buf)) == strlen(buf))
&& ( (val = fcntl(fd, F_GETFD, 0)) >= 0)
)
{
val |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, val) >=0 )
rv=1;
}
if (rv==0)
close(fd);
}
return(rv);
}
/* -- End of File -- */

71
libsrc/make_log_str.c Normal file
View file

@ -0,0 +1,71 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* $Log$
*
*******************************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pwd.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <memory.h>
#include <malloc.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/timestamp.h>
#include <mplib1/pid_check.h>
#include <mplib1/fprintfile.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
char *
make_log_str( char *buf )
{
static char log_str[TIMESTAMP_STR_SZ];
char pid_str[PID_STR_LEN];
char *tstr;
if (buf==NULL)
buf=log_str;
tstr = make_timestamp_str( NULL );
gen_pid_str( pid_str, getpid() );
sprintf( buf, "%s %s %s ",
tstr, pid_str, get_my_uname() );
return(buf);
}
/* -- End of File -- */

220
libsrc/match_tok.c Normal file
View file

@ -0,0 +1,220 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/match_tok.h>
/* ------------------------------------------------------------------
Defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Structure definitions
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Global variables
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Function prototypes
------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------
Function : match_string
Summary : This function return whether the line parameter
: contains the string in the match parameter
: It will allow the match string to be bound to
: the start of the line (ala grep)
: It will also return a pointer to the first
: non-blank token after the match (or the start
: of the string
Input Parameters : pointer line buffer
: pointer to matching string
Output Parameters : pointer to a character pointer for next token
: return value
Global Variables : None
Return Value : 1 == found 0 == not found
--------------------------------------------------------------------------*/
int
match_string ( const char *line_ptr,
const char *match_ptr,
char ** next_tok )
{
int rv = 0;
const char *cp2=NULL,*ttok;
ttok = line_ptr;
if (*match_ptr == '^')
{
match_ptr++;
cp2 = strstr(line_ptr,match_ptr);
if (cp2 == line_ptr)
rv = 1;
}
else
{
cp2 = strstr(line_ptr,match_ptr);
if (cp2 != NULL )
rv = 1;
}
if (next_tok)
{
if (rv)
{
/* skip past matched token and point to next token */
cp2 += strlen(match_ptr);
while (*cp2 == ' ')
cp2++;
*next_tok = (char *)(size_t)cp2;
}
else
*next_tok = (char *)(size_t)ttok;
}
return(rv);
}
/* ---------------------------------------------------------------------------
Function : match_a_string
Summary : This function return whether the line parameter
: matches one of the parameters in the match_token
: list
: It will allow the match string to be bound to
: the start of the line (ala grep)
: It will also return a pointer to the first
: non-blank token after the match (or the start
: of the string
Input Parameters : pointer line buffer
: pointer to match token list
: this is a pointer to an array of type match_token
: the array is terminated by a entry with a NULL
: m_ptr
Output Parameters : pointer to a character pointer for next token
: return value
Global Variables : None
Return Value : value specified in matched token or
: value on the terminating token
--------------------------------------------------------------------------*/
int
match_a_string ( const char *line_ptr,
struct match_token *match_ptr,
char ** next_tok )
{
int rv;
if (next_tok)
*next_tok=(char *)(size_t)line_ptr;
rv=match_ptr->m_val;
while ( match_ptr->m_ptr
&& match_string( line_ptr, match_ptr->m_ptr, next_tok )==0
)
{
match_ptr++;
rv=match_ptr->m_val;
};
return(rv);
#if 0
int rv = matched = 0,sl;
char *cp,*cp2=NULL,*ttok;
ttok = (char *)line_ptr;
do
while ((cp = (char *)match_ptr->m_ptr) && rv == 0)
{
if (*cp == '^')
{
cp++;
cp2 = strstr(line_ptr,cp);
if (cp2 == line_ptr)
{
sl = strlen(cp);
rv = match_ptr->m_val;
}
}
else
{
cp2 = strstr(line_ptr,cp);
if (cp2 != NULL )
{
sl = strlen(cp);
rv = match_ptr->m_val;
}
}
#ifdef DEBUG
/*if (rv)*/
/*printf("Found entry %d <%s> in <%s>\n",rv,cp,line_ptr);*/
#endif
match_ptr++;
}
if (next_tok)
if (cp2 && rv)
{
/* skip past matched token and point to next token */
cp2 += sl;
while (*cp2 == ' ')
cp2++;
#ifdef DEBUG
/*if (rv)*/
/*printf("moving to <%s>\n",cp2);*/
#endif
*next_tok = cp2;
}
else
*next_tok = ttok;
return(rv);
#endif
}
/* -- End of File -- */

125
libsrc/min_list.c Normal file
View file

@ -0,0 +1,125 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose : min list handling
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <mplib1/mplib1_config.h>
#include <mplib1/min_list.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
#ifndef NULL
#define NULL ((void *)0)
#endif
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
int
Init_Min_Node( Min_Node *node )
{
INIT_MIN_NODE(node);
return(0);
}
int
Init_Min_List( Min_List *list )
{
list->ln_Head.ln_Pred = NULL;
list->ln_Head.ln_Succ = &list->ln_Tail;
list->ln_Tail.ln_Pred = &list->ln_Head;
list->ln_Tail.ln_Succ = NULL;
return(0);
}
int
Remove_Min_Node ( Min_Node *node )
{
if (node->ln_Succ)
node->ln_Succ->ln_Pred = node->ln_Pred;
if (node->ln_Pred)
node->ln_Pred->ln_Succ = node->ln_Succ;
return(0);
}
int
Add_To_Min_Head ( Min_List *list, Min_Node *node )
{
/* First remove node from previous list (if any) */
Remove_Min_Node( node );
/* Now set up Node in new position */
ADD_MIN_AFTER( &list->ln_Head, node );
return(0);
}
int
Add_To_Min_Tail ( Min_List *list, Min_Node *node )
{
/* First remove node from previous list (if any) */
Remove_Min_Node( node );
/* Now set up Node in new position */
ADD_MIN_BEFORE( &list->ln_Tail, node );
return(0);
}
int
Add_Min_After ( Min_Node *node1, Min_Node *node2 )
{
/* First remove node from previous list (if any) */
Remove_Min_Node( node2 );
/* Now set up Node in new position */
ADD_MIN_AFTER( node1, node2 );
return(0);
}
int
Add_Min_Before ( Min_Node *node1, Min_Node *node2 )
{
/* First remove node from previous list (if any) */
Remove_Min_Node( node2 );
/* Now set up Node in new position */
ADD_MIN_BEFORE( node1, node2 );
return(0);
}
/* -- End of File -- */

72
libsrc/mpbasename.c Normal file
View file

@ -0,0 +1,72 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/mpbasename.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------
Function : mpbasename
Summary : This function returns a pointer to the base name
: of the filename given
Input Parameters : pointer to a filename
Output Parameters : None
Global Variables : None
Return Value : pointer to basename of filename
--------------------------------------------------------------------------*/
char *
mpbasename ( const char *full_name )
{
const char *cp;
cp = full_name + strlen(full_name) - 1;
while ( cp > full_name && *cp != '/' ) cp --;
if ( *cp == '/' ) cp++;
return((char *)(size_t)cp);
}
/* -- End of File -- */

108
libsrc/mpstrtok.c Normal file
View file

@ -0,0 +1,108 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/mpstrtok.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
struct strtok
{
char *str_st;
char *str_end;
char *str_nxt;
};
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
char *
mpstrtok( char *str, void **ftok, const char *seps )
{
struct strtok *tok= *ftok;
char *cp,*cp2;
if (str)
{
/* first call, set things up and give first details */
tok = (struct strtok *)malloc(sizeof(struct strtok));
*ftok = tok;
if (tok == NULL)
return(NULL);
tok->str_st = str;
tok->str_end = str + strlen(str);
tok->str_nxt = str;
}else if (tok==NULL)
return(NULL);
if (seps==NULL)
{
/* early termination, free memory */
free(tok);
*ftok = NULL;
return(NULL);
}
/* skip leading seperators */
cp = tok->str_nxt;
while (*cp && strchr(seps,*cp)) cp++;
/* have we gone too far ? */
if (cp >= tok->str_end)
{
free(tok);
*ftok = NULL;
return(NULL);
}
/* now mark the end of the string */
cp2 = cp;
while (*cp2 && strchr(seps,*cp2)==NULL) cp2++;
tok->str_nxt = cp2 + ((*cp2)? 1 : 0);
*cp2 = '\0';
return(cp);
}
/* -- End of File -- */

73
libsrc/pidstr.c Normal file
View file

@ -0,0 +1,73 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/pid_check.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
void
gen_pid_str( char *buf, pid_t the_pid )
{
if (buf)
{
sprintf( buf, "%ld", (long)the_pid );
}
return;
}
int
is_pid_dead( pid_t the_pid )
{
int rv;
rv = kill( the_pid, 0 );
if (rv!=0 && errno!=ESRCH)
rv=0;
return(rv);
}
/* -- End of File -- */

70
libsrc/safe_string.c Normal file
View file

@ -0,0 +1,70 @@
/*
*******************************************************************************
* Copyright (c) 1997 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source$
* $Author$
* $Date$
* $Revision$
* Purpose : Safe strlen
*
*******************************************************************************
*
* Change History
*
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdlib.h>
#include <string.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/safe_string.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
size_t
Sstrlen( const char *str1 )
{
size_t i;
if (str1)
i=strlen(str1);
else
i=0;
return(i);
}
char *
Sstrcpy( char *str1, const char *str2 )
{
if (str2)
strcpy( str1, str2 );
else
*str1='\0';
return(str1);
}
/* -- End of File -- */

120
libsrc/stopwatch.c Normal file
View file

@ -0,0 +1,120 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/stopwatch.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static int
get_time( struct timeval *tvp )
{
int rv;
#ifdef H_GETTIMEOFDAY_2_NULL
rv = gettimeofday( tvp, NULL );
#else
#ifdef H_GETTIMEOFDAY_2_PARAMS
struct timezone my_tz;
my_tz.tz_minuteswest = 0;
my_tz.tz_dsttime = 0;
rv = gettimeofday( tvp, &my_tz );
#else
rv = gettimeofday( tvp );
#endif
#endif
return(rv);
}
int
init_stopwatch( struct stopwatch *stp )
{
if (stp)
memset( stp, '\0', sizeof(struct stopwatch) );
return(0);
}
int
start_stopwatch( struct stopwatch *stp )
{
int rv;
if (stp)
{
rv = get_time( &stp->start_time );
}else
{
rv= -1;
errno = ENOENT;
}
return(rv);
}
int
stop_stopwatch( struct stopwatch *stp )
{
int rv;
struct timeval end_time;
if (stp && stp->start_time.tv_sec)
{
rv = get_time( &end_time );
accum_stop_timevals( stp, &end_time );
}else
{
rv= -1;
errno = ENOENT;
}
return(rv);
}
int
accrete_stopwatch( struct stopwatch *stp_into, struct stopwatch *stp_from )
{
add_timevals( &stp_into->cumulative_time, &stp_from->cumulative_time );
return(0);
}
/* -- End of File -- */

123
libsrc/stopwatch_c.c Normal file
View file

@ -0,0 +1,123 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
#ident "$Header$"
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/stopwatch.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
void
diff_timevals( struct timeval *end_p, struct timeval *start_p )
{
/* Generate the difference, subtract the start from the end */
end_p->tv_sec -= start_p->tv_sec;
if (end_p->tv_usec < start_p->tv_usec)
{
end_p->tv_usec = (end_p->tv_usec + 1000000 - start_p->tv_usec);
end_p->tv_sec--;
}else
{
end_p->tv_usec -= start_p->tv_usec;
}
return;
}
void
add_timevals( struct timeval *cump, struct timeval *tvp )
{
if (cump && tvp)
{
/* Now add it in */
cump->tv_usec += tvp->tv_usec;
if (cump->tv_usec >= 1000000)
{
cump->tv_usec -= 1000000;
cump->tv_sec++;
}
cump->tv_sec += tvp->tv_sec;
}
return;
}
void
accum_stop_timevals( struct stopwatch *stp, struct timeval *etp )
{
/* get the difference between the start and end time */
diff_timevals( etp, &stp->start_time );
/* Now add it in */
add_timevals( &stp->cumulative_time, etp );
return;
}
char *
display_stopwatch( struct stopwatch *stp, int mode )
{
switch( mode )
{
case 0 :
if (stp->cumulative_time.tv_sec < 1000)
{
sprintf( stp->elps_str, "%03d.%02d seconds",
(int)stp->cumulative_time.tv_sec,
(int)stp->cumulative_time.tv_usec/10000 );
}else
{
sprintf( stp->elps_str, "%06d.%02d seconds",
(int)stp->cumulative_time.tv_sec,
(int)stp->cumulative_time.tv_usec/10000 );
}
break;
default :
strcpy( stp->elps_str, "Unknown display mode" );
break;
}
return(stp->elps_str);
}
/* -- End of File -- */

106
libsrc/time.c Normal file
View file

@ -0,0 +1,106 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
* *
* $Source$
* $Author$
* $Date$
* $Revision$
* *
*******************************************************************************
* *
* $Log$
*
*******************************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pwd.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <memory.h>
#include <malloc.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/timestamp.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
struct timeval *
get_current_timeval( struct timeval *tvp )
{
if (tvp)
{
#ifdef H_GETTIMEOFDAY_2_NULL
gettimeofday( tvp, NULL );
#else
#ifdef H_GETTIMEOFDAY_2_PARAMS
struct timezone my_tz;
my_tz.tz_minuteswest = 0;
my_tz.tz_dsttime = 0;
gettimeofday( tvp, &my_tz );
#else
gettimeofday( tvp );
#endif
#endif
}
return(tvp);
}
char *
build_timestamp_str( struct timeval *tvp, char *buf )
{
char hunds[10];
struct tm *tim;
if (tvp && buf)
{
tim = gmtime((time_t *)&tvp->tv_sec);
/* Change to conform to ISO 8601 / EN 28601 */
strftime( buf, TIMESTAMP_STR_SZ, "%Y-%m-%d %H:%M:%S", tim );
sprintf( hunds, ".%02dZ", (int)(tvp->tv_usec / 10000L) );
strcat( buf, hunds );
}
return(buf);
}
char *
make_timestamp_str( char *buf )
{
static char log_str[TIMESTAMP_STR_SZ];
struct timeval tval;
get_current_timeval( &tval );
if (buf==NULL)
buf = log_str;
(void)build_timestamp_str( &tval, buf );
return(buf);
}
/* -- End of File -- */

535
libsrc/vre_alloc.c Normal file
View file

@ -0,0 +1,535 @@
/*
*******************************************************************************
* Copyright (c) 1996 Martin Poole *
*******************************************************************************
**
** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
**
** Any changes to be made to this file should first be checked with
** mplib1 source control for library integrity.
**
** mplib1 source control can be reached at mplib1@quatermass.co.uk
**
*
* $Source: /home/cvs/cvsroot/onelan/onelan/src/mplib1/libsrc/vre_alloc.c,v $
* $Author: mpoole $
* $Date: 2002/10/07 09:37:40 $
* $Revision: 1.2 $
* Purpose :
*
*******************************************************************************
*
* Change History
*
* $Log: vre_alloc.c,v $
* Revision 1.2 2002/10/07 09:37:40 mpoole
* Initial checkin of mplib1-3.1.0
*
* Revision 1.1 2002/10/07 09:36:57 mpoole
* Initial checkin of mplib1-3.1.0
*
*
*******************************************************************************
*/
#ident "$Header: /home/cvs/cvsroot/onelan/onelan/src/mplib1/libsrc/vre_alloc.c,v 1.2 2002/10/07 09:37:40 mpoole Exp $"
/* vre2disp.c
vogon record editor. Display only version
********************************************************************
Copyright 1989,90,91,94,95 Martin Poole
Released for use by Y2 Computing Limited - 1990
Released for use by Perot Systems Europe Limited - 1995.
********************************************************************
*/
/* ------------------------------------------------------------------
Include files
------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <mplib1/mplib1_config.h>
#include <mplib1/dl_list.h>
#include <mplib1/mpstrtok.h>
#include <mplib1/fgetline.h>
#include <mplib1/vre.h>
/* ------------------------------------------------------------------
defines
------------------------------------------------------------------ */
static dl_List_t object_list;
static int done_init=0;
static FILE *err_fp=NULL;
/* ------------------------------------------------------------------
Code starts here
------------------------------------------------------------------ */
static int
init_obj_list( void )
{
if (done_init==0)
{
done_init=1;
dl_Init_List( &object_list, 0 );
}
return(0);
}
int
vre_Init_VRE( FILE *fp )
{
err_fp = fp;
init_obj_list();
return(0);
}
static struct vre_type_obj *
alloc_type( const char *nm )
{
struct vre_type_obj *top;
top = (struct vre_type_obj *)malloc( sizeof(struct vre_type_obj) + strlen(nm) );
if (top)
{
dl_Init_Node( &top->to_Node, top->to_Name, top );
top->to_Flags = 0;
top->to_Disp = (vre_disp_t)NULL;
dl_Init_List( &top->to_Elems, 0 );
strcpy( top->to_Name, nm );
}
return(top);
}
struct vre_type_obj *
vre_Find_Type( const char *nm )
{
init_obj_list( );
return( (struct vre_type_obj *) dl_Find_Item_By_Name( &object_list, nm ));
}
int
vre_Add_Type( struct vre_type_obj *top )
{
int rv=0;
init_obj_list( );
if (!dl_Find_Item_By_Name( &object_list, top->to_Name ))
{
dl_Add_Tail( &object_list, &top->to_Node );
rv = 1;
}
return(rv);
}
struct vre_type_obj *
vre_Type_Synonym( const char *nm, const char *synm )
{
struct vre_type_obj *top=NULL,*top2;
init_obj_list( );
top2 = (struct vre_type_obj *)dl_Find_Item_By_Name( &object_list, synm );
if (top2)
{
top = (struct vre_type_obj *)dl_Find_Item_By_Name( &object_list, nm );
if (top)
return(NULL);
top = alloc_type( nm );
if (top)
{
top->to_Flags = TO_TYPEDEF;
top->to_Disp = (vre_disp_t)top2;
top->to_Size = top2->to_Size;
top->to_Align = top2->to_Align;
dl_Add_Tail( &object_list, &top->to_Node );
}
}
return(top);
}
struct vre_type_obj *
vre_New_Type( const char *nm,
vre_disp_t disp,
size_t isize,
int ialign,
int add )
{
struct vre_type_obj *top;
init_obj_list( );
top = (struct vre_type_obj *)dl_Find_Item_By_Name( &object_list, nm );
if (top)
return(NULL);
top = alloc_type( nm );
if (top)
{
if (disp)
{
top->to_Flags = TO_DISPLAY;
top->to_Disp = disp;
}
else
{
top->to_Flags = TO_COMPOSITE;
top->to_Disp = (vre_disp_t)NULL;
}
top->to_Size = isize;
top->to_Align = ialign;
if (add)
dl_Add_Tail( &object_list, &top->to_Node );
}
return(top);
}
struct vre_elem_obj *
vre_New_Elem( const char *nm,
const char *typ,
off_t offset,
int arr_sz )
{
struct vre_elem_obj *eop=NULL;
size_t als;
init_obj_list( );
if (dl_Find_Item_By_Name( &object_list, typ ))
{
/* Type exists so allow creation */
als = sizeof(struct vre_elem_obj)
+ (size_t)(strlen(nm) + strlen(typ) + 1);
eop = malloc( als );
if (eop)
{
strcpy( eop->eo_Type, typ );
eop->eo_Name = eop->eo_Type + strlen(eop->eo_Type) + 1;
strcpy( eop->eo_Name, nm );
dl_Init_Node( &eop->eo_Node, eop->eo_Name, eop );
eop->eo_Offset = offset;
eop->eo_Arr_sz = arr_sz;
}
}else
if (err_fp)
fprintf( err_fp, "Cannot find type <%s\n", typ );
return(eop);
}
struct vre_elem_obj *
vre_Cat_New_Elem( struct vre_type_obj *ntyp,
const char *el_nm,
const char *el_typ,
int arr_sz )
{
struct vre_elem_obj *eop=NULL;
struct vre_type_obj *top;
off_t offset;
top = vre_Find_Type( el_typ );
if (ntyp && top)
{
offset = (ntyp->to_Size + (top->to_Align - 1)) & ~(top->to_Align - 1);
eop = vre_New_Elem( el_nm, top->to_Name, offset, arr_sz );
if (eop)
{
dl_Add_Tail( &ntyp->to_Elems, &eop->eo_Node );
/* and now adjust the typ size */
if (ntyp->to_Align < top->to_Align)
{
/* set the align acording to the largest alignment */
ntyp->to_Align = top->to_Align;
}
if (offset>= ntyp->to_Size)
{
/* it's on the end of the structure */
if (arr_sz > 1)
ntyp->to_Size = (size_t)offset + (top->to_Size * (size_t)arr_sz);
else
ntyp->to_Size = (size_t)offset + top->to_Size;
}
}else
{
if (err_fp)
fprintf( stderr, "Unable to create new element <%s>\n", el_nm );
}
}else
{
/* not enough specified */
if (err_fp)
fprintf( stderr, "Unable to add element <%s><%s>\n", el_nm, el_typ );
}
return(eop);
}
static void
disp_this_type( struct vre_type_obj *top,
struct vre_disp_walk_item *dwip ); /* forward definition */
static void
disp_elems( struct vre_elem_obj *eop,
struct vre_disp_walk_item *dwip )
{
struct vre_type_obj *top;
const void *optr;
const char *olds;
char *cp;
top = dl_Find_Item_By_Name( &object_list, eop->eo_Type );
if (top)
{
cp = malloc( strlen(dwip->prefix)
+ strlen(eop->eo_Name) + 1 );
if (cp)
{
optr = dwip->ptr;
dwip->ptr = ((const char *)dwip->ptr + eop->eo_Offset);
olds = dwip->prefix;
dwip->prefix = cp;
sprintf( cp, "%s%s", olds, eop->eo_Name );
dwip->eop = eop;
dwip->top = top;
disp_this_type( top, dwip );
free( cp );
dwip->prefix = olds;
dwip->ptr = optr;
}else
{
fprintf( dwip->fp, " ** Cannot allocate for recursion **\n" );
}
}
return;
}
int
vre_Disp_Prefix( FILE *fp,
const void *ptr,
const void *base,
const char *prefix,
const char *suffix )
{
static char e_str[]="\0";
fprintf( fp, "%08x %s%s ",
(int)((const char *)ptr - (const char *)base),
(prefix)?prefix:e_str, (suffix)?suffix:e_str );
return(0);
}
static void
disp_this_type( struct vre_type_obj *top,
struct vre_disp_walk_item *dwip )
{
const char *olds;
char *cp;
if (dwip->flags & VRE_DISP_ELEM_NAMES)
vre_Disp_Prefix( dwip->fp, dwip->ptr, dwip->base, dwip->prefix, NULL );
while ( top && (top->to_Flags & TO_TYPEDEF))
top = (struct vre_type_obj *)top->to_Disp;
if (top)
{
if (top->to_Flags & TO_DISPLAY)
{
(* top->to_Disp)( dwip->ptr, dwip );
fputc( '\n', dwip->fp );
}else
{
cp = malloc( strlen(dwip->prefix)
+ strlen(top->to_Name) + 2 );
if (cp)
{
olds = dwip->prefix;
dwip->prefix = cp;
if (dwip->flags & VRE_DISP_ELEM_NAMES)
sprintf( cp, "%s.", olds );
fputc( '\n', dwip->fp );
dl_Walk_List( &top->to_Elems,
(dl_Walk_List_t)disp_elems, dwip );
free( cp );
dwip->prefix = olds;
}else
{
fprintf( dwip->fp, " ** Cannot allocate for recursion **\n" );
}
}
}else
{
fprintf( dwip->fp, " ** Cannot find type for display **\n" );
}
return;
}
int
vre_Get_Info( const char *el_nm,
size_t *isize,
int *ialign,
off_t *offset,
int *arr_sz,
int *flags )
{
struct vre_type_obj *top;
struct vre_elem_obj *eop;
int rv=0;
off_t soff;
char *pstr;
char *cp;
void *tokptr;
static char seps[]=".";
pstr = strdup(el_nm);
if (pstr)
{
/* mark off the single word */
cp = strstr( pstr, "\t " );
if (cp)
*cp = '\0';
/* set things up and walk the elements adding up the details */
cp=mpstrtok( pstr, &tokptr, seps );
if (cp)
{
top = vre_Find_Type( cp );
if (top)
{
soff=0;
eop = (struct vre_elem_obj *) -1;
while ( (cp = mpstrtok( NULL, &tokptr, seps ))
&& eop
&& top
)
{
eop = (struct vre_elem_obj *)dl_Find_Item_By_Name( &top->to_Elems, cp );
if (eop)
{
soff += eop->eo_Offset;
top = vre_Find_Type( eop->eo_Type );
}
};
if (eop && top)
{
if (offset)
*offset = soff;
if (isize)
*isize = top->to_Size;
if (arr_sz)
*arr_sz = eop->eo_Arr_sz;
if (ialign)
*ialign = top->to_Align;
rv = 1;
}
}
}
(void)mpstrtok( NULL, &tokptr, NULL );
free(pstr);
}
return(rv);
}
off_t
vre_Get_Offset( const char *el_nm )
{
off_t offset= -1,soff;
if ( vre_Get_Info( el_nm, NULL, NULL, &soff, NULL, NULL ))
offset=soff;
return(offset);
}
int
vre_Disp_Item( FILE *fp,
const char *type,
const char *name,
const void *ptr,
const void *base,
int flags,
void *u_param )
{
struct vre_type_obj *top;
struct vre_disp_walk_item dwi;
init_obj_list( );
top = (struct vre_type_obj *)dl_Find_Item_By_Name( &object_list, type );
if (top)
{
dwi.fp = fp;
dwi.prefix = (name)?name:type;
dwi.ptr = ptr;
dwi.base = base;
dwi.flags = flags;
dwi.u_param = u_param;
disp_this_type( top, &dwi );
}else
{
fprintf(fp, "Cannot find object of type <%s>\n", type );
}
return(0);
}
static void
disp_elem( void *vp1, void *vp2 )
{
FILE *fp;
struct vre_elem_obj *eop;
eop = vp1;
fp = vp2;
fprintf( fp, " Name: %s Offset: %08lx Arr: %08x Type: %s\n",
eop->eo_Name, eop->eo_Offset, eop->eo_Arr_sz, eop->eo_Type );
return;
}
static void
disp_type( void *vp1, void *vp2 )
{
FILE *fp;
struct vre_type_obj *top;
top = vp1;
fp = vp2;
if (top->to_Flags & TO_TYPEDEF)
{
struct vre_type_obj *top2;
top2 = top;
if (top2 && (top2->to_Flags & TO_TYPEDEF));
top2 = (struct vre_type_obj *) top2->to_Disp;
fprintf( fp, "Type: %s\n Flags: %08x Display: %p (%s)\n",
top->to_Name, top->to_Flags, top->to_Disp, top2->to_Name );
}else
fprintf( fp, "Type: %s\n Flags: %08x Display: %p\n",
top->to_Name, top->to_Flags, top->to_Disp );
fprintf( fp, " Size: %16zx Align: %08x\n",
top->to_Size, top->to_Align );
dl_Walk_List( &top->to_Elems, (dl_Walk_List_t)disp_elem, fp );
return;
}
int
vre_Disp_Types( FILE *fp, int flags )
{
dl_Walk_List( &object_list, (dl_Walk_List_t)disp_type, fp );
return(0);
}
/* -- End of File -- */

Some files were not shown because too many files have changed in this diff Show more