first commit
This commit is contained in:
commit
59a096572e
78
Makefile
Normal file
78
Makefile
Normal 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
5
Makefile.am
Normal 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
BIN
doc/bback.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 294 B |
BIN
doc/bpin.gif
Normal file
BIN
doc/bpin.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
47
doc/bpo_alloc.html
Normal file
47
doc/bpo_alloc.html
Normal 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
224
doc/bpo_init.html
Normal 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( &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
74
doc/bpo_intro.html
Normal 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 <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
</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 & 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
393
doc/bpo_list.html
Normal 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 >0, 0,
|
||||
of <0 just like <i>qsort</i> & <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> & <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>
|
37
doc/bpo_list_walk_demo.html
Normal file
37
doc/bpo_list_walk_demo.html
Normal 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
104
doc/bpo_lock.html
Normal 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
62
doc/bpo_lock_old.html
Normal 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
218
doc/bpo_proc.html
Normal 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
160
doc/bpo_queue.html
Normal 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
81
doc/build_argv.html
Normal 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<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->argc, argvtp->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
139
doc/cfg_eval.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
62
doc/cfg_example.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
47
doc/cfg_file.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
69
doc/cfg_init.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
117
doc/cfg_misc.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
67
doc/cfg_private.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
87
doc/cfg_read.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
62
doc/cfg_set.html
Normal 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 <mplib1/cfg_file.h>
|
||||
|
||||
</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
146
doc/configsummary.html
Normal 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
75
doc/cpustopwatch.html
Normal 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 <mplib1/stopwatch.h>
|
||||
|
||||
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
163
doc/daemon.html
Normal 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> & <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> & <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> &
|
||||
<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> & <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> & <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
27
doc/dl_add.html
Normal 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 <mplib1/dl_list.h>
|
||||
|
||||
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
27
doc/dl_find.html
Normal 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 <mplib1/dl_list.h>
|
||||
|
||||
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
250
doc/dl_list.html
Normal 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 <mplib1/dl_list.h>
|
||||
|
||||
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
382
doc/dl_lru.html
Normal 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 <mplib1/dl_lru.h>
|
||||
</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, &rf1, &rf2 );
|
||||
|
||||
if ( rv <= CACHE_MISSED )
|
||||
{
|
||||
rv = Database_Check( key_value, &rf1, &rf2 );
|
||||
|
||||
if ( rv == FOUND )
|
||||
{
|
||||
Add_Cache_Item( list_name, key_value, &rf1, &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, &rf1, &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, &rf1, &rf2 );
|
||||
|
||||
if ( rv == FOUND )
|
||||
{
|
||||
Add_Cache_Item( list_name, key_value, &rf1, &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, &rf1, &rf2 );
|
||||
|
||||
/* fiddle with values of rf1 & rf2 for some reason */
|
||||
|
||||
Find_Cache_Item( list_name, key_value, field_list, &rf1, &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
23
doc/dl_rem.html
Normal 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 <mplib1/dl_list.h>
|
||||
|
||||
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
45
doc/do_hex_dump.html
Normal 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 <mplib1/dumphex.h>
|
||||
|
||||
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
22
doc/dumphex.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> #include <dumphex.h> </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> #include <mplib1/dumphex.h> </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
68
doc/fgetline.html
Normal 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 <mplib1/fgetline.h>
|
||||
|
||||
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 <mplib1/fgetline.h>
|
||||
|
||||
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
103
doc/fprintfile.html
Normal file
|
@ -0,0 +1,103 @@
|
|||
<html>
|
||||
<head>
|
||||
<title> fprintfile </title>
|
||||
</head>
|
||||
<body bgcolor="#ffffff" text="#000000">
|
||||
<h1> fprintfile </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/fprintfile.h>
|
||||
</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: <%s> failed. Error %d\n",
|
||||
stn_name, SQLCODE );
|
||||
</pre>
|
||||
produces
|
||||
<pre>
|
||||
1996-12-31 13:45:56.78Z 22301 myname get_stn_name: <ZZZC69> 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
BIN
doc/gpin.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
28
doc/hex_dump.html
Normal file
28
doc/hex_dump.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> hex_dump() </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> hex_dump() </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/dumphex.h>
|
||||
|
||||
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
82
doc/index.html
Normal 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 <mplib1/stricmp.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="mpstrtok.html"> #include <mplib1/mpstrtok.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="fgetline.html"> #include <mplib1/fgetline.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="fprintfile.html"> #include <mplib1/fprintfile.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="dumphex.html"> #include <mplib1/dumphex.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="lock_file.html"> #include <mplib1/lock_file.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="lmsort.html"> #include <mplib1/lmsort.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="cfg_file.html"> #include <mplib1/cfg_file.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="dl_list.html"> #include <mplib1/dl_list.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="pid_check.html"> #include <mplib1/pid_check.h> </a>
|
||||
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="dl_lru.html"> #include <mplib1/dl_lru.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="vre.html"> #include <mplib1/vre.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="min_list.html"> #include <mplib1/min_list.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="match_tok.html"> #include <mplib1/match_tok.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="gdbm_util.html"> #include <mplib1/gdbm_util.h> </a>
|
||||
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="stopwatch.html"> #include <mplib1/stopwatch.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="pid_check.html"> #include <mplib1/pid_check.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="build_argv.html"> #include <mplib1/build_argv.h> </a>
|
||||
<dt><dd><img src="ppin.gif" align=bottom width=21 height=21>
|
||||
<a href="daemon.html"> #include <mplib1/daemon.h> </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
113
doc/lmsort.html
Normal file
|
@ -0,0 +1,113 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> lmsort </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> lmsort </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/lmsort.h>
|
||||
|
||||
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( &them[0],
|
||||
ARRAY_SIZE,
|
||||
sizeof(struct some_struct),
|
||||
some_struct_comparison_function );
|
||||
|
||||
for ( t=0; t<ARRAY_SIZE; t++ )
|
||||
some_struct_print_function( &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( &them[0],
|
||||
ARRAY_SIZE,
|
||||
sizeof(struct some_struct),
|
||||
NULL );
|
||||
lp2 = lmsort( lp1, some_struct_comparison_function );
|
||||
|
||||
while (lp2)
|
||||
{
|
||||
some_struct_print_function( lp2->dp );
|
||||
lp2 = lp2->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 ->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
25
doc/lock_file.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> lock_file </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> lock_file </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/lock_file.h>
|
||||
|
||||
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
86
doc/match_tok.html
Normal 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 <mplib1/match_tok.h>
|
||||
|
||||
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
70
doc/min_list.html
Normal 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 <mplib1/min_list.h>
|
||||
|
||||
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
22
doc/mpbasename.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<title> mpbasename.h </title>
|
||||
</head>
|
||||
<body bgcolor="#ffffff" text="#000000">
|
||||
<h1> mpbasename.h </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/mpbasename.h>
|
||||
</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
66
doc/mpstrtok.html
Normal file
|
@ -0,0 +1,66 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> mpstrtok() </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> mpstrtok() </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/mpstrtok.h>
|
||||
|
||||
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: <a>
|
||||
token: <selection>
|
||||
token: <of>
|
||||
token: <strings>
|
||||
</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
37
doc/pid_check.html
Normal 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 <mplib1/pid_check.h>
|
||||
</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
BIN
doc/ppin.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
BIN
doc/rpin.gif
Normal file
BIN
doc/rpin.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
29
doc/safe_string.html
Normal file
29
doc/safe_string.html
Normal 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 <mplib1/safe_string.h>
|
||||
|
||||
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
161
doc/stopwatch.html
Normal file
|
@ -0,0 +1,161 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> stopwatch </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> stopwatch </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/stopwatch.h>
|
||||
|
||||
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
23
doc/stricmp.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> stricmp() </TITLE>
|
||||
</HEAD>
|
||||
<BODY bgcolor="#ffffff" text="#000000">
|
||||
<h1> stricmp() </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/stricmp.h>
|
||||
|
||||
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
86
doc/timestamp.html
Normal file
|
@ -0,0 +1,86 @@
|
|||
<html>
|
||||
<head>
|
||||
<title> timestamp.h </title>
|
||||
</head>
|
||||
<body bgcolor="#ffffff" text="#000000">
|
||||
<h1> timestamp.h </h1>
|
||||
|
||||
<pre>
|
||||
#include <mplib1/timestamp.h>
|
||||
</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
BIN
doc/ypin.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
37
gen_html_index
Executable file
37
gen_html_index
Executable 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
674
gpl-3.0.txt
Normal 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
1
include/body_part.html
Normal file
|
@ -0,0 +1 @@
|
|||
<body bgcolor="#ffffff" text="#000000">
|
94
include/bpo_alloc_private.h
Normal file
94
include/bpo_alloc_private.h
Normal 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
142
include/bpo_init_internal.h
Normal 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 -- */
|
50
include/bpo_list_internal.h
Normal file
50
include/bpo_list_internal.h
Normal 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
183
include/bpo_lock_internal.h
Normal 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
156
include/bpo_proc_internal.h
Normal 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
140
include/bpo_q_internal.h
Normal 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 -- */
|
82
include/cfg_file_internal.h
Normal file
82
include/cfg_file_internal.h
Normal 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
179
include/dl_lru_private.h
Normal 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
34
include/index.html
Normal 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
38
index.html
Normal 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
123
libsrc/Makefile
Normal 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
211
libsrc/build_argv.c
Normal 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
573
libsrc/cfg_file.c
Normal 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( ¤t_lists, 0 );
|
||||
}
|
||||
if (list_name==NULL)
|
||||
{
|
||||
if (def_list)
|
||||
return(def_list);
|
||||
list_name = config_list;
|
||||
}
|
||||
|
||||
clp = dl_Find_Item_By_Name( ¤t_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( ¤t_lists, &clp->cl_Node );
|
||||
}
|
||||
}
|
||||
return(clp);
|
||||
}
|
||||
|
||||
dl_List_t *
|
||||
get_config_list_list( void )
|
||||
{
|
||||
if (!done_init)
|
||||
{
|
||||
done_init = 1;
|
||||
(void)dl_Init_List( ¤t_lists, 0 );
|
||||
}
|
||||
return( ¤t_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
97
libsrc/cfg_watch.c
Normal 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
123
libsrc/cpustopwatch.c
Normal 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
114
libsrc/daemonloop.c
Normal 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
98
libsrc/daemonsleep.c
Normal 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
428
libsrc/dl_list.c
Normal 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
940
libsrc/dl_lru.c
Normal 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
739
libsrc/dl_lru_range.c
Normal 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
285
libsrc/dl_lru_rep.c
Normal 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
253
libsrc/dl_sort_i.c
Normal 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
251
libsrc/dl_sort_n.c
Normal 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
107
libsrc/dumphex.c
Normal 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
101
libsrc/fgetline.c
Normal 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
91
libsrc/fgetline2.c
Normal 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
70
libsrc/fprintfile.c
Normal 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
69
libsrc/fput_log_str.c
Normal 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
79
libsrc/get_uname.c
Normal 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
286
libsrc/index.html
Normal 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
152
libsrc/inthand.c
Normal 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
131
libsrc/leavesub.c
Normal 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
226
libsrc/lmsort.c
Normal 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
88
libsrc/lmsort_m.c
Normal 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
93
libsrc/lock_file.c
Normal 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
71
libsrc/make_log_str.c
Normal 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
220
libsrc/match_tok.c
Normal 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
125
libsrc/min_list.c
Normal 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
72
libsrc/mpbasename.c
Normal 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
108
libsrc/mpstrtok.c
Normal 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
73
libsrc/pidstr.c
Normal 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
70
libsrc/safe_string.c
Normal 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
120
libsrc/stopwatch.c
Normal 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
123
libsrc/stopwatch_c.c
Normal 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
106
libsrc/time.c
Normal 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
535
libsrc/vre_alloc.c
Normal 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
Loading…
Reference in a new issue