Added UBI library

This commit is contained in:
Michiel Broek 2001-11-25 22:28:04 +00:00
parent 4349e984c6
commit 614bc71f09
16 changed files with 6017 additions and 1 deletions

481
lib/COPYING.LIB Normal file
View File

@ -0,0 +1,481 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, 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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey 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 library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -30,11 +30,15 @@ MBINET_HDRS = mbinet.h
MEMWATCH_SRCS = memwatch.c
MEMWATCH_OBJS = memwatch.o
MEMWATCH_HDRS = memwatch.h
UBI_SRCS = debugparse.c ubi_BinTree.c ubi_Cache.c ubi_SplayTree.c ubi_dLinkList.c ubi_sLinkList.c
UBI_HDRS = debugparse.h ubi_BinTree.h ubi_Cache.h ubi_SplayTree.h ubi_dLinkList.h ubi_sLinkList.h
UBI_OBJS = debugparse.o ubi_BinTree.o ubi_Cache.o ubi_SplayTree.o ubi_dLinkList.o ubi_sLinkList.o
OTHER_HDRS = ansi.h bluewave.h libs.h mbse.h records.h structs.h
SRCS = ${CLCOMM_SRCS} ${COMMON_SRCS} ${DBASE_SRCS} ${MSGBASE_SRCS} ${MBINET_SRCS} ${MEMWATCH_SRCS}
OBJS = ${CLCOMM_OBJS} ${COMMON_OBJS} ${DBASE_OBJS} ${MSGBASE_OBJS} ${MBINET_OBJS} ${MEMWATCH_OBJS}
HDRS = ${CLCOMM_HDRS} ${COMMON_HDRS} ${DBASE_HDRS} ${MSGBASE_HDRS} ${MBINET_HDRS} ${MEMWATCH_HDRS} ${OTHER_HDRS}
OTHER = Makefile README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org
OTHER = Makefile README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org \
COPYING.LIB README.UBI
TARGET = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a
#############################################################################
@ -71,6 +75,10 @@ libmemwatch.a: ${MEMWATCH_OBJS}
ar r $@ $?
${RANLIB} $@
libubi.a: ${UBI_OBJS}
ar r $@ $?
${RANLIB} $@
install: all
clean:

16
lib/README.UBI Normal file
View File

@ -0,0 +1,16 @@
Sun Nov 25 23:18:30 CET 2001
The C code files in the samba/source/ubiqx directory are licensed under
the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE (LGPL). A copy of the
LGPL should also be included in this directory under the name COPYING.LIB.
If this file is not present, you can obtain a copy of the LGPL by writing
to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA.
The versions of the ubiqx modules distributed with MBSE BBS may have been
modified for inclusion with MBSE BBS. The main distribution, which contains
additional available modules, can be found at:
http://www.interads.co.uk/~crh/ubiqx/
Michiel Broek.

309
lib/debugparse.c Normal file
View File

@ -0,0 +1,309 @@
/* ========================================================================== **
* debugparse.c
*
* Copyright (C) 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* -------------------------------------------------------------------------- **
* This module is a very simple parser for Samba debug log files.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
* The important function in this module is dbg_char2token(). The rest is
* basically fluff. (Potentially useful fluff, but still fluff.)
* ========================================================================== **
*/
#include "libs.h"
#include "debugparse.h"
/* -------------------------------------------------------------------------- **
* Constants...
*
* DBG_BSIZE - This internal constant is used only by dbg_test(). It is the
* size of the read buffer. I've tested the function using a
* DBG_BSIZE value of 2.
*/
#define DBG_BSIZE 128
/* -------------------------------------------------------------------------- **
* Functions...
*/
char *dbg_token2string( dbg_Token tok )
/* ------------------------------------------------------------------------ **
* Given a token, return a string describing the token.
*
* Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
*
* Output: A string identifying the token. This is useful for debugging,
* etc.
*
* Note: If the token is not known, this function will return the
* string "<unknown>".
*
* ------------------------------------------------------------------------ **
*/
{
switch( tok )
{
case dbg_null:
return( (char *)"null" );
case dbg_ignore:
return( (char *)"ignore" );
case dbg_header:
return( (char *)"header" );
case dbg_timestamp:
return( (char *)"time stamp" );
case dbg_level:
return( (char *)"level" );
case dbg_sourcefile:
return( (char *)"source file" );
case dbg_function:
return( (char *)"function" );
case dbg_lineno:
return( (char *)"line number" );
case dbg_message:
return( (char *)"message" );
case dbg_eof:
return( (char *)"[EOF]" );
}
return( (char *)"<unknown>" );
} /* dbg_token2string */
dbg_Token dbg_char2token( dbg_Token *state, int c )
/* ------------------------------------------------------------------------ **
* Parse input one character at a time.
*
* Input: state - A pointer to a token variable. This is used to
* maintain the parser state between calls. For
* each input stream, you should set up a separate
* state variable and initialize it to dbg_null.
* Pass a pointer to it into this function with each
* character in the input stream. See dbg_test()
* for an example.
* c - The "current" character in the input stream.
*
* Output: A token.
* The token value will change when delimiters are found,
* which indicate a transition between syntactical objects.
* Possible return values are:
*
* dbg_null - The input character was an end-of-line.
* This resets the parser to its initial state
* in preparation for parsing the next line.
* dbg_eof - Same as dbg_null, except that the character
* was an end-of-file.
* dbg_ignore - Returned for whitespace and delimiters.
* These lexical tokens are only of interest
* to the parser.
* dbg_header - Indicates the start of a header line. The
* input character was '[' and was the first on
* the line.
* dbg_timestamp - Indicates that the input character was part
* of a header timestamp.
* dbg_level - Indicates that the input character was part
* of the debug-level value in the header.
* dbg_sourcefile - Indicates that the input character was part
* of the sourcefile name in the header.
* dbg_function - Indicates that the input character was part
* of the function name in the header.
* dbg_lineno - Indicates that the input character was part
* of the DEBUG call line number in the header.
* dbg_message - Indicates that the input character was part
* of the DEBUG message text.
*
* ------------------------------------------------------------------------ **
*/
{
/* The terminating characters that we see will greatly depend upon
* how they are read. For example, if gets() is used instead of
* fgets(), then we will not see newline characters. A lot also
* depends on the calling function, which may handle terminators
* itself.
*
* '\n', '\0', and EOF are all considered line terminators. The
* dbg_eof token is sent back if an EOF is encountered.
*
* Warning: only allow the '\0' character to be sent if you are
* using gets() to read whole lines (thus replacing '\n'
* with '\0'). Sending '\0' at the wrong time will mess
* up the parsing.
*/
switch( c )
{
case EOF:
*state = dbg_null; /* Set state to null (initial state) so */
return( dbg_eof ); /* that we can restart with new input. */
case '\n':
case '\0':
*state = dbg_null; /* A newline or eoln resets to the null state. */
return( dbg_null );
}
/* When within the body of the message, only a line terminator
* can cause a change of state. We've already checked for line
* terminators, so if the current state is dbg_msgtxt, simply
* return that as our current token.
*/
if( dbg_message == *state )
return( dbg_message );
/* If we are at the start of a new line, and the input character
* is an opening bracket, then the line is a header line, otherwise
* it's a message body line.
*/
if( dbg_null == *state )
{
if( '[' == c )
{
*state = dbg_timestamp;
return( dbg_header );
}
*state = dbg_message;
return( dbg_message );
}
/* We've taken care of terminators, text blocks and new lines.
* The remaining possibilities are all within the header line
* itself.
*/
/* Within the header line, whitespace can be ignored *except*
* within the timestamp.
*/
if( isspace( c ) )
{
/* Fudge. The timestamp may contain space characters. */
if( (' ' == c) && (dbg_timestamp == *state) )
return( dbg_timestamp );
/* Otherwise, ignore whitespace. */
return( dbg_ignore );
}
/* Okay, at this point we know we're somewhere in the header.
* Valid header *states* are: dbg_timestamp, dbg_level,
* dbg_sourcefile, dbg_function, and dbg_lineno.
*/
switch( c )
{
case ',':
if( dbg_timestamp == *state )
{
*state = dbg_level;
return( dbg_ignore );
}
break;
case ']':
if( dbg_level == *state )
{
*state = dbg_sourcefile;
return( dbg_ignore );
}
break;
case ':':
if( dbg_sourcefile == *state )
{
*state = dbg_function;
return( dbg_ignore );
}
break;
case '(':
if( dbg_function == *state )
{
*state = dbg_lineno;
return( dbg_ignore );
}
break;
case ')':
if( dbg_lineno == *state )
{
*state = dbg_null;
return( dbg_ignore );
}
break;
}
/* If the previous block did not result in a state change, then
* return the current state as the current token.
*/
return( *state );
} /* dbg_char2token */
void dbg_test( void )
/* ------------------------------------------------------------------------ **
* Simple test function.
*
* Input: none.
* Output: none.
* Notes: This function was used to test dbg_char2token(). It reads a
* Samba log file from stdin and prints parsing info to stdout.
* It also serves as a simple example.
*
* ------------------------------------------------------------------------ **
*/
{
char bufr[DBG_BSIZE];
int i;
int linecount = 1;
dbg_Token old = dbg_null,
new = dbg_null,
state = dbg_null;
while( fgets( bufr, DBG_BSIZE, stdin ) )
{
for( i = 0; bufr[i]; i++ )
{
old = new;
new = dbg_char2token( &state, bufr[i] );
switch( new )
{
case dbg_header:
if( linecount > 1 )
(void)putchar( '\n' );
break;
case dbg_null:
linecount++;
break;
case dbg_ignore:
break;
default:
if( old != new )
(void)printf( "\n[%05d]%12s: ", linecount, dbg_token2string(new) );
(void)putchar( bufr[i] );
}
}
}
(void)putchar( '\n' );
} /* dbg_test */
/* -------------------------------------------------------------------------- **
* This simple main line can be uncommented and used to test the parser.
*/
/*
* int main( void )
* {
* dbg_test();
* return( 0 );
* }
*/
/* ========================================================================== */

127
lib/debugparse.h Normal file
View File

@ -0,0 +1,127 @@
#ifndef DEBUGPARSE_H
#define DEBUGPARSE_H
/* ========================================================================== **
* debugparse.c
*
* Copyright (C) 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
*
* -------------------------------------------------------------------------- **
* This module is a very simple parser for Samba debug log files.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
* The important function in this module is dbg_char2token(). The rest is
* basically fluff. (Potentially useful fluff, but still fluff.)
* ========================================================================== **
*/
// #include "sys_include.h"
/* This module compiles quite nicely outside of the Samba environment.
* You'll need the following headers:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
*/
/* -------------------------------------------------------------------------- **
* These are the tokens returned by dbg_char2token().
*/
typedef enum
{
dbg_null = 0,
dbg_ignore,
dbg_header,
dbg_timestamp,
dbg_level,
dbg_sourcefile,
dbg_function,
dbg_lineno,
dbg_message,
dbg_eof
} dbg_Token;
/* -------------------------------------------------------------------------- **
* Function prototypes...
*/
char *dbg_token2string( dbg_Token tok );
/* ------------------------------------------------------------------------ **
* Given a token, return a string describing the token.
*
* Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
*
* Output: A string identifying the token. This is useful for debugging,
* etc.
*
* Note: If the token is not known, this function will return the
* string "<unknown>".
*
* ------------------------------------------------------------------------ **
*/
dbg_Token dbg_char2token( dbg_Token *state, int c );
/* ------------------------------------------------------------------------ **
* Parse input one character at a time.
*
* Input: state - A pointer to a token variable. This is used to
* maintain the parser state between calls. For
* each input stream, you should set up a separate
* state variable and initialize it to dbg_null.
* Pass a pointer to it into this function with each
* character in the input stream. See dbg_test()
* for an example.
* c - The "current" character in the input stream.
*
* Output: A token.
* The token value will change when delimiters are found,
* which indicate a transition between syntactical objects.
* Possible return values are:
*
* dbg_null - The input character was an end-of-line.
* This resets the parser to its initial state
* in preparation for parsing the next line.
* dbg_eof - Same as dbg_null, except that the character
* was an end-of-file.
* dbg_ignore - Returned for whitespace and delimiters.
* These lexical tokens are only of interest
* to the parser.
* dbg_header - Indicates the start of a header line. The
* input character was '[' and was the first on
* the line.
* dbg_timestamp - Indicates that the input character was part
* of a header timestamp.
* dbg_level - Indicates that the input character was part
* of the debug-level value in the header.
* dbg_sourcefile - Indicates that the input character was part
* of the sourcefile name in the header.
* dbg_function - Indicates that the input character was part
* of the function name in the header.
* dbg_lineno - Indicates that the input character was part
* of the DEBUG call line number in the header.
* dbg_message - Indicates that the input character was part
* of the DEBUG message text.
*
* ------------------------------------------------------------------------ **
*/
/* -------------------------------------------------------------------------- */
#endif /* DEBUGPARSE_H */

View File

@ -26,12 +26,433 @@
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************
* Ideas taken from Samba, Copyright (C) Andrew Tridgell 1992-1998
*****************************************************************************/
#include "libs.h"
#include "structs.h"
#include "clcomm.h"
#include "common.h"
#include "ubi_sLinkList.h"
#include "ubi_dLinkList.h"
#include "ubi_Cache.h"
typedef enum {CASE_UPPER, CASE_LOWER} CASES;
int case_default = CASE_UPPER; /* Are conforming 8.3 names all upper or lower? */
int case_mangle = TRUE; /* If true, all chars in 8.3 should be same case. */
/* -------------------------------------------------------------------------- **
* Other stuff...
*
* magic_char - This is the magic char used for mangling. It's
* global. There is a call to lp_magicchar() in server.c
* that is used to override the initial value.
*
* MANGLE_BASE - This is the number of characters we use for name mangling.
*
* basechars - The set characters used for name mangling. This
* is static (scope is this file only).
*
* mangle() - Macro used to select a character from basechars (i.e.,
* mangle(n) will return the nth digit, modulo MANGLE_BASE).
*
* chartest - array 0..255. The index range is the set of all possible
* values of a byte. For each byte value, the content is a
* two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK,
* below.
*
* ct_initialized - False until the chartest array has been initialized via
* a call to init_chartest().
*
* BASECHAR_MASK - Masks the upper nibble of a one-byte value.
*
* ILLEGAL_MASK - Masks the lower nibble of a one-byte value.
*
* isbasecahr() - Given a character, check the chartest array to see
* if that character is in the basechars set. This is
* faster than using strchr().
*
* isillegal() - Given a character, check the chartest array to see
* if that character is in the illegal characters set.
* This is faster than using strchr().
*
* mangled_cache - Cache header used for storing mangled -> original
* reverse maps.
*
* mc_initialized - False until the mangled_cache structure has been
* initialized via a call to reset_mangled_cache().
*
* MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
* cache. A value of 0 indicates "infinite".
*
* MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the
* cache. When the cache was kept as an array of 256
* byte strings, the default cache size was 50 entries.
* This required a fixed 12.5Kbytes of memory. The
* mangled stack parameter is no longer used (though
* this might change). We're now using a fixed 16Kbyte
* maximum cache size. This will probably be much more
* than 50 entries.
*/
char magic_char = '~';
static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
static unsigned char chartest[256] = { 0 };
static int ct_initialized = FALSE;
#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
#define BASECHAR_MASK 0xf0
#define ILLEGAL_MASK 0x0f
#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
// static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
static int mc_initialized = FALSE;
#define MANGLED_CACHE_MAX_ENTRIES 0
#define MANGLED_CACHE_MAX_MEMORY 16384
/* ************************************************************************** **
* Initialize the static character test array.
*
* Input: none
*
* Output: none
*
* Notes: This function changes (loads) the contents of the <chartest>
* array. The scope of <chartest> is this file.
*
* ************************************************************************** **
*/
static void init_chartest( void )
{
char *illegalchars = (char *)"*\\/?<>|\":";
unsigned char *s;
memset( (char *)chartest, '\0', 256 );
for( s = (unsigned char *)illegalchars; *s; s++ )
chartest[*s] = ILLEGAL_MASK;
for( s = (unsigned char *)basechars; *s; s++ )
chartest[*s] |= BASECHAR_MASK;
ct_initialized = TRUE;
} /* init_chartest */
/* ************************************************************************** **
* Return True if a name is a special msdos reserved name.
*
* Input: fname - String containing the name to be tested.
*
* Output: True, if the name matches one of the list of reserved names.
*
* Notes: This is a static function called by is_8_3(), below.
*
* ************************************************************************** **
*/
static int is_reserved_msdos( char *fname )
{
char upperFname[13];
char *p;
strncpy (upperFname, fname, 12);
/* lpt1.txt and con.txt etc are also illegal */
p = strchr(upperFname,'.');
if( p )
*p = '\0';
tu( upperFname );
p = upperFname + 1;
switch( upperFname[0] )
{
case 'A':
if( 0 == strcmp( p, "UX" ) )
return( TRUE );
break;
case 'C':
if( (0 == strcmp( p, "LOCK$" ))
|| (0 == strcmp( p, "ON" ))
|| (0 == strcmp( p, "OM1" ))
|| (0 == strcmp( p, "OM2" ))
|| (0 == strcmp( p, "OM3" ))
|| (0 == strcmp( p, "OM4" ))
)
return( TRUE );
break;
case 'L':
if( (0 == strcmp( p, "PT1" ))
|| (0 == strcmp( p, "PT2" ))
|| (0 == strcmp( p, "PT3" ))
)
return( TRUE );
break;
case 'N':
if( 0 == strcmp( p, "UL" ) )
return( TRUE );
break;
case 'P':
if( 0 == strcmp( p, "RN" ) )
return( TRUE );
break;
}
return( FALSE );
} /* is_reserved_msdos */
/* ************************************************************************** **
* Determine whether or not a given name contains illegal characters, even
* long names.
*
* Input: name - The name to be tested.
*
* Output: True if an illegal character was found in <name>, else False.
*
* Notes: This is used to test a name on the host system, long or short,
* for characters that would be illegal on most client systems,
* particularly DOS and Windows systems. Unix and AmigaOS, for
* example, allow a filenames which contain such oddities as
* quotes ("). If a name is found which does contain an illegal
* character, it is mangled even if it conforms to the 8.3
* format.
*
* ************************************************************************** **
*/
static int is_illegal_name( char *name )
{
unsigned char *s;
int skip;
if( !name )
return( TRUE );
if( !ct_initialized )
init_chartest();
s = (unsigned char *)name;
while( *s )
{
skip = get_character_len( *s );
if( skip != 0 )
{
s += skip;
}
else
{
if( isillegal( *s ) )
return( TRUE );
else
s++;
}
}
return( FALSE );
} /* is_illegal_name */
/* ************************************************************************** **
* Return True if the name *could be* a mangled name.
*
* Input: s - A path name - in UNIX pathname format.
*
* Output: True if the name matches the pattern described below in the
* notes, else False.
*
* Notes: The input name is *not* tested for 8.3 compliance. This must be
* done separately. This function returns true if the name contains
* a magic character followed by excactly two characters from the
* basechars list (above), which in turn are followed either by the
* nul (end of string) byte or a dot (extension) or by a '/' (end of
* a directory name).
*
* ************************************************************************** **
*/
int is_mangled( char *s )
{
char *magic;
if( !ct_initialized )
init_chartest();
magic = strchr( s, magic_char );
while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */
{
if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
&& isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */
&& isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */
return( TRUE ); /* If all above, then true, */
magic = strchr( magic+1, magic_char ); /* else seek next magic. */
}
return( FALSE );
} /* is_mangled */
/* ************************************************************************** **
* Return True if the name is a valid DOS name in 8.3 DOS format.
*
* Input: fname - File name to be checked.
* check_case - If True, and if case_mangle is True, then the
* name will be checked to see if all characters
* are the correct case. See case_mangle and
* case_default above.
*
* Output: True if the name is a valid DOS name, else FALSE.
*
* ************************************************************************** **
*/
int is_8_3( char *fname, int check_case )
{
int len;
int l;
int skip;
char *p;
char *dot_pos;
char *slash_pos = strrchr( fname, '/' );
/* If there is a directory path, skip it. */
if( slash_pos )
fname = slash_pos + 1;
len = strlen( fname );
Syslog('f', "Checking %s for 8.3\n", fname);
/* Can't be 0 chars or longer than 12 chars */
if( (len == 0) || (len > 12) )
return( FALSE );
/* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
if( is_reserved_msdos( fname ) )
return( FALSE );
/* Check that all characters are the correct case, if asked to do so. */
if( check_case && case_mangle )
{
switch( case_default )
{
case CASE_LOWER:
if( strhasupper( fname ) )
return(FALSE);
break;
case CASE_UPPER:
if( strhaslower( fname ) )
return(FALSE);
break;
}
}
/* Can't contain invalid dos chars */
/* Windows use the ANSI charset.
But filenames are translated in the PC charset.
This Translation may be more or less relaxed depending
the Windows application. */
/* %%% A nice improvment to name mangling would be to translate
filename to ANSI charset on the smb server host */
p = fname;
dot_pos = NULL;
while( *p )
{
if( (skip = get_character_len( *p )) != 0 )
p += skip;
else
{
if( *p == '.' && !dot_pos )
dot_pos = (char *)p;
else
if( !isdoschar( *p ) )
return( FALSE );
p++;
}
}
/* no dot and less than 9 means OK */
if( !dot_pos )
return( len <= 8 );
l = PTR_DIFF( dot_pos, fname );
/* base must be at least 1 char except special cases . and .. */
if( l == 0 )
return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
/* base can't be greater than 8 */
if( l > 8 )
return( FALSE );
/* see smb.conf(5) for a description of the 'strip dot' parameter. */
if( lp_strip_dot()
&& len - l == 1
&& !strchr( dot_pos + 1, '.' ) )
{
*dot_pos = 0;
return( TRUE );
}
/* extension must be between 1 and 3 */
if( (len - l < 2 ) || (len - l > 4) )
return( FALSE );
/* extensions may not have a dot */
if( strchr( dot_pos+1, '.' ) )
return( FALSE );
/* must be in 8.3 format */
return( TRUE );
} /* is_8_3 */
/* ************************************************************************** **
* Compare two cache keys and return a value indicating their ordinal
* relationship.
*
* Input: ItemPtr - Pointer to a comparison key. In this case, this will
* be a mangled name string.
* NodePtr - Pointer to a node in the cache. The node structure
* will be followed in memory by a mangled name string.
*
* Output: A signed integer, as follows:
* (x < 0) <==> Key1 less than Key2
* (x == 0) <==> Key1 equals Key2
* (x > 0) <==> Key1 greater than Key2
*
* Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for
* more info.
*
* ************************************************************************** **
*/
static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
{
char *Key1 = (char *)ItemPtr;
char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
return( StrCaseCmp( Key1, Key2 ) );
} /* cache_compare */
/* ************************************************************************** **
* Free a cache entry.
*
* Input: WarrenZevon - Pointer to the entry that is to be returned to
* Nirvana.
* Output: none.
*
* Notes: This function gets around the possibility that the standard
* free() function may be implemented as a macro, or other evil
* subversions (oh, so much fun).
*
* ************************************************************************** **
*/
static void cache_free_entry( ubi_trNodePtr WarrenZevon )
{
ZERO_STRUCTP(WarrenZevon);
free( WarrenZevon );
} /* cache_free_entry */

1133
lib/ubi_BinTree.c Normal file

File diff suppressed because it is too large Load Diff

859
lib/ubi_BinTree.h Normal file
View File

@ -0,0 +1,859 @@
#ifndef UBI_BINTREE_H
#define UBI_BINTREE_H
/* ========================================================================== **
* ubi_BinTree.h
*
* Copyright (C) 1991-1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
*
* This module implements a simple binary tree.
*
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_BinTree.h,v
* Revision 4.10 2000/06/06 20:38:40 crh
* In the ReplaceNode() function, the old node header was being copied
* to the new node header using a byte-by-byte copy. This was causing
* the 'insure' software testing program to report a memory leak. The
* fix was to do a simple assignement: *newnode = *oldnode;
* This quieted the (errant) memory leak reports and is probably a bit
* faster than the bytewise copy.
*
* Revision 4.9 2000/01/08 23:24:30 crh
* Clarified a variety of if( pointer ) lines, replacing them with
* if( NULL != pointer ). This is more correct, and I have heard
* of at least one (obscure?) system out there that uses a non-zero
* value for NULL.
* Also, speed improvement in Neighbor(). It was comparing pointers
* when it could have compared two gender values. The pointer
* comparison was somewhat indirect (does pointer equal the pointer
* of the parent of the node pointed to by pointer). Urq.
*
* Revision 4.8 1999/09/22 03:40:30 crh
* Modified ubi_btTraverse() and ubi_btKillTree(). They now return an
* unsigned long indicating the number of nodes processed. The change
* is subtle. An empty tree formerly returned False, and now returns
* zero.
*
* Revision 4.7 1998/10/21 06:15:07 crh
* Fixed bugs in FirstOf() and LastOf() reported by Massimo Campostrini.
* See function comments.
*
* Revision 4.6 1998/07/25 17:02:10 crh
* Added the ubi_trNewTree() macro.
*
* Revision 4.5 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 4.4 1998/06/03 17:42:46 crh
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
* included by all of the binary tree files.
*
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
* of tree types by simply changing a header. Unfortunately, the
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
* conflict if used together. You must either choose a single tree
* type, or use the underlying function calls directly. Compare
* the two header files for more information.
*
* Revision 4.3 1998/06/02 01:28:43 crh
* Changed ubi_null.h to sys_include.h to make it more generic.
*
* Revision 4.2 1998/05/20 04:32:36 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
* Also, the balance and gender fields of the node were declared as
* signed char. As I understand it, at least one SunOS or Solaris
* compiler doesn't like "signed char". The declarations were
* wrong anyway, so I changed them to simple "char".
*
* Revision 4.1 1998/03/31 06:13:47 crh
* Thomas Aglassinger sent E'mail pointing out errors in the
* dereferencing of function pointers, and a missing typecast.
* Thanks, Thomas!
*
* Revision 4.0 1998/03/10 03:16:04 crh
* Added the AVL field 'balance' to the ubi_btNode structure. This means
* that all BinTree modules now use the same basic node structure, which
* greatly simplifies the AVL module.
* Decided that this was a big enough change to justify a new major revision
* number. 3.0 was an error, so we're at 4.0.
*
* Revision 2.6 1998/01/24 06:27:30 crh
* Added ubi_trCount() macro.
*
* Revision 2.5 1997/12/23 03:59:21 crh
* In this version, all constants & macros defined in the header file have
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
* when run with '-pedantic -fsyntax-only -Wall'.
*
* Revision 2.4 1997/07/26 04:11:14 crh
* + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
* and ubi_trFALSE.
* + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
* + There used to be something called "ubi_TypeDefs.h". I got rid of it.
* + Added function ubi_btLeafNode().
*
* Revision 2.3 1997/06/03 05:15:27 crh
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
* Also changed the interface to function InitTree(). See the comments
* for this function for more information.
*
* Revision 2.2 1995/10/03 22:00:40 CRH
* Ubisized!
*
* Revision 2.1 95/03/09 23:43:46 CRH
* Added the ModuleID static string and function. These modules are now
* self-identifying.
*
* Revision 2.0 95/02/27 22:00:33 CRH
* Revision 2.0 of this program includes the following changes:
*
* 1) A fix to a major typo in the RepaceNode() function.
* 2) The addition of the static function Border().
* 3) The addition of the public functions FirstOf() and LastOf(), which
* use Border(). These functions are used with trees that allow
* duplicate keys.
* 4) A complete rewrite of the Locate() function. Locate() now accepts
* a "comparison" operator.
* 5) Overall enhancements to both code and comments.
*
* I decided to give this a new major rev number because the interface has
* changed. In particular, there are two new functions, and changes to the
* Locate() function.
*
* Revision 1.0 93/10/15 22:55:04 CRH
* With this revision, I have added a set of #define's that provide a single,
* standard API to all existing tree modules. Until now, each of the three
* existing modules had a different function and typedef prefix, as follows:
*
* Module Prefix
* ubi_BinTree ubi_bt
* ubi_AVLtree ubi_avl
* ubi_SplayTree ubi_spt
*
* To further complicate matters, only those portions of the base module
* (ubi_BinTree) that were superceeded in the new module had the new names.
* For example, if you were using ubi_SplayTree, the locate function was
* called "ubi_sptLocate", but the next and previous functions remained
* "ubi_btNext" and "ubi_btPrev".
*
* This was not too terrible if you were familiar with the modules and knew
* exactly which tree model you wanted to use. If you wanted to be able to
* change modules (for speed comparisons, etc), things could get messy very
* quickly.
*
* So, I have added a set of defined names that get redefined in any of the
* descendant modules. To use this standardized interface in your code,
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
* datatype names for the module that you are using. Just remember to
* include the header for that module in your program file. Because these
* names are handled by the preprocessor, there is no added run-time
* overhead.
*
* Note that the original names do still exist, and can be used if you wish
* to write code directly to a specific module. This should probably only be
* done if you are planning to implement a new descendant type, such as
* red/black trees. CRH
*
* V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
*
* ========================================================================== **
*/
/* -------------------------------------------------------------------------- **
* Macros and constants.
*
* General purpose:
* ubi_trTRUE - Boolean TRUE.
* ubi_trFALSE - Boolean FALSE.
*
* Flags used in the tree header:
* ubi_trOVERWRITE - This flag indicates that an existing node may be
* overwritten by a new node with a matching key.
* ubi_trDUPKEY - This flag indicates that the tree allows duplicate
* keys. If the tree does allow duplicates, the
* overwrite flag is ignored.
*
* Node link array index constants: (Each node has an array of three
* pointers. One to the left, one to the right, and one back to the
* parent.)
* ubi_trLEFT - Left child pointer.
* ubi_trPARENT - Parent pointer.
* ubi_trRIGHT - Right child pointer.
* ubi_trEQUAL - Synonym for PARENT.
*
* ubi_trCompOps: These values are used in the ubi_trLocate() function.
* ubi_trLT - request the first instance of the greatest key less than
* the search key.
* ubi_trLE - request the first instance of the greatest key that is less
* than or equal to the search key.
* ubi_trEQ - request the first instance of key that is equal to the
* search key.
* ubi_trGE - request the first instance of a key that is greater than
* or equal to the search key.
* ubi_trGT - request the first instance of the first key that is greater
* than the search key.
* -------------------------------------------------------------------------- **
*/
#define ubi_trTRUE 0xFF
#define ubi_trFALSE 0x00
#define ubi_trOVERWRITE 0x01 /* Turn on allow overwrite */
#define ubi_trDUPKEY 0x02 /* Turn on allow duplicate keys */
/* Pointer array index constants... */
#define ubi_trLEFT 0x00
#define ubi_trPARENT 0x01
#define ubi_trRIGHT 0x02
#define ubi_trEQUAL ubi_trPARENT
typedef enum {
ubi_trLT = 1,
ubi_trLE,
ubi_trEQ,
ubi_trGE,
ubi_trGT
} ubi_trCompOps;
/* -------------------------------------------------------------------------- **
* These three macros allow simple manipulation of pointer index values (LEFT,
* RIGHT, and PARENT).
*
* Normalize() - converts {LEFT, PARENT, RIGHT} into {-1, 0 ,1}. C
* uses {negative, zero, positive} values to indicate
* {less than, equal to, greater than}.
* AbNormal() - converts {negative, zero, positive} to {LEFT, PARENT,
* RIGHT} (opposite of Normalize()). Note: C comparison
* functions, such as strcmp(), return {negative, zero,
* positive} values, which are not necessarily {-1, 0,
* 1}. This macro uses the the ubi_btSgn() function to
* compensate.
* RevWay() - converts LEFT to RIGHT and RIGHT to LEFT. PARENT (EQUAL)
* is left as is.
* -------------------------------------------------------------------------- **
*/
#define ubi_trNormalize(W) ((char)( (W) - ubi_trEQUAL ))
#define ubi_trAbNormal(W) ((char)( ((char)ubi_btSgn( (long)(W) )) \
+ ubi_trEQUAL ))
#define ubi_trRevWay(W) ((char)( ubi_trEQUAL - ((W) - ubi_trEQUAL) ))
/* -------------------------------------------------------------------------- **
* These macros allow us to quickly read the values of the OVERWRITE and
* DUPlicate KEY bits of the tree root flags field.
* -------------------------------------------------------------------------- **
*/
#define ubi_trDups_OK(A) \
((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
#define ubi_trOvwt_OK(A) \
((ubi_trOVERWRITE & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
/* -------------------------------------------------------------------------- **
* Additional Macros...
*
* ubi_trCount() - Given a pointer to a tree root, this macro returns the
* number of nodes currently in the tree.
*
* ubi_trNewTree() - This macro makes it easy to declare and initialize a
* tree header in one step. The line
*
* static ubi_trNewTree( MyTree, cmpfn, ubi_trDUPKEY );
*
* is equivalent to
*
* static ubi_trRoot MyTree[1]
* = {{ NULL, cmpfn, 0, ubi_trDUPKEY }};
*
* -------------------------------------------------------------------------- **
*/
#define ubi_trCount( R ) (((ubi_trRootPtr)(R))->count)
#define ubi_trNewTree( N, C, F ) ubi_trRoot (N)[1] = {{ NULL, (C), 0, (F) }}
/* -------------------------------------------------------------------------- **
* Typedefs...
*
* ubi_trBool - Your typcial true or false...
*
* Item Pointer: The ubi_btItemPtr is a generic pointer. It is used to
* indicate a key that is being searched for within the tree.
* Searching occurs whenever the ubi_trFind(), ubi_trLocate(),
* or ubi_trInsert() functions are called.
* -------------------------------------------------------------------------- **
*/
typedef unsigned char ubi_trBool;
typedef void *ubi_btItemPtr; /* A pointer to key data within a node. */
/* ------------------------------------------------------------------------- **
* Binary Tree Node Structure: This structure defines the basic elements of
* the tree nodes. In general you *SHOULD NOT PLAY WITH THESE FIELDS*!
* But, of course, I have to put the structure into this header so that
* you can use it as a building block.
*
* The fields are as follows:
* Link - an array of pointers. These pointers are manipulated by
* the BT routines. The pointers indicate the left and right
* child nodes and the parent node. By keeping track of the
* parent pointer, we avoid the need for recursive routines or
* hand-tooled stacks to keep track of our path back to the
* root. The use of these pointers is subject to change without
* notice.
* gender - a one-byte field indicating whether the node is the RIGHT or
* LEFT child of its parent. If the node is the root of the
* tree, gender will be PARENT.
* balance - only used by the AVL tree module. This field indicates
* the height balance at a given node. See ubi_AVLtree for
* details.
*
* ------------------------------------------------------------------------- **
*/
typedef struct ubi_btNodeStruct {
struct ubi_btNodeStruct *Link[ 3 ];
char gender;
char balance;
} ubi_btNode;
typedef ubi_btNode *ubi_btNodePtr; /* Pointer to an ubi_btNode structure. */
/* ------------------------------------------------------------------------- **
* The next three typedefs define standard function types used by the binary
* tree management routines. In particular:
*
* ubi_btCompFunc is a pointer to a comparison function. Comparison
* functions are passed an ubi_btItemPtr and an
* ubi_btNodePtr. They return a value that is (<0), 0,
* or (>0) to indicate that the Item is (respectively)
* "less than", "equal to", or "greater than" the Item
* contained within the node. (See ubi_btInitTree()).
* ubi_btActionRtn is a pointer to a function that may be called for each
* node visited when performing a tree traversal (see
* ubi_btTraverse()). The function will be passed two
* parameters: the first is a pointer to a node in the
* tree, the second is a generic pointer that may point to
* anything that you like.
* ubi_btKillNodeRtn is a pointer to a function that will deallocate the
* memory used by a node (see ubi_btKillTree()). Since
* memory management is left up to you, deallocation may
* mean anything that you want it to mean. Just remember
* that the tree *will* be destroyed and that none of the
* node pointers will be valid any more.
* ------------------------------------------------------------------------- **
*/
typedef int (*ubi_btCompFunc)( ubi_btItemPtr, ubi_btNodePtr );
typedef void (*ubi_btActionRtn)( ubi_btNodePtr, void * );
typedef void (*ubi_btKillNodeRtn)( ubi_btNodePtr );
/* -------------------------------------------------------------------------- **
* Tree Root Structure: This structure gives us a convenient handle for
* accessing whole binary trees. The fields are:
* root - A pointer to the root node of the tree.
* count - A count of the number of nodes stored in the tree.
* cmp - A pointer to the comparison routine to be used when building or
* searching the tree.
* flags - A set of bit flags. Two flags are currently defined:
*
* ubi_trOVERWRITE - If set, this flag indicates that a new node should
* (bit 0x01) overwrite an old node if the two have identical
* keys (ie., the keys are equal).
* ubi_trDUPKEY - If set, this flag indicates that the tree is
* (bit 0x02) allowed to contain nodes with duplicate keys.
*
* NOTE: ubi_trInsert() tests ubi_trDUPKEY before ubi_trOVERWRITE.
*
* All of these values are set when you initialize the root structure by
* calling ubi_trInitTree().
* -------------------------------------------------------------------------- **
*/
typedef struct {
ubi_btNodePtr root; /* A pointer to the root node of the tree */
ubi_btCompFunc cmp; /* A pointer to the tree's comparison function */
unsigned long count; /* A count of the number of nodes in the tree */
char flags; /* Overwrite Y|N, Duplicate keys Y|N... */
} ubi_btRoot;
typedef ubi_btRoot *ubi_btRootPtr; /* Pointer to an ubi_btRoot structure. */
/* -------------------------------------------------------------------------- **
* Function Prototypes.
*/
long ubi_btSgn( long x );
/* ------------------------------------------------------------------------ **
* Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
*
* Input: x - a signed long integer value.
*
* Output: the "sign" of x, represented as follows:
* -1 == negative
* 0 == zero (no sign)
* 1 == positive
*
* Note: This utility is provided in order to facilitate the conversion
* of C comparison function return values into BinTree direction
* values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
* AbNormal() conversion macro!
*
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr );
/* ------------------------------------------------------------------------ **
* Initialize a tree node.
*
* Input: a pointer to a ubi_btNode structure to be initialized.
* Output: a pointer to the initialized ubi_btNode structure (ie. the
* same as the input pointer).
* ------------------------------------------------------------------------ **
*/
ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
ubi_btCompFunc CompFunc,
char Flags );
/* ------------------------------------------------------------------------ **
* Initialize the fields of a Tree Root header structure.
*
* Input: RootPtr - a pointer to an ubi_btRoot structure to be
* initialized.
* CompFunc - a pointer to a comparison function that will be used
* whenever nodes in the tree must be compared against
* outside values.
* Flags - One bytes worth of flags. Flags include
* ubi_trOVERWRITE and ubi_trDUPKEY. See the header
* file for more info.
*
* Output: a pointer to the initialized ubi_btRoot structure (ie. the
* same value as RootPtr).
*
* Note: The interface to this function has changed from that of
* previous versions. The <Flags> parameter replaces two
* boolean parameters that had the same basic effect.
* ------------------------------------------------------------------------ **
*/
ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
ubi_btNodePtr NewNode,
ubi_btItemPtr ItemPtr,
ubi_btNodePtr *OldNode );
/* ------------------------------------------------------------------------ **
* This function uses a non-recursive algorithm to add a new element to the
* tree.
*
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
* the root of the tree to which NewNode is to be added.
* NewNode - a pointer to an ubi_btNode structure that is NOT
* part of any tree.
* ItemPtr - A pointer to the sort key that is stored within
* *NewNode. ItemPtr MUST point to information stored
* in *NewNode or an EXACT DUPLICATE. The key data
* indicated by ItemPtr is used to place the new node
* into the tree.
* OldNode - a pointer to an ubi_btNodePtr. When searching
* the tree, a duplicate node may be found. If
* duplicates are allowed, then the new node will
* be simply placed into the tree. If duplicates
* are not allowed, however, then one of two things
* may happen.
* 1) if overwritting *is not* allowed, this
* function will return FALSE (indicating that
* the new node could not be inserted), and
* *OldNode will point to the duplicate that is
* still in the tree.
* 2) if overwritting *is* allowed, then this
* function will swap **OldNode for *NewNode.
* In this case, *OldNode will point to the node
* that was removed (thus allowing you to free
* the node).
* ** If you are using overwrite mode, ALWAYS **
* ** check the return value of this parameter! **
* Note: You may pass NULL in this parameter, the
* function knows how to cope. If you do this,
* however, there will be no way to return a
* pointer to an old (ie. replaced) node (which is
* a problem if you are using overwrite mode).
*
* Output: a boolean value indicating success or failure. The function
* will return FALSE if the node could not be added to the tree.
* Such failure will only occur if duplicates are not allowed,
* nodes cannot be overwritten, AND a duplicate key was found
* within the tree.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
ubi_btNodePtr DeadNode );
/* ------------------------------------------------------------------------ **
* This function removes the indicated node from the tree.
*
* Input: RootPtr - A pointer to the header of the tree that contains
* the node to be removed.
* DeadNode - A pointer to the node that will be removed.
*
* Output: This function returns a pointer to the node that was removed
* from the tree (ie. the same as DeadNode).
*
* Note: The node MUST be in the tree indicated by RootPtr. If not,
* strange and evil things will happen to your trees.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe,
ubi_trCompOps CompOp );
/* ------------------------------------------------------------------------ **
* The purpose of ubi_btLocate() is to find a node or set of nodes given
* a target value and a "comparison operator". The Locate() function is
* more flexible and (in the case of trees that may contain dupicate keys)
* more precise than the ubi_btFind() function. The latter is faster,
* but it only searches for exact matches and, if the tree contains
* duplicates, Find() may return a pointer to any one of the duplicate-
* keyed records.
*
* Input:
* RootPtr - A pointer to the header of the tree to be searched.
* FindMe - An ubi_btItemPtr that indicates the key for which to
* search.
* CompOp - One of the following:
* CompOp Return a pointer to the node with
* ------ ---------------------------------
* ubi_trLT - the last key value that is less
* than FindMe.
* ubi_trLE - the first key matching FindMe, or
* the last key that is less than
* FindMe.
* ubi_trEQ - the first key matching FindMe.
* ubi_trGE - the first key matching FindMe, or the
* first key greater than FindMe.
* ubi_trGT - the first key greater than FindMe.
* Output:
* A pointer to the node matching the criteria listed above under
* CompOp, or NULL if no node matched the criteria.
*
* Notes:
* In the case of trees with duplicate keys, Locate() will behave as
* follows:
*
* Find: 3 Find: 3
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
* ^ ^ ^ ^ ^
* LT EQ GT LE GE
*
* That is, when returning a pointer to a node with a key that is LESS
* THAN the target key (FindMe), Locate() will return a pointer to the
* LAST matching node.
* When returning a pointer to a node with a key that is GREATER
* THAN the target key (FindMe), Locate() will return a pointer to the
* FIRST matching node.
*
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe );
/* ------------------------------------------------------------------------ **
* This function performs a non-recursive search of a tree for any node
* matching a specific key.
*
* Input:
* RootPtr - a pointer to the header of the tree to be searched.
* FindMe - a pointer to the key value for which to search.
*
* Output:
* A pointer to a node with a key that matches the key indicated by
* FindMe, or NULL if no such node was found.
*
* Note: In a tree that allows duplicates, the pointer returned *might
* not* point to the (sequentially) first occurance of the
* desired key. In such a tree, it may be more useful to use
* ubi_btLocate().
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btNext( ubi_btNodePtr P );
/* ------------------------------------------------------------------------ **
* Given the node indicated by P, find the (sorted order) Next node in the
* tree.
* Input: P - a pointer to a node that exists in a binary tree.
* Output: A pointer to the "next" node in the tree, or NULL if P pointed
* to the "last" node in the tree or was NULL.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P );
/* ------------------------------------------------------------------------ **
* Given the node indicated by P, find the (sorted order) Previous node in
* the tree.
* Input: P - a pointer to a node that exists in a binary tree.
* Output: A pointer to the "previous" node in the tree, or NULL if P
* pointed to the "first" node in the tree or was NULL.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P );
/* ------------------------------------------------------------------------ **
* Given the node indicated by P, find the (sorted order) First node in the
* subtree of which *P is the root.
* Input: P - a pointer to a node that exists in a binary tree.
* Output: A pointer to the "first" node in a subtree that has *P as its
* root. This function will return NULL only if P is NULL.
* Note: In general, you will be passing in the value of the root field
* of an ubi_btRoot structure.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btLast( ubi_btNodePtr P );
/* ------------------------------------------------------------------------ **
* Given the node indicated by P, find the (sorted order) Last node in the
* subtree of which *P is the root.
* Input: P - a pointer to a node that exists in a binary tree.
* Output: A pointer to the "last" node in a subtree that has *P as its
* root. This function will return NULL only if P is NULL.
* Note: In general, you will be passing in the value of the root field
* of an ubi_btRoot structure.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
ubi_btItemPtr MatchMe,
ubi_btNodePtr p );
/* ------------------------------------------------------------------------ **
* Given a tree that a allows duplicate keys, and a pointer to a node in
* the tree, this function will return a pointer to the first (traversal
* order) node with the same key value.
*
* Input: RootPtr - A pointer to the root of the tree.
* MatchMe - A pointer to the key value. This should probably
* point to the key within node *p.
* p - A pointer to a node in the tree.
* Output: A pointer to the first node in the set of nodes with keys
* matching <FindMe>.
* Notes: Node *p MUST be in the set of nodes with keys matching
* <FindMe>. If not, this function will return NULL.
*
* 4.7: Bug found & fixed by Massimo Campostrini,
* Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
*
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
ubi_btItemPtr MatchMe,
ubi_btNodePtr p );
/* ------------------------------------------------------------------------ **
* Given a tree that a allows duplicate keys, and a pointer to a node in
* the tree, this function will return a pointer to the last (traversal
* order) node with the same key value.
*
* Input: RootPtr - A pointer to the root of the tree.
* MatchMe - A pointer to the key value. This should probably
* point to the key within node *p.
* p - A pointer to a node in the tree.
* Output: A pointer to the last node in the set of nodes with keys
* matching <FindMe>.
* Notes: Node *p MUST be in the set of nodes with keys matching
* <FindMe>. If not, this function will return NULL.
*
* 4.7: Bug found & fixed by Massimo Campostrini,
* Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
*
* ------------------------------------------------------------------------ **
*/
unsigned long ubi_btTraverse( ubi_btRootPtr RootPtr,
ubi_btActionRtn EachNode,
void *UserData );
/* ------------------------------------------------------------------------ **
* Traverse a tree in sorted order (non-recursively). At each node, call
* (*EachNode)(), passing a pointer to the current node, and UserData as the
* second parameter.
*
* Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
* the tree to be traversed.
* EachNode - a pointer to a function to be called at each node
* as the node is visited.
* UserData - a generic pointer that may point to anything that
* you choose.
*
* Output: A count of the number of nodes visited. This will be zero
* if the tree is empty.
*
* ------------------------------------------------------------------------ **
*/
unsigned long ubi_btKillTree( ubi_btRootPtr RootPtr,
ubi_btKillNodeRtn FreeNode );
/* ------------------------------------------------------------------------ **
* Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
* structure. Return a count of the number of nodes deleted.
*
* Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
* the root of the tree to delete.
* FreeNode - a function that will be called for each node in the
* tree to deallocate the memory used by the node.
*
* Output: The number of nodes removed from the tree.
* A value of 0 will be returned if:
* - The tree actually contains 0 entries.
* - the value of <RootPtr> is NULL, in which case the tree is
* assumed to be empty
* - the value of <FreeNode> is NULL, in which case entries
* cannot be removed, so 0 is returned. *Make sure that you
* provide a valid value for <FreeNode>*.
* In all other cases, you should get a positive value equal to
* the value of RootPtr->count upon entry.
*
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader );
/* ------------------------------------------------------------------------ **
* Returns a pointer to a leaf node.
*
* Input: leader - Pointer to a node at which to start the descent.
*
* Output: A pointer to a leaf node selected in a somewhat arbitrary
* manner.
*
* Notes: I wrote this function because I was using splay trees as a
* database cache. The cache had a maximum size on it, and I
* needed a way of choosing a node to sacrifice if the cache
* became full. In a splay tree, less recently accessed nodes
* tend toward the bottom of the tree, meaning that leaf nodes
* are good candidates for removal. (I really can't think of
* any other reason to use this function.)
* + In a simple binary tree or an AVL tree, the most recently
* added nodes tend to be nearer the bottom, making this a *bad*
* way to choose which node to remove from the cache.
* + Randomizing the traversal order is probably a good idea. You
* can improve the randomization of leaf node selection by passing
* in pointers to nodes other than the root node each time. A
* pointer to any node in the tree will do. Of course, if you
* pass a pointer to a leaf node you'll get the same thing back.
*
* ------------------------------------------------------------------------ **
*/
int ubi_btModuleID( int size, char *list[] );
/* ------------------------------------------------------------------------ **
* Returns a set of strings that identify the module.
*
* Input: size - The number of elements in the array <list>.
* list - An array of pointers of type (char *). This array
* should, initially, be empty. This function will fill
* in the array with pointers to strings.
* Output: The number of elements of <list> that were used. If this value
* is less than <size>, the values of the remaining elements are
* not guaranteed.
*
* Notes: Please keep in mind that the pointers returned indicate strings
* stored in static memory. Don't free() them, don't write over
* them, etc. Just read them.
* ------------------------------------------------------------------------ **
*/
/* -------------------------------------------------------------------------- **
* Masquarade...
*
* This set of defines allows you to write programs that will use any of the
* implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
* Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
* including the appropriate module header.
*/
#define ubi_trItemPtr ubi_btItemPtr
#define ubi_trNode ubi_btNode
#define ubi_trNodePtr ubi_btNodePtr
#define ubi_trRoot ubi_btRoot
#define ubi_trRootPtr ubi_btRootPtr
#define ubi_trCompFunc ubi_btCompFunc
#define ubi_trActionRtn ubi_btActionRtn
#define ubi_trKillNodeRtn ubi_btKillNodeRtn
#define ubi_trSgn( x ) ubi_btSgn( x )
#define ubi_trInitNode( Np ) ubi_btInitNode( (ubi_btNodePtr)(Np) )
#define ubi_trInitTree( Rp, Cf, Fl ) \
ubi_btInitTree( (ubi_btRootPtr)(Rp), (ubi_btCompFunc)(Cf), (Fl) )
#define ubi_trInsert( Rp, Nn, Ip, On ) \
ubi_btInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
(ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
#define ubi_trRemove( Rp, Dn ) \
ubi_btRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
#define ubi_trLocate( Rp, Ip, Op ) \
ubi_btLocate( (ubi_btRootPtr)(Rp), \
(ubi_btItemPtr)(Ip), \
(ubi_trCompOps)(Op) )
#define ubi_trFind( Rp, Ip ) \
ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
#define ubi_trNext( P ) ubi_btNext( (ubi_btNodePtr)(P) )
#define ubi_trPrev( P ) ubi_btPrev( (ubi_btNodePtr)(P) )
#define ubi_trFirst( P ) ubi_btFirst( (ubi_btNodePtr)(P) )
#define ubi_trLast( P ) ubi_btLast( (ubi_btNodePtr)(P) )
#define ubi_trFirstOf( Rp, Ip, P ) \
ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
(ubi_btItemPtr)(Ip), \
(ubi_btNodePtr)(P) )
#define ubi_trLastOf( Rp, Ip, P ) \
ubi_btLastOf( (ubi_btRootPtr)(Rp), \
(ubi_btItemPtr)(Ip), \
(ubi_btNodePtr)(P) )
#define ubi_trTraverse( Rp, En, Ud ) \
ubi_btTraverse((ubi_btRootPtr)(Rp), (ubi_btActionRtn)(En), (void *)(Ud))
#define ubi_trKillTree( Rp, Fn ) \
ubi_btKillTree( (ubi_btRootPtr)(Rp), (ubi_btKillNodeRtn)(Fn) )
#define ubi_trLeafNode( Nd ) \
ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
#define ubi_trModuleID( s, l ) ubi_btModuleID( s, l )
/* ========================================================================== */
#endif /* UBI_BINTREE_H */

506
lib/ubi_Cache.c Normal file
View File

@ -0,0 +1,506 @@
/* ========================================================================== **
* ubi_Cache.c
*
* Copyright (C) 1997 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
*
* This module implements a generic cache.
*
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* This module uses a splay tree to implement a simple cache. The cache
* module adds a thin layer of functionality to the splay tree. In
* particular:
*
* - The tree (cache) may be limited in size by the number of
* entries permitted or the amount of memory used. When either
* limit is exceeded cache entries are removed until the cache
* conforms.
* - Some statistical information is kept so that an approximate
* "hit ratio" can be calculated.
* - There are several functions available that provide access to
* and management of cache size limits, hit ratio, and tree
* trimming.
*
* The splay tree is used because recently accessed items tend toward the
* top of the tree and less recently accessed items tend toward the bottom.
* This makes it easy to purge less recently used items should the cache
* exceed its limits.
*
* To use this module, you will need to supply a comparison function of
* type ubi_trCompFunc and a node-freeing function of type
* ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
* these. (This is all basic ubiqx tree management stuff.)
*
* Notes:
*
* - Cache performance will start to suffer dramatically if the
* cache becomes large enough to force the OS to start swapping
* memory to disk. This is because the nodes of the underlying tree
* will be scattered across memory in an order that is completely
* unrelated to their traversal order. As more and more of the
* cache is placed into swap space, more and more swaps will be
* required for a simple traversal (...and then there's the splay
* operation).
*
* In one simple test under Linux, the load and dump of a cache of
* 400,000 entries took only 1min, 40sec of real time. The same
* test with 450,000 records took 2 *hours* and eight minutes.
*
* - In an effort to save memory, I considered using an unsigned
* short to save the per-entry entry size. I would have tucked this
* value into some unused space in the tree node structure. On
* 32-bit word aligned systems this would have saved an additional
* four bytes per entry. I may revisit this issue, but for now I've
* decided against it.
*
* Using an unsigned short would limit the size of an entry to 64K
* bytes. That's probably more than enough for most applications.
* The key word in that last sentence, however, is "probably". I
* really dislike imposing such limits on things.
*
* - Each entry keeps track of the amount of memory it used and the
* cache header keeps the total. This information is provided via
* the EntrySize parameter in ubi_cachePut(), so it is up to you to
* make sure that the numbers are accurate. (The numbers don't even
* have to represent bytes used.)
*
* As you consider this, note that the strdup() function--as an
* example--will call malloc(). The latter generally allocates a
* multiple of the system word size, which may be more than the
* number of bytes needed to store the string.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_Cache.c,v
* Revision 0.4 1999/09/22 03:42:24 crh
* Fixed a minor typo.
*
* Revision 0.3 1998/06/03 18:00:15 crh
* Further fiddling with sys_include.h, which is no longer explicitly
* included by this module since it is inherited from ubi_BinTree.h.
*
* Revision 0.2 1998/06/02 01:36:18 crh
* Changed include name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.1 1998/05/20 04:36:02 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.0 1997/12/18 06:24:33 crh
* Initial Revision.
*
* ========================================================================== **
*/
#include "libs.h"
#include "ubi_Cache.h" /* Header for *this* module. */
/* -------------------------------------------------------------------------- **
* Static data...
*/
/* commented out until I make use of it...
static char ModuleID[] =
"ubi_Cache\n\
\tRevision: 0.4 \n\
\tDate: 1999/09/22 03:42:24 \n\
\tAuthor: crh \n";
*/
/* -------------------------------------------------------------------------- **
* Internal functions...
*/
static void free_entry( ubi_cacheRootPtr CachePtr, ubi_cacheEntryPtr EntryPtr )
/* ------------------------------------------------------------------------ **
* Free a ubi_cacheEntry, and adjust the mem_used counter accordingly.
*
* Input: CachePtr - A pointer to the cache from which the entry has
* been removed.
* EntryPtr - A pointer to the already removed entry.
*
* Output: none.
*
* Notes: The entry must be removed from the cache *before* this function
* is called!!!!
* ------------------------------------------------------------------------ **
*/
{
CachePtr->mem_used -= EntryPtr->entry_size;
(*CachePtr->free_func)( (void *)EntryPtr );
} /* free_entry */
static void cachetrim( ubi_cacheRootPtr crptr )
/* ------------------------------------------------------------------------ **
* Remove entries from the cache until the number of entries and the amount
* of memory used are *both* below or at the maximum.
*
* Input: crptr - pointer to the cache to be trimmed.
*
* Output: None.
*
* ------------------------------------------------------------------------ **
*/
{
while( ( crptr->max_entries && (crptr->max_entries < crptr->root.count) )
|| ( crptr->max_memory && (crptr->max_memory < crptr->mem_used) ) )
{
if( !ubi_cacheReduce( crptr, 1 ) )
return;
}
} /* cachetrim */
/* -------------------------------------------------------------------------- **
* Exported functions...
*/
ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
ubi_trCompFunc CompFunc,
ubi_trKillNodeRtn FreeFunc,
unsigned long MaxEntries,
unsigned long MaxMemory )
/* ------------------------------------------------------------------------ **
* Initialize a cache header structure.
*
* Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
* to be initialized.
* CompFunc - A pointer to the function that will be called
* to compare two cache values. See the module
* comments, above, for more information.
* FreeFunc - A pointer to a function that will be called
* to free a cache entry. If you allocated
* the cache entry using malloc(), then this
* will likely be free(). If you are allocating
* cache entries from a free list, then this will
* likely be a function that returns memory to the
* free list, etc.
* MaxEntries - The maximum number of entries that will be
* allowed to exist in the cache. If this limit
* is exceeded, then existing entries will be
* removed from the cache. A value of zero
* indicates that there is no limit on the number
* of cache entries. See ubi_cachePut().
* MaxMemory - The maximum amount of memory, in bytes, to be
* allocated to the cache (excluding the cache
* header). If this is exceeded, existing entries
* in the cache will be removed until enough memory
* has been freed to meet the condition. See
* ubi_cachePut().
*
* Output: A pointer to the initialized cache (i.e., the same as CachePtr).
*
* Notes: Both MaxEntries and MaxMemory may be changed after the cache
* has been created. See
* ubi_cacheSetMaxEntries()
* ubi_cacheSetMaxMemory()
* ubi_cacheGetMaxEntries()
* ubi_cacheGetMaxMemory() (the latter two are macros).
*
* - Memory is allocated in multiples of the word size. The
* return value of the strlen() function does not reflect
* this; it will allways be less than or equal to the amount
* of memory actually allocated. Keep this in mind when
* choosing a value for MaxMemory.
*
* ------------------------------------------------------------------------ **
*/
{
if( CachePtr )
{
(void)ubi_trInitTree( CachePtr, CompFunc, ubi_trOVERWRITE );
CachePtr->free_func = FreeFunc;
CachePtr->max_entries = MaxEntries;
CachePtr->max_memory = MaxMemory;
CachePtr->mem_used = 0;
CachePtr->cache_hits = 0;
CachePtr->cache_trys = 0;
}
return( CachePtr );
} /* ubi_cacheInit */
ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr )
/* ------------------------------------------------------------------------ **
* Remove and free all entries in an existing cache.
*
* Input: CachePtr - A pointer to the cache that is to be cleared.
*
* Output: A pointer to the cache header (i.e., the same as CachePtr).
* This function re-initializes the cache header.
*
* ------------------------------------------------------------------------ **
*/
{
if( CachePtr )
{
(void)ubi_trKillTree( CachePtr, CachePtr->free_func );
CachePtr->mem_used = 0;
CachePtr->cache_hits = 0;
CachePtr->cache_trys = 0;
}
return( CachePtr );
} /* ubi_cacheClear */
void ubi_cachePut( ubi_cacheRootPtr CachePtr,
unsigned long EntrySize,
ubi_cacheEntryPtr EntryPtr,
ubi_trItemPtr Key )
/* ------------------------------------------------------------------------ **
* Add an entry to the cache.
*
* Input: CachePtr - A pointer to the cache into which the entry
* will be added.
* EntrySize - The size, in bytes, of the memory block indicated
* by EntryPtr. This will be copied into the
* EntryPtr->entry_size field.
* EntryPtr - A pointer to a memory block that begins with a
* ubi_cacheEntry structure. The entry structure
* should be followed immediately by the data to be
* cached (even if that is a pointer to yet more data).
* Key - Pointer used to identify the lookup key within the
* Entry.
*
* Output: None.
*
* Notes: After adding the new node, the cache is "trimmed". This
* removes extra nodes if the tree has exceeded it's memory or
* entry count limits. It is unlikely that the newly added node
* will be purged from the cache (assuming a reasonably large
* cache), since new nodes in a splay tree (which is what this
* module was designed to use) are moved to the top of the tree
* and the cache purge process removes nodes from the bottom of
* the tree.
* - The underlying splay tree is opened in OVERWRITE mode. If
* the input key matches an existing key, the existing entry will
* be politely removed from the tree and freed.
* - Memory is allocated in multiples of the word size. The
* return value of the strlen() function does not reflect
* this; it will allways be less than or equal to the amount
* of memory actually allocated.
*
* ------------------------------------------------------------------------ **
*/
{
ubi_trNodePtr OldNode;
EntryPtr->entry_size = EntrySize;
CachePtr->mem_used += EntrySize;
(void)ubi_trInsert( CachePtr, EntryPtr, Key, &OldNode );
if( OldNode )
free_entry( CachePtr, (ubi_cacheEntryPtr)OldNode );
cachetrim( CachePtr );
} /* ubi_cachePut */
ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
ubi_trItemPtr FindMe )
/* ------------------------------------------------------------------------ **
* Attempt to retrieve an entry from the cache.
*
* Input: CachePtr - A ponter to the cache that is to be searched.
* FindMe - A ubi_trItemPtr that indicates the key for which
* to search.
*
* Output: A pointer to the cache entry that was found, or NULL if no
* matching entry was found.
*
* Notes: This function also updates the hit ratio counters.
* The counters are unsigned short. If the number of cache tries
* reaches 32768, then both the number of tries and the number of
* hits are divided by two. This prevents the counters from
* overflowing. See the comments in ubi_cacheHitRatio() for
* additional notes.
*
* ------------------------------------------------------------------------ **
*/
{
ubi_trNodePtr FoundPtr;
FoundPtr = ubi_trFind( CachePtr, FindMe );
if( FoundPtr )
CachePtr->cache_hits++;
CachePtr->cache_trys++;
if( CachePtr->cache_trys & 0x8000 )
{
CachePtr->cache_hits = CachePtr->cache_hits / 2;
CachePtr->cache_trys = CachePtr->cache_trys / 2;
}
return( (ubi_cacheEntryPtr)FoundPtr );
} /* ubi_cacheGet */
ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe )
/* ------------------------------------------------------------------------ **
* Find and delete the specified cache entry.
*
* Input: CachePtr - A pointer to the cache.
* DeleteMe - The key of the entry to be deleted.
*
* Output: TRUE if the entry was found & freed, else FALSE.
*
* ------------------------------------------------------------------------ **
*/
{
ubi_trNodePtr FoundPtr;
FoundPtr = ubi_trFind( CachePtr, DeleteMe );
if( FoundPtr )
{
(void)ubi_trRemove( CachePtr, FoundPtr );
free_entry( CachePtr, (ubi_cacheEntryPtr)FoundPtr );
return( ubi_trTRUE );
}
return( ubi_trFALSE );
} /* ubi_cacheDelete */
ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count )
/* ------------------------------------------------------------------------ **
* Remove <count> entries from the bottom of the cache.
*
* Input: CachePtr - A pointer to the cache which is to be reduced in
* size.
* count - The number of entries to remove.
*
* Output: The function will return TRUE if <count> entries were removed,
* else FALSE. A return value of FALSE should indicate that
* there were less than <count> entries in the cache, and that the
* cache is now empty.
*
* Notes: This function forces a reduction in the number of cache entries
* without requiring that the MaxMemory or MaxEntries values be
* changed.
*
* ------------------------------------------------------------------------ **
*/
{
ubi_trNodePtr NodePtr;
while( count )
{
NodePtr = ubi_trLeafNode( CachePtr->root.root );
if( NULL == NodePtr )
return( ubi_trFALSE );
else
{
(void)ubi_trRemove( CachePtr, NodePtr );
free_entry( CachePtr, (ubi_cacheEntryPtr)NodePtr );
}
count--;
}
return( ubi_trTRUE );
} /* ubi_cacheReduce */
unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
unsigned long NewSize )
/* ------------------------------------------------------------------------ **
* Change the maximum number of entries allowed to exist in the cache.
*
* Input: CachePtr - A pointer to the cache to be modified.
* NewSize - The new maximum number of cache entries.
*
* Output: The maximum number of entries previously allowed to exist in
* the cache.
*
* Notes: If the new size is less than the old size, this function will
* trim the cache (remove excess entries).
* - A value of zero indicates an unlimited number of entries.
*
* ------------------------------------------------------------------------ **
*/
{
unsigned long oldsize = CachePtr->max_entries; /* Save the old value. */
CachePtr->max_entries = NewSize; /* Apply the new value. */
if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
cachetrim( CachePtr ); /* remove excess. */
return( oldsize );
} /* ubi_cacheSetMaxEntries */
unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
unsigned long NewSize )
/* ------------------------------------------------------------------------ **
* Change the maximum amount of memory to be used for storing cache
* entries.
*
* Input: CachePtr - A pointer to the cache to be modified.
* NewSize - The new cache memory size.
*
* Output: The previous maximum memory size.
*
* Notes: If the new size is less than the old size, this function will
* trim the cache (remove excess entries).
* - A value of zero indicates that the cache has no memory limit.
*
* ------------------------------------------------------------------------ **
*/
{
unsigned long oldsize = CachePtr->max_memory; /* Save the old value. */
CachePtr->max_memory = NewSize; /* Apply the new value. */
if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
cachetrim( CachePtr ); /* remove excess. */
return( oldsize );
} /* ubi_cacheSetMaxMemory */
int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr )
/* ------------------------------------------------------------------------ **
* Returns a value that is 10,000 times the slightly weighted average hit
* ratio for the cache.
*
* Input: CachePtr - Pointer to the cache to be queried.
*
* Output: An integer that is 10,000 times the number of successful
* cache hits divided by the number of cache lookups, or:
* (10000 * hits) / trys
* You can easily convert this to a float, or do something
* like this (where i is the return value of this function):
*
* printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
*
* Notes: I say "slightly-weighted", because the numerator and
* denominator are both accumulated in locations of type
* 'unsigned short'. If the number of cache trys becomes
* large enough, both are divided by two. (See function
* ubi_cacheGet().)
* Dividing both numerator and denominator by two does not
* change the ratio (much...it is an integer divide), but it
* does mean that subsequent increments to either counter will
* have twice as much significance as previous ones.
*
* - The value returned by this function will be in the range
* [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
* always be true.
*
* ------------------------------------------------------------------------ **
*/
{
int tmp = 0;
if( CachePtr->cache_trys )
tmp = (int)( (10000 * (long)(CachePtr->cache_hits) )
/ (long)(CachePtr->cache_trys) );
return( tmp );
} /* ubi_cacheHitRatio */
/* -------------------------------------------------------------------------- */

412
lib/ubi_Cache.h Normal file
View File

@ -0,0 +1,412 @@
#ifndef UBI_CACHE_H
#define UBI_CACHE_H
/* ========================================================================== **
* ubi_Cache.h
*
* Copyright (C) 1997 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
*
* This module implements a generic cache.
*
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* This module uses a splay tree to implement a simple cache. The cache
* module adds a thin layer of functionality to the splay tree. In
* particular:
*
* - The tree (cache) may be limited in size by the number of
* entries permitted or the amount of memory used. When either
* limit is exceeded cache entries are removed until the cache
* conforms.
* - Some statistical information is kept so that an approximate
* "hit ratio" can be calculated.
* - There are several functions available that provide access to
* and management of cache size limits, hit ratio, and tree
* trimming.
*
* The splay tree is used because recently accessed items tend toward the
* top of the tree and less recently accessed items tend toward the bottom.
* This makes it easy to purge less recently used items should the cache
* exceed its limits.
*
* To use this module, you will need to supply a comparison function of
* type ubi_trCompFunc and a node-freeing function of type
* ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
* these. (This is all basic ubiqx tree management stuff.)
*
* Notes:
*
* - Cache performance will start to suffer dramatically if the
* cache becomes large enough to force the OS to start swapping
* memory to disk. This is because the nodes of the underlying tree
* will be scattered across memory in an order that is completely
* unrelated to their traversal order. As more and more of the
* cache is placed into swap space, more and more swaps will be
* required for a simple traversal (...and then there's the splay
* operation).
*
* In one simple test under Linux, the load and dump of a cache of
* 400,000 entries took only 1min, 40sec of real time. The same
* test with 450,000 records took 2 *hours* and eight minutes.
*
* - In an effort to save memory, I considered using an unsigned
* short to save the per-entry entry size. I would have tucked this
* value into some unused space in the tree node structure. On
* 32-bit word aligned systems this would have saved an additional
* four bytes per entry. I may revisit this issue, but for now I've
* decided against it.
*
* Using an unsigned short would limit the size of an entry to 64K
* bytes. That's probably more than enough for most applications.
* The key word in that last sentence, however, is "probably". I
* really dislike imposing such limits on things.
*
* - Each entry keeps track of the amount of memory it used and the
* cache header keeps the total. This information is provided via
* the EntrySize parameter in ubi_cachePut(), so it is up to you to
* make sure that the numbers are accurate. (The numbers don't even
* have to represent bytes used.)
*
* As you consider this, note that the strdup() function--as an
* example--will call malloc(). The latter generally allocates a
* multiple of the system word size, which may be more than the
* number of bytes needed to store the string.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_Cache.h,v
* Revision 0.4 1999/09/22 03:42:24 crh
* Fixed a minor typo.
*
* Revision 0.3 1998/06/03 18:00:15 crh
* Further fiddling with sys_include.h, which is no longer explicitly
* included by this module since it is inherited from ubi_BinTree.h.
*
* Revision 0.2 1998/06/02 01:36:18 crh
* Changed include name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.1 1998/05/20 04:36:02 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.0 1997/12/18 06:25:23 crh
* Initial Revision.
*
* ========================================================================== **
*/
#include "ubi_SplayTree.h"
/* -------------------------------------------------------------------------- **
* Typedefs...
*
* ubi_cacheRoot - Cache header structure, which consists of a binary
* tree root and other required housekeeping fields, as
* listed below.
* ubi_cacheRootPtr - Pointer to a Cache.
*
* ubi_cacheEntry - A cache Entry, which consists of a tree node
* structure and the size (in bytes) of the entry
* data. The entry size should be supplied via
* the EntrySize parameter of the ubi_cachePut()
* function.
*
* ubi_cacheEntryPtr - Pointer to a ubi_cacheEntry.
*
*/
typedef struct
{
ubi_trRoot root; /* Splay tree control structure. */
ubi_trKillNodeRtn free_func; /* Function used to free entries. */
unsigned long max_entries; /* Max cache entries. 0 == unlimited */
unsigned long max_memory; /* Max memory to use. 0 == unlimited */
unsigned long mem_used; /* Memory currently in use (bytes). */
unsigned short cache_hits; /* Incremented on succesful find. */
unsigned short cache_trys; /* Incremented on cache lookup. */
} ubi_cacheRoot;
typedef ubi_cacheRoot *ubi_cacheRootPtr;
typedef struct
{
ubi_trNode node; /* Tree node structure. */
unsigned long entry_size; /* Entry size. Used when managing
* caches with maximum memory limits.
*/
} ubi_cacheEntry;
typedef ubi_cacheEntry *ubi_cacheEntryPtr;
/* -------------------------------------------------------------------------- **
* Macros...
*
* ubi_cacheGetMaxEntries() - Report the current maximum number of entries
* allowed in the cache. Zero indicates no
* maximum.
* ubi_cacheGetMaxMemory() - Report the current maximum amount of memory
* that may be used in the cache. Zero
* indicates no maximum.
* ubi_cacheGetEntryCount() - Report the current number of entries in the
* cache.
* ubi_cacheGetMemUsed() - Report the amount of memory currently in use
* by the cache.
*/
#define ubi_cacheGetMaxEntries( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_entries)
#define ubi_cacheGetMaxMemory( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_memory)
#define ubi_cacheGetEntryCount( Cptr ) (((ubi_cacheRootPtr)(Cptr))->root.count)
#define ubi_cacheGetMemUsed( Cptr ) (((ubi_cacheRootPtr)(Cptr))->mem_used)
/* -------------------------------------------------------------------------- **
* Prototypes...
*/
ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
ubi_trCompFunc CompFunc,
ubi_trKillNodeRtn FreeFunc,
unsigned long MaxEntries,
unsigned long MaxMemory );
/* ------------------------------------------------------------------------ **
* Initialize a cache header structure.
*
* Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
* to be initialized.
* CompFunc - A pointer to the function that will be called
* to compare two cache values. See the module
* comments, above, for more information.
* FreeFunc - A pointer to a function that will be called
* to free a cache entry. If you allocated
* the cache entry using malloc(), then this
* will likely be free(). If you are allocating
* cache entries from a free list, then this will
* likely be a function that returns memory to the
* free list, etc.
* MaxEntries - The maximum number of entries that will be
* allowed to exist in the cache. If this limit
* is exceeded, then existing entries will be
* removed from the cache. A value of zero
* indicates that there is no limit on the number
* of cache entries. See ubi_cachePut().
* MaxMemory - The maximum amount of memory, in bytes, to be
* allocated to the cache (excluding the cache
* header). If this is exceeded, existing entries
* in the cache will be removed until enough memory
* has been freed to meet the condition. See
* ubi_cachePut().
*
* Output: A pointer to the initialized cache (i.e., the same as CachePtr).
*
* Notes: Both MaxEntries and MaxMemory may be changed after the cache
* has been created. See
* ubi_cacheSetMaxEntries()
* ubi_cacheSetMaxMemory()
* ubi_cacheGetMaxEntries()
* ubi_cacheGetMaxMemory() (the latter two are macros).
*
* - Memory is allocated in multiples of the word size. The
* return value of the strlen() function does not reflect
* this; it will allways be less than or equal to the amount
* of memory actually allocated. Keep this in mind when
* choosing a value for MaxMemory.
*
* ------------------------------------------------------------------------ **
*/
ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr );
/* ------------------------------------------------------------------------ **
* Remove and free all entries in an existing cache.
*
* Input: CachePtr - A pointer to the cache that is to be cleared.
*
* Output: A pointer to the cache header (i.e., the same as CachePtr).
* This function re-initializes the cache header.
*
* ------------------------------------------------------------------------ **
*/
void ubi_cachePut( ubi_cacheRootPtr CachePtr,
unsigned long EntrySize,
ubi_cacheEntryPtr EntryPtr,
ubi_trItemPtr Key );
/* ------------------------------------------------------------------------ **
* Add an entry to the cache.
*
* Input: CachePtr - A pointer to the cache into which the entry
* will be added.
* EntrySize - The size, in bytes, of the memory block indicated
* by EntryPtr. This will be copied into the
* EntryPtr->entry_size field.
* EntryPtr - A pointer to a memory block that begins with a
* ubi_cacheEntry structure. The entry structure
* should be followed immediately by the data to be
* cached (even if that is a pointer to yet more data).
* Key - Pointer used to identify the lookup key within the
* Entry.
*
* Output: None.
*
* Notes: After adding the new node, the cache is "trimmed". This
* removes extra nodes if the tree has exceeded it's memory or
* entry count limits. It is unlikely that the newly added node
* will be purged from the cache (assuming a reasonably large
* cache), since new nodes in a splay tree (which is what this
* module was designed to use) are moved to the top of the tree
* and the cache purge process removes nodes from the bottom of
* the tree.
* - The underlying splay tree is opened in OVERWRITE mode. If
* the input key matches an existing key, the existing entry will
* be politely removed from the tree and freed.
* - Memory is allocated in multiples of the word size. The
* return value of the strlen() function does not reflect
* this; it will allways be less than or equal to the amount
* of memory actually allocated.
*
* ------------------------------------------------------------------------ **
*/
ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
ubi_trItemPtr FindMe );
/* ------------------------------------------------------------------------ **
* Attempt to retrieve an entry from the cache.
*
* Input: CachePtr - A ponter to the cache that is to be searched.
* FindMe - A ubi_trItemPtr that indicates the key for which
* to search.
*
* Output: A pointer to the cache entry that was found, or NULL if no
* matching entry was found.
*
* Notes: This function also updates the hit ratio counters.
* The counters are unsigned short. If the number of cache tries
* reaches 32768, then both the number of tries and the number of
* hits are divided by two. This prevents the counters from
* overflowing. See the comments in ubi_cacheHitRatio() for
* additional notes.
*
* ------------------------------------------------------------------------ **
*/
ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe );
/* ------------------------------------------------------------------------ **
* Find and delete the specified cache entry.
*
* Input: CachePtr - A pointer to the cache.
* DeleteMe - The key of the entry to be deleted.
*
* Output: TRUE if the entry was found & freed, else FALSE.
*
* ------------------------------------------------------------------------ **
*/
ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count );
/* ------------------------------------------------------------------------ **
* Remove <count> entries from the bottom of the cache.
*
* Input: CachePtr - A pointer to the cache which is to be reduced in
* size.
* count - The number of entries to remove.
*
* Output: The function will return TRUE if <count> entries were removed,
* else FALSE. A return value of FALSE should indicate that
* there were less than <count> entries in the cache, and that the
* cache is now empty.
*
* Notes: This function forces a reduction in the number of cache entries
* without requiring that the MaxMemory or MaxEntries values be
* changed.
*
* ------------------------------------------------------------------------ **
*/
unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
unsigned long NewSize );
/* ------------------------------------------------------------------------ **
* Change the maximum number of entries allowed to exist in the cache.
*
* Input: CachePtr - A pointer to the cache to be modified.
* NewSize - The new maximum number of cache entries.
*
* Output: The maximum number of entries previously allowed to exist in
* the cache.
*
* Notes: If the new size is less than the old size, this function will
* trim the cache (remove excess entries).
* - A value of zero indicates an unlimited number of entries.
*
* ------------------------------------------------------------------------ **
*/
unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
unsigned long NewSize );
/* ------------------------------------------------------------------------ **
* Change the maximum amount of memory to be used for storing cache
* entries.
*
* Input: CachePtr - A pointer to the cache to be modified.
* NewSize - The new cache memory size.
*
* Output: The previous maximum memory size.
*
* Notes: If the new size is less than the old size, this function will
* trim the cache (remove excess entries).
* - A value of zero indicates that the cache has no memory limit.
*
* ------------------------------------------------------------------------ **
*/
int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr );
/* ------------------------------------------------------------------------ **
* Returns a value that is 10,000 times the slightly weighted average hit
* ratio for the cache.
*
* Input: CachePtr - Pointer to the cache to be queried.
*
* Output: An integer that is 10,000 times the number of successful
* cache hits divided by the number of cache lookups, or:
* (10000 * hits) / trys
* You can easily convert this to a float, or do something
* like this (where i is the return value of this function):
*
* printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
*
* Notes: I say "slightly-weighted", because the numerator and
* denominator are both accumulated in locations of type
* 'unsigned short'. If the number of cache trys becomes
* large enough, both are divided by two. (See function
* ubi_cacheGet().)
* Dividing both numerator and denominator by two does not
* change the ratio (much...it is an integer divide), but it
* does mean that subsequent increments to either counter will
* have twice as much significance as previous ones.
*
* - The value returned by this function will be in the range
* [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
* always be true.
*
* ------------------------------------------------------------------------ **
*/
/* -------------------------------------------------------------------------- */
#endif /* ubi_CACHE_H */

513
lib/ubi_SplayTree.c Normal file
View File

@ -0,0 +1,513 @@
/* ========================================================================== **
* ubi_SplayTree.c
*
* Copyright (C) 1993-1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
*
* This module implements "splay" trees. Splay trees are binary trees
* that are rearranged (splayed) whenever a node is accessed. The
* splaying process *tends* to make the tree bushier (improves balance),
* and the nodes that are accessed most frequently *tend* to be closer to
* the top.
*
* References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
* Robert Tarjan. Journal of the Association for Computing
* Machinery Vol 32, No. 3, July 1985 pp. 652-686
*
* See also: http://www.cs.cmu.edu/~sleator/
*
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_SplayTree.c,v
* Revision 4.5 2000/01/08 23:26:49 crh
* Added ubi_trSplay() macro, which does a type cast for us.
*
* Revision 4.4 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 4.3 1998/06/03 17:45:05 crh
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
* included by all of the binary tree files.
*
* Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
* to like syntax like this:
*
* if( (a = b) )
*
* The fix was to change lines like the above to:
*
* if( 0 != (a=b) )
*
* Which means the same thing.
*
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
* of tree types by simply changing a header. Unfortunately, the
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
* conflict if used together. You must either choose a single tree
* type, or use the underlying function calls directly. Compare
* the two header files for more information.
*
* Revision 4.2 1998/06/02 01:29:14 crh
* Changed ubi_null.h to sys_include.h to make it more generic.
*
* Revision 4.1 1998/05/20 04:37:54 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 4.0 1998/03/10 03:41:33 crh
* Minor comment changes. The revision number is now 4.0 to match the
* BinTree and AVLtree modules.
*
* Revision 2.7 1998/01/24 06:37:08 crh
* Added a URL for more information.
*
* Revision 2.6 1997/12/23 04:01:12 crh
* In this version, all constants & macros defined in the header file have
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
* when run with '-pedantic -fsyntax-only -Wall'.
*
* Revision 2.5 1997/07/26 04:15:42 crh
* + Cleaned up a few minor syntax annoyances that gcc discovered for me.
* + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
*
* Revision 2.4 1997/06/03 04:42:21 crh
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
* problems.
*
* Revision 2.3 1995/10/03 22:19:07 CRH
* Ubisized!
* Also, added the function ubi_sptSplay().
*
* Revision 2.1 95/03/09 23:54:42 CRH
* Added the ModuleID static string and function. These modules are now
* self-identifying.
*
* Revision 2.0 95/02/27 22:34:46 CRH
* This module was updated to match the interface changes made to the
* ubi_BinTree module. In particular, the interface to the Locate() function
* has changed. See ubi_BinTree for more information on changes and new
* functions.
*
* The revision number was also upped to match ubi_BinTree.
*
* Revision 1.1 93/10/18 20:35:16 CRH
* I removed the hard-coded logical device names from the include file
* specifications. CRH
*
* Revision 1.0 93/10/15 23:00:15 CRH
* With this revision, I have added a set of #define's that provide a single,
* standard API to all existing tree modules. Until now, each of the three
* existing modules had a different function and typedef prefix, as follows:
*
* Module Prefix
* ubi_BinTree ubi_bt
* ubi_AVLtree ubi_avl
* ubi_SplayTree ubi_spt
*
* To further complicate matters, only those portions of the base module
* (ubi_BinTree) that were superceeded in the new module had the new names.
* For example, if you were using ubi_SplayTree, the locate function was
* called "ubi_sptLocate", but the next and previous functions remained
* "ubi_btNext" and "ubi_btPrev".
*
* This was not too terrible if you were familiar with the modules and knew
* exactly which tree model you wanted to use. If you wanted to be able to
* change modules (for speed comparisons, etc), things could get messy very
* quickly.
*
* So, I have added a set of defined names that get redefined in any of the
* descendant modules. To use this standardized interface in your code,
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
* datatype names for the module that you are using. Just remember to
* include the header for that module in your program file. Because these
* names are handled by the preprocessor, there is no added run-time
* overhead.
*
* Note that the original names do still exist, and can be used if you wish
* to write code directly to a specific module. This should probably only be
* done if you are planning to implement a new descendant type, such as
* red/black trees. CRH
*
* Revision 0.1 93/04/25 22:03:32 CRH
* Simply changed the <exec/types.h> #include reference the .c file to
* use <stdlib.h> instead. The latter is portable, the former is not.
*
* Revision 0.0 93/04/21 23:05:52 CRH
* Initial version, written by Christopher R. Hertel.
* This module implements Splay Trees using the ubi_BinTree module as a basis.
*
* ========================================================================== **
*/
#include "libs.h"
#include "ubi_SplayTree.h" /* Header for THIS module. */
/* ========================================================================== **
* Static data.
*/
static char ModuleID[] = "ubi_SplayTree\n\
\tRevision: 4.5 \n\
\tDate: 2000/01/08 23:26:49 \n\
\tAuthor: crh \n";
/* ========================================================================== **
* Private functions...
*/
static void Rotate( ubi_btNodePtr p )
/* ------------------------------------------------------------------------ **
* This function performs a single rotation, moving node *p up one level
* in the tree.
*
* Input: p - a pointer to an ubi_btNode in a tree.
*
* Output: None.
*
* Notes: This implements a single rotation in either direction (left
* or right). This is the basic building block of all splay
* tree rotations.
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr parentp;
ubi_btNodePtr tmp;
char way;
char revway;
parentp = p->Link[ubi_trPARENT]; /* Find parent. */
if( parentp ) /* If no parent, then we're already the root. */
{
way = p->gender;
revway = ubi_trRevWay(way);
tmp = p->Link[(int)revway];
parentp->Link[(int)way] = tmp;
if( tmp )
{
tmp->Link[ubi_trPARENT] = parentp;
tmp->gender = way;
}
tmp = parentp->Link[ubi_trPARENT];
p->Link[ubi_trPARENT] = tmp;
p->gender = parentp->gender;
if( tmp )
tmp->Link[(int)(p->gender)] = p;
parentp->Link[ubi_trPARENT] = p;
parentp->gender = revway;
p->Link[(int)revway] = parentp;
}
} /* Rotate */
static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
/* ------------------------------------------------------------------------ **
* Move the node indicated by SplayWithMe to the root of the tree by
* splaying the tree.
*
* Input: SplayWithMe - A pointer to an ubi_btNode within a tree.
*
* Output: A pointer to the root of the splay tree (i.e., the same as
* SplayWithMe).
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr parent;
while( NULL != (parent = SplayWithMe->Link[ubi_trPARENT]) )
{
if( parent->gender == SplayWithMe->gender ) /* Zig-Zig */
Rotate( parent );
else
{
if( ubi_trEQUAL != parent->gender ) /* Zig-Zag */
Rotate( SplayWithMe );
}
Rotate( SplayWithMe ); /* Zig */
} /* while */
return( SplayWithMe );
} /* Splay */
/* ========================================================================== **
* Exported utilities.
*/
ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
ubi_btNodePtr NewNode,
ubi_btItemPtr ItemPtr,
ubi_btNodePtr *OldNode )
/* ------------------------------------------------------------------------ **
* This function uses a non-recursive algorithm to add a new element to the
* splay tree.
*
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
* the root of the tree to which NewNode is to be added.
* NewNode - a pointer to an ubi_btNode structure that is NOT
* part of any tree.
* ItemPtr - A pointer to the sort key that is stored within
* *NewNode. ItemPtr MUST point to information stored
* in *NewNode or an EXACT DUPLICATE. The key data
* indicated by ItemPtr is used to place the new node
* into the tree.
* OldNode - a pointer to an ubi_btNodePtr. When searching
* the tree, a duplicate node may be found. If
* duplicates are allowed, then the new node will
* be simply placed into the tree. If duplicates
* are not allowed, however, then one of two things
* may happen.
* 1) if overwritting *is not* allowed, this
* function will return FALSE (indicating that
* the new node could not be inserted), and
* *OldNode will point to the duplicate that is
* still in the tree.
* 2) if overwritting *is* allowed, then this
* function will swap **OldNode for *NewNode.
* In this case, *OldNode will point to the node
* that was removed (thus allowing you to free
* the node).
* ** If you are using overwrite mode, ALWAYS **
* ** check the return value of this parameter! **
* Note: You may pass NULL in this parameter, the
* function knows how to cope. If you do this,
* however, there will be no way to return a
* pointer to an old (ie. replaced) node (which is
* a problem if you are using overwrite mode).
*
* Output: a boolean value indicating success or failure. The function
* will return FALSE if the node could not be added to the tree.
* Such failure will only occur if duplicates are not allowed,
* nodes cannot be overwritten, AND a duplicate key was found
* within the tree.
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr OtherP;
if( !(OldNode) )
OldNode = &OtherP;
if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
{
RootPtr->root = Splay( NewNode );
return( ubi_trTRUE );
}
/* Splay the unreplacable, duplicate keyed, unique, old node. */
RootPtr->root = Splay( (*OldNode) );
return( ubi_trFALSE );
} /* ubi_sptInsert */
ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
/* ------------------------------------------------------------------------ **
* This function removes the indicated node from the tree.
*
* Input: RootPtr - A pointer to the header of the tree that contains
* the node to be removed.
* DeadNode - A pointer to the node that will be removed.
*
* Output: This function returns a pointer to the node that was removed
* from the tree (ie. the same as DeadNode).
*
* Note: The node MUST be in the tree indicated by RootPtr. If not,
* strange and evil things will happen to your trees.
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr p;
(void)Splay( DeadNode ); /* Move dead node to root. */
if( NULL != (p = DeadNode->Link[ubi_trLEFT]) )
{ /* If left subtree exists... */
ubi_btNodePtr q = DeadNode->Link[ubi_trRIGHT];
p->Link[ubi_trPARENT] = NULL; /* Left subtree node becomes root.*/
p->gender = ubi_trPARENT;
p = ubi_btLast( p ); /* Find rightmost left node... */
p->Link[ubi_trRIGHT] = q; /* ...attach right tree. */
if( q )
q->Link[ubi_trPARENT] = p;
RootPtr->root = Splay( p ); /* Resplay at p. */
}
else
{
if( NULL != (p = DeadNode->Link[ubi_trRIGHT]) )
{ /* No left, but right subtree exists... */
p->Link[ubi_trPARENT] = NULL; /* Right subtree root becomes... */
p->gender = ubi_trPARENT; /* ...overall tree root. */
RootPtr->root = p;
}
else
RootPtr->root = NULL; /* No subtrees => empty tree. */
}
(RootPtr->count)--; /* Decrement node count. */
return( DeadNode ); /* Return pointer to pruned node. */
} /* ubi_sptRemove */
ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe,
ubi_trCompOps CompOp )
/* ------------------------------------------------------------------------ **
* The purpose of ubi_btLocate() is to find a node or set of nodes given
* a target value and a "comparison operator". The Locate() function is
* more flexible and (in the case of trees that may contain dupicate keys)
* more precise than the ubi_btFind() function. The latter is faster,
* but it only searches for exact matches and, if the tree contains
* duplicates, Find() may return a pointer to any one of the duplicate-
* keyed records.
*
* Input:
* RootPtr - A pointer to the header of the tree to be searched.
* FindMe - An ubi_btItemPtr that indicates the key for which to
* search.
* CompOp - One of the following:
* CompOp Return a pointer to the node with
* ------ ---------------------------------
* ubi_trLT - the last key value that is less
* than FindMe.
* ubi_trLE - the first key matching FindMe, or
* the last key that is less than
* FindMe.
* ubi_trEQ - the first key matching FindMe.
* ubi_trGE - the first key matching FindMe, or the
* first key greater than FindMe.
* ubi_trGT - the first key greater than FindMe.
* Output:
* A pointer to the node matching the criteria listed above under
* CompOp, or NULL if no node matched the criteria.
*
* Notes:
* In the case of trees with duplicate keys, Locate() will behave as
* follows:
*
* Find: 3 Find: 3
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
* ^ ^ ^ ^ ^
* LT EQ GT LE GE
*
* That is, when returning a pointer to a node with a key that is LESS
* THAN the target key (FindMe), Locate() will return a pointer to the
* LAST matching node.
* When returning a pointer to a node with a key that is GREATER
* THAN the target key (FindMe), Locate() will return a pointer to the
* FIRST matching node.
*
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr p;
p = ubi_btLocate( RootPtr, FindMe, CompOp );
if( p )
RootPtr->root = Splay( p );
return( p );
} /* ubi_sptLocate */
ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe )
/* ------------------------------------------------------------------------ **
* This function performs a non-recursive search of a tree for any node
* matching a specific key.
*
* Input:
* RootPtr - a pointer to the header of the tree to be searched.
* FindMe - a pointer to the key value for which to search.
*
* Output:
* A pointer to a node with a key that matches the key indicated by
* FindMe, or NULL if no such node was found.
*
* Note: In a tree that allows duplicates, the pointer returned *might
* not* point to the (sequentially) first occurance of the
* desired key. In such a tree, it may be more useful to use
* ubi_sptLocate().
* ------------------------------------------------------------------------ **
*/
{
ubi_btNodePtr p;
p = ubi_btFind( RootPtr, FindMe );
if( p )
RootPtr->root = Splay( p );
return( p );
} /* ubi_sptFind */
void ubi_sptSplay( ubi_btRootPtr RootPtr,
ubi_btNodePtr SplayMe )
/* ------------------------------------------------------------------------ **
* This function allows you to splay the tree at a given node, thus moving
* the node to the top of the tree.
*
* Input:
* RootPtr - a pointer to the header of the tree to be splayed.
* SplayMe - a pointer to a node within the tree. This will become
* the new root node.
* Output: None.
*
* Notes: This is an uncharacteristic function for this group of modules
* in that it provides access to the internal balancing routines,
* which would normally be hidden.
* Splaying the tree will not damage it (assuming that I've done
* *my* job), but there is overhead involved. I don't recommend
* that you use this function unless you understand the underlying
* Splay Tree principles involved.
* ------------------------------------------------------------------------ **
*/
{
RootPtr->root = Splay( SplayMe );
} /* ubi_sptSplay */
int ubi_sptModuleID( int size, char *list[] )
/* ------------------------------------------------------------------------ **
* Returns a set of strings that identify the module.
*
* Input: size - The number of elements in the array <list>.
* list - An array of pointers of type (char *). This array
* should, initially, be empty. This function will fill
* in the array with pointers to strings.
* Output: The number of elements of <list> that were used. If this value
* is less than <size>, the values of the remaining elements are
* not guaranteed.
*
* Notes: Please keep in mind that the pointers returned indicate strings
* stored in static memory. Don't free() them, don't write over
* them, etc. Just read them.
* ------------------------------------------------------------------------ **
*/
{
if( size > 0 )
{
list[0] = ModuleID;
if( size > 1 )
return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
return( 1 );
}
return( 0 );
} /* ubi_sptModuleID */
/* ================================ The End ================================= */

377
lib/ubi_SplayTree.h Normal file
View File

@ -0,0 +1,377 @@
#ifndef UBI_SPLAYTREE_H
#define UBI_SPLAYTREE_H
/* ========================================================================== **
* ubi_SplayTree.h
*
* Copyright (C) 1993-1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
*
* This module implements "splay" trees. Splay trees are binary trees
* that are rearranged (splayed) whenever a node is accessed. The
* splaying process *tends* to make the tree bushier (improves balance),
* and the nodes that are accessed most frequently *tend* to be closer to
* the top.
*
* References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
* Robert Tarjan. Journal of the Association for Computing
* Machinery Vol 32, No. 3, July 1985 pp. 652-686
*
* See also: http://www.cs.cmu.edu/~sleator/
*
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_SplayTree.h,v
* Revision 4.5 2000/01/08 23:26:49 crh
* Added ubi_trSplay() macro, which does a type cast for us.
*
* Revision 4.4 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 4.3 1998/06/03 17:45:05 crh
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
* included by all of the binary tree files.
*
* Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
* to like syntax like this:
*
* if( (a = b) )
*
* The fix was to change lines like the above to:
*
* if( 0 != (a=b) )
*
* Which means the same thing.
*
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
* of tree types by simply changing a header. Unfortunately, the
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
* conflict if used together. You must either choose a single tree
* type, or use the underlying function calls directly. Compare
* the two header files for more information.
*
* Revision 4.2 1998/06/02 01:29:14 crh
* Changed ubi_null.h to sys_include.h to make it more generic.
*
* Revision 4.1 1998/05/20 04:37:54 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 4.0 1998/03/10 03:40:57 crh
* Minor comment changes. The revision number is now 4.0 to match the
* BinTree and AVLtree modules.
*
* Revision 2.7 1998/01/24 06:37:57 crh
* Added a URL for more information.
*
* Revision 2.6 1997/12/23 04:02:20 crh
* In this version, all constants & macros defined in the header file have
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
* when run with '-pedantic -fsyntax-only -Wall'.
*
* Revision 2.5 1997/07/26 04:15:46 crh
* + Cleaned up a few minor syntax annoyances that gcc discovered for me.
* + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
*
* Revision 2.4 1997/06/03 05:22:56 crh
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
* problems.
*
* Revision 2.3 1995/10/03 22:19:37 CRH
* Ubisized!
* Also, added the function ubi_sptSplay().
*
* Revision 2.1 95/03/09 23:55:04 CRH
* Added the ModuleID static string and function. These modules are now
* self-identifying.
*
* Revision 2.0 95/02/27 22:34:55 CRH
* This module was updated to match the interface changes made to the
* ubi_BinTree module. In particular, the interface to the Locate() function
* has changed. See ubi_BinTree for more information on changes and new
* functions.
*
* The revision number was also upped to match ubi_BinTree.
*
*
* Revision 1.0 93/10/15 22:59:36 CRH
* With this revision, I have added a set of #define's that provide a single,
* standard API to all existing tree modules. Until now, each of the three
* existing modules had a different function and typedef prefix, as follows:
*
* Module Prefix
* ubi_BinTree ubi_bt
* ubi_AVLtree ubi_avl
* ubi_SplayTree ubi_spt
*
* To further complicate matters, only those portions of the base module
* (ubi_BinTree) that were superceeded in the new module had the new names.
* For example, if you were using ubi_SplayTree, the locate function was
* called "ubi_sptLocate", but the next and previous functions remained
* "ubi_btNext" and "ubi_btPrev".
*
* This was not too terrible if you were familiar with the modules and knew
* exactly which tree model you wanted to use. If you wanted to be able to
* change modules (for speed comparisons, etc), things could get messy very
* quickly.
*
* So, I have added a set of defined names that get redefined in any of the
* descendant modules. To use this standardized interface in your code,
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
* datatype names for the module that you are using. Just remember to
* include the header for that module in your program file. Because these
* names are handled by the preprocessor, there is no added run-time
* overhead.
*
* Note that the original names do still exist, and can be used if you wish
* to write code directly to a specific module. This should probably only be
* done if you are planning to implement a new descendant type, such as
* red/black trees. CRH
*
* Revision 0.0 93/04/21 23:07:13 CRH
* Initial version, written by Christopher R. Hertel.
* This module implements Splay Trees using the ubi_BinTree module as a basis.
*
* ========================================================================== **
*/
#include "ubi_BinTree.h" /* Base binary tree functions, types, etc. */
/* ========================================================================== **
* Function prototypes...
*/
ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
ubi_btNodePtr NewNode,
ubi_btItemPtr ItemPtr,
ubi_btNodePtr *OldNode );
/* ------------------------------------------------------------------------ **
* This function uses a non-recursive algorithm to add a new element to the
* splay tree.
*
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
* the root of the tree to which NewNode is to be added.
* NewNode - a pointer to an ubi_btNode structure that is NOT
* part of any tree.
* ItemPtr - A pointer to the sort key that is stored within
* *NewNode. ItemPtr MUST point to information stored
* in *NewNode or an EXACT DUPLICATE. The key data
* indicated by ItemPtr is used to place the new node
* into the tree.
* OldNode - a pointer to an ubi_btNodePtr. When searching
* the tree, a duplicate node may be found. If
* duplicates are allowed, then the new node will
* be simply placed into the tree. If duplicates
* are not allowed, however, then one of two things
* may happen.
* 1) if overwritting *is not* allowed, this
* function will return FALSE (indicating that
* the new node could not be inserted), and
* *OldNode will point to the duplicate that is
* still in the tree.
* 2) if overwritting *is* allowed, then this
* function will swap **OldNode for *NewNode.
* In this case, *OldNode will point to the node
* that was removed (thus allowing you to free
* the node).
* ** If you are using overwrite mode, ALWAYS **
* ** check the return value of this parameter! **
* Note: You may pass NULL in this parameter, the
* function knows how to cope. If you do this,
* however, there will be no way to return a
* pointer to an old (ie. replaced) node (which is
* a problem if you are using overwrite mode).
*
* Output: a boolean value indicating success or failure. The function
* will return FALSE if the node could not be added to the tree.
* Such failure will only occur if duplicates are not allowed,
* nodes cannot be overwritten, AND a duplicate key was found
* within the tree.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode );
/* ------------------------------------------------------------------------ **
* This function removes the indicated node from the tree.
*
* Input: RootPtr - A pointer to the header of the tree that contains
* the node to be removed.
* DeadNode - A pointer to the node that will be removed.
*
* Output: This function returns a pointer to the node that was removed
* from the tree (ie. the same as DeadNode).
*
* Note: The node MUST be in the tree indicated by RootPtr. If not,
* strange and evil things will happen to your trees.
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe,
ubi_trCompOps CompOp );
/* ------------------------------------------------------------------------ **
* The purpose of ubi_btLocate() is to find a node or set of nodes given
* a target value and a "comparison operator". The Locate() function is
* more flexible and (in the case of trees that may contain dupicate keys)
* more precise than the ubi_btFind() function. The latter is faster,
* but it only searches for exact matches and, if the tree contains
* duplicates, Find() may return a pointer to any one of the duplicate-
* keyed records.
*
* Input:
* RootPtr - A pointer to the header of the tree to be searched.
* FindMe - An ubi_btItemPtr that indicates the key for which to
* search.
* CompOp - One of the following:
* CompOp Return a pointer to the node with
* ------ ---------------------------------
* ubi_trLT - the last key value that is less
* than FindMe.
* ubi_trLE - the first key matching FindMe, or
* the last key that is less than
* FindMe.
* ubi_trEQ - the first key matching FindMe.
* ubi_trGE - the first key matching FindMe, or the
* first key greater than FindMe.
* ubi_trGT - the first key greater than FindMe.
* Output:
* A pointer to the node matching the criteria listed above under
* CompOp, or NULL if no node matched the criteria.
*
* Notes:
* In the case of trees with duplicate keys, Locate() will behave as
* follows:
*
* Find: 3 Find: 3
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
* ^ ^ ^ ^ ^
* LT EQ GT LE GE
*
* That is, when returning a pointer to a node with a key that is LESS
* THAN the target key (FindMe), Locate() will return a pointer to the
* LAST matching node.
* When returning a pointer to a node with a key that is GREATER
* THAN the target key (FindMe), Locate() will return a pointer to the
* FIRST matching node.
*
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
* ------------------------------------------------------------------------ **
*/
ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
ubi_btItemPtr FindMe );
/* ------------------------------------------------------------------------ **
* This function performs a non-recursive search of a tree for any node
* matching a specific key.
*
* Input:
* RootPtr - a pointer to the header of the tree to be searched.
* FindMe - a pointer to the key value for which to search.
*
* Output:
* A pointer to a node with a key that matches the key indicated by
* FindMe, or NULL if no such node was found.
*
* Note: In a tree that allows duplicates, the pointer returned *might
* not* point to the (sequentially) first occurance of the
* desired key. In such a tree, it may be more useful to use
* ubi_sptLocate().
* ------------------------------------------------------------------------ **
*/
void ubi_sptSplay( ubi_btRootPtr RootPtr,
ubi_btNodePtr SplayMe );
/* ------------------------------------------------------------------------ **
* This function allows you to splay the tree at a given node, thus moving
* the node to the top of the tree.
*
* Input:
* RootPtr - a pointer to the header of the tree to be splayed.
* SplayMe - a pointer to a node within the tree. This will become
* the new root node.
* Output: None.
*
* Notes: This is an uncharacteristic function for this group of modules
* in that it provides access to the internal balancing routines,
* which would normally be hidden.
* Splaying the tree will not damage it (assuming that I've done
* *my* job), but there is overhead involved. I don't recommend
* that you use this function unless you understand the underlying
* Splay Tree principles involved.
* ------------------------------------------------------------------------ **
*/
int ubi_sptModuleID( int size, char *list[] );
/* ------------------------------------------------------------------------ **
* Returns a set of strings that identify the module.
*
* Input: size - The number of elements in the array <list>.
* list - An array of pointers of type (char *). This array
* should, initially, be empty. This function will fill
* in the array with pointers to strings.
* Output: The number of elements of <list> that were used. If this value
* is less than <size>, the values of the remaining elements are
* not guaranteed.
*
* Notes: Please keep in mind that the pointers returned indicate strings
* stored in static memory. Don't free() them, don't write over
* them, etc. Just read them.
* ------------------------------------------------------------------------ **
*/
/* -------------------------------------------------------------------------- **
* Masquarade...
*
* This set of defines allows you to write programs that will use any of the
* implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
* Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
* including the appropriate module header.
*/
#undef ubi_trInsert
#undef ubi_trRemove
#undef ubi_trLocate
#undef ubi_trFind
#undef ubi_trModuleID
#define ubi_trInsert( Rp, Nn, Ip, On ) \
ubi_sptInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
(ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
#define ubi_trRemove( Rp, Dn ) \
ubi_sptRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
#define ubi_trLocate( Rp, Ip, Op ) \
ubi_sptLocate( (ubi_btRootPtr)(Rp), \
(ubi_btItemPtr)(Ip), \
(ubi_trCompOps)(Op) )
#define ubi_trFind( Rp, Ip ) \
ubi_sptFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
#define ubi_trSplay( Rp, Sm ) \
ubi_sptSplay( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Sm) )
#define ubi_trModuleID( s, l ) ubi_sptModuleID( s, l )
/* ================================ The End ================================= */
#endif /* UBI_SPLAYTREE_H */

172
lib/ubi_dLinkList.c Normal file
View File

@ -0,0 +1,172 @@
/* ========================================================================== **
* ubi_dLinkList.c
*
* Copyright (C) 1997, 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
* This module implements simple doubly-linked lists.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_dLinkList.c,v
* Revision 0.11 1999/06/19 16:58:06 crh
* Renamed the ubi_slRemove() function in ubi_sLinkList to
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
* match the functionality of the ubi_dlRemove() function in
* ubi_dLinkList. The new name is more 'correct'.
*
* Revision 0.10 1998/07/24 07:30:20 crh
* Added the ubi_dlNewList() macro.
*
* Revision 0.9 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 0.8 1998/06/03 18:06:03 crh
* Further fiddling with sys_include.h, which has been moved from the .c file
* to the .h file.
*
* Revision 0.7 1998/06/02 01:38:47 crh
* Changed include file name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.6 1998/05/20 04:38:05 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.5 1998/03/10 02:55:00 crh
* Simplified the code and added macros for stack & queue manipulations.
*
* Revision 0.4 1998/01/03 01:53:56 crh
* Added ubi_dlCount() macro.
*
* Revision 0.3 1997/10/15 03:05:39 crh
* Added some handy type casting to the macros. Added AddHere and RemThis
* macros.
*
* Revision 0.2 1997/10/08 03:07:21 crh
* Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
* macro, which was passing the wrong value for <After> to Insert().
*
* Revision 0.1 1997/10/07 04:34:07 crh
* Initial Revision.
*
* -------------------------------------------------------------------------- **
* This module is similar to the ubi_sLinkList module, but it is neither a
* descendant type nor an easy drop-in replacement for the latter. One key
* difference is that the ubi_dlRemove() function removes the indicated node,
* while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
* *following* the indicated node.
*
* ========================================================================== **
*/
#include "libs.h"
#include "ubi_dLinkList.h" /* Header for *this* module. */
/* ========================================================================== **
* Functions...
*/
ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr )
/* ------------------------------------------------------------------------ **
* Initialize a doubly-linked list header.
*
* Input: ListPtr - A pointer to the list structure that is to be
* initialized for use.
*
* Output: A pointer to the initialized list header (i.e., same as
* <ListPtr>).
*
* ------------------------------------------------------------------------ **
*/
{
ListPtr->Head = NULL;
ListPtr->Tail = NULL;
ListPtr->count = 0;
return( ListPtr );
} /* ubi_dlInitList */
ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
ubi_dlNodePtr New,
ubi_dlNodePtr After )
/* ------------------------------------------------------------------------ **
* Insert a new node into the list.
*
* Input: ListPtr - A pointer to the list into which the node is to
* be inserted.
* New - Pointer to the new node.
* After - NULL, or a pointer to a node that is already in the
* list.
* If NULL, then <New> will be added at the head of the
* list, else it will be added following <After>.
*
* Output: A pointer to the node that was inserted into the list (i.e.,
* the same as <New>).
*
* ------------------------------------------------------------------------ **
*/
{
ubi_dlNodePtr PredNode = After ? After : (ubi_dlNodePtr)ListPtr;
New->Next = PredNode->Next;
New->Prev = After;
PredNode->Next = New;
if( New->Next )
New->Next->Prev = New;
else
ListPtr->Tail = New;
(ListPtr->count)++;
return( New );
} /* ubi_dlInsert */
ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old )
/* ------------------------------------------------------------------------ **
* Remove a node from the list.
*
* Input: ListPtr - A pointer to the list from which <Old> is to be
* removed.
* Old - A pointer to the node that is to be removed from the
* list.
*
* Output: A pointer to the node that was removed (i.e., <Old>).
*
* ------------------------------------------------------------------------ **
*/
{
if( Old )
{
if( Old->Next )
Old->Next->Prev = Old->Prev;
else
ListPtr->Tail = Old->Prev;
if( Old->Prev )
Old->Prev->Next = Old->Next;
else
ListPtr->Head = Old->Next;
(ListPtr->count)--;
}
return( Old );
} /* ubi_dlRemove */
/* ================================ The End ================================= */

241
lib/ubi_dLinkList.h Normal file
View File

@ -0,0 +1,241 @@
#ifndef UBI_DLINKLIST_H
#define UBI_DLINKLIST_H
/* ========================================================================== **
* ubi_dLinkList.h
*
* Copyright (C) 1997, 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
* This module implements simple doubly-linked lists.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_dLinkList.h,v
* Revision 0.11 1999/06/19 16:58:06 crh
* Renamed the ubi_slRemove() function in ubi_sLinkList to
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
* match the functionality of the ubi_dlRemove() function in
* ubi_dLinkList. The new name is more 'correct'.
*
* Revision 0.10 1998/07/24 07:30:20 crh
* Added the ubi_dlNewList() macro.
*
* Revision 0.9 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 0.8 1998/06/03 18:06:03 crh
* Further fiddling with sys_include.h, which has been moved from the .c file
* to the .h file.
*
* Revision 0.7 1998/06/02 01:38:47 crh
* Changed include file name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.6 1998/05/20 04:38:05 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.5 1998/03/10 02:54:04 crh
* Simplified the code and added macros for stack & queue manipulations.
*
* Revision 0.4 1998/01/03 01:53:44 crh
* Added ubi_dlCount() macro.
*
* Revision 0.3 1997/10/15 03:04:31 crh
* Added some handy type casting to the macros. Added AddHere and RemThis
* macros.
*
* Revision 0.2 1997/10/08 03:08:16 crh
* Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
* macro, which was passing the wrong value for <After> to Insert().
*
* Revision 0.1 1997/10/07 04:34:38 crh
* Initial Revision.
*
* -------------------------------------------------------------------------- **
* This module is similar to the ubi_sLinkList module, but it is neither a
* descendant type nor an easy drop-in replacement for the latter. One key
* difference is that the ubi_dlRemove() function removes the indicated node,
* while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
* *following* the indicated node.
*
* ========================================================================== **
*/
/* ========================================================================== **
* Typedefs...
*
* ubi_dlNode - This is the basic node structure.
* ubi_dlNodePtr - Pointer to a node.
* ubi_dlList - This is the list header structure.
* ubi_dlListPtr - Pointer to a List (i.e., a list header structure).
*
*/
typedef struct ubi_dlListNode
{
struct ubi_dlListNode *Next;
struct ubi_dlListNode *Prev;
} ubi_dlNode;
typedef ubi_dlNode *ubi_dlNodePtr;
typedef struct
{
ubi_dlNodePtr Head;
ubi_dlNodePtr Tail;
unsigned long count;
} ubi_dlList;
typedef ubi_dlList *ubi_dlListPtr;
/* ========================================================================== **
* Macros...
*
* ubi_dlNewList - Macro used to declare and initialize a new list in one
* swell foop. It is used when defining a variable of
* type ubi_dlList. The definition
* static ubi_dlNewList( gerbil );
* is translated to
* static ubi_dlList gerbil[1] = {{ NULL, NULL, 0 }};
*
* ubi_dlCount - Return the number of entries currently in the list.
*
* ubi_dlAddHead - Add a new node at the head of the list.
* ubi_dlAddNext - Add a node following the given node.
* ubi_dlAddTail - Add a new node at the tail of the list.
* Note: AddTail evaluates the L parameter twice.
*
* ubi_dlRemHead - Remove the node at the head of the list, if any.
* Note: RemHead evaluates the L parameter twice.
* ubi_dlRemThis - Remove the indicated node.
* ubi_dlRemTail - Remove the node at the tail of the list, if any.
* Note: RemTail evaluates the L parameter twice.
*
* ubi_dlFirst - Return a pointer to the first node in the list, if any.
* ubi_dlLast - Return a pointer to the last node in the list, if any.
* ubi_dlNext - Given a node, return a pointer to the next node.
* ubi_dlPrev - Given a node, return a pointer to the previous node.
*
* ubi_dlPush - Add a node at the head of the list (synonym of AddHead).
* ubi_dlPop - Remove a node at the head of the list (synonym of RemHead).
* ubi_dlEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
* ubi_dlDequeue - Remove a node at the head of the list (synonym of RemHead).
*
* Note that all of these provide type casting of the parameters. The
* Add and Rem macros are nothing more than nice front-ends to the
* Insert and Remove operations.
*
* Also note that the First, Next and Last macros do no parameter checking!
*
*/
#define ubi_dlNewList( L ) ubi_dlList (L)[1] = {{ NULL, NULL, 0 }}
#define ubi_dlCount( L ) (((ubi_dlListPtr)(L))->count)
#define ubi_dlAddHead( L, N ) \
ubi_dlInsert( (ubi_dlListPtr)(L), (ubi_dlNodePtr)(N), NULL )
#define ubi_dlAddNext( L, N, A ) \
ubi_dlInsert( (ubi_dlListPtr)(L), \
(ubi_dlNodePtr)(N), \
(ubi_dlNodePtr)(A) )
#define ubi_dlAddTail( L, N ) \
ubi_dlInsert( (ubi_dlListPtr)(L), \
(ubi_dlNodePtr)(N), \
(((ubi_dlListPtr)(L))->Tail) )
#define ubi_dlRemHead( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
(((ubi_dlListPtr)(L))->Head) )
#define ubi_dlRemThis( L, N ) ubi_dlRemove( (ubi_dlListPtr)(L), \
(ubi_dlNodePtr)(N) )
#define ubi_dlRemTail( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
(((ubi_dlListPtr)(L))->Tail) )
#define ubi_dlFirst( L ) (((ubi_dlListPtr)(L))->Head)
#define ubi_dlLast( L ) (((ubi_dlListPtr)(L))->Tail)
#define ubi_dlNext( N ) (((ubi_dlNodePtr)(N))->Next)
#define ubi_dlPrev( N ) (((ubi_dlNodePtr)(N))->Prev)
#define ubi_dlPush ubi_dlAddHead
#define ubi_dlPop ubi_dlRemHead
#define ubi_dlEnqueue ubi_dlAddTail
#define ubi_dlDequeue ubi_dlRemHead
/* ========================================================================== **
* Function prototypes...
*/
ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr );
/* ------------------------------------------------------------------------ **
* Initialize a doubly-linked list header.
*
* Input: ListPtr - A pointer to the list structure that is to be
* initialized for use.
*
* Output: A pointer to the initialized list header (i.e., same as
* <ListPtr>).
*
* ------------------------------------------------------------------------ **
*/
ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
ubi_dlNodePtr New,
ubi_dlNodePtr After );
/* ------------------------------------------------------------------------ **
* Insert a new node into the list.
*
* Input: ListPtr - A pointer to the list into which the node is to
* be inserted.
* New - Pointer to the new node.
* After - NULL, or a pointer to a node that is already in the
* list.
* If NULL, then <New> will be added at the head of the
* list, else it will be added following <After>.
*
* Output: A pointer to the node that was inserted into the list (i.e.,
* the same as <New>).
*
* ------------------------------------------------------------------------ **
*/
ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old );
/* ------------------------------------------------------------------------ **
* Remove a node from the list.
*
* Input: ListPtr - A pointer to the list from which <Old> is to be
* removed.
* Old - A pointer to the node that is to be removed from the
* list.
*
* Output: A pointer to the node that was removed (i.e., <Old>).
*
* ------------------------------------------------------------------------ **
*/
/* ================================ The End ================================= */
#endif /* UBI_DLINKLIST_H */

188
lib/ubi_sLinkList.c Normal file
View File

@ -0,0 +1,188 @@
/* ========================================================================== **
* ubi_sLinkList.c
*
* Copyright (C) 1997, 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
* This module implements a simple singly-linked list.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_sLinkList.c,v
* Revision 0.10 1999/06/19 16:58:06 crh
* Renamed the ubi_slRemove() function in ubi_sLinkList to
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
* match the functionality of the ubi_dlRemove() function in
* ubi_dLinkList. The new name is more 'correct'.
*
* Revision 0.9 1998/07/24 07:30:20 crh
* Added the ubi_slNewList() macro.
*
* Revision 0.8 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 0.7 1998/06/03 18:06:03 crh
* Further fiddling with sys_include.h, which has been moved from the .c file
* to the .h file.
*
* Revision 0.6 1998/06/02 01:38:47 crh
* Changed include file name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.5 1998/05/20 04:38:05 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.4 1998/03/10 02:23:20 crh
* Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
* the functions and macros. Not a complete rewrite but close to it.
*
* Revision 0.3 1998/01/03 01:59:52 crh
* Added ubi_slCount() macro.
*
* Revision 0.2 1997/10/21 03:35:18 crh
* Added parameter <After> in function Insert(). Made necessary changes
* to macro AddHead() and added macro AddHere().
*
* Revision 0.1 1997/10/16 02:53:45 crh
* Initial Revision.
*
* -------------------------------------------------------------------------- **
* This module implements a singly-linked list which may also be used as a
* queue or a stack. For a queue, entries are added at the tail and removed
* from the head of the list. For a stack, the entries are entered and
* removed from the head of the list. A traversal of the list will always
* start at the head of the list and proceed toward the tail. This is all
* mind-numbingly simple, but I'm surprised by the number of programs out
* there which re-implement this a dozen or so times.
*
* Note: When the list header is initialized, the Tail pointer is set to
* point to the Head pointer. This simplifies things a great deal,
* except that you can't initialize a stack or queue by simply
* zeroing it out. One sure way to initialize the header is to call
* ubi_slInit(). Another option would be something like this:
*
* ubi_slNewList( MyList );
*
* Which translates to:
*
* ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
*
* See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
* for more info.
*
* + Also, note that this module is similar to the ubi_dLinkList
* module. There are three key differences:
* - This is a singly-linked list, the other is a doubly-linked
* list.
* - In this module, if the list is empty, the tail pointer will
* point back to the head of the list as described above. This
* is not done in ubi_dLinkList.
* - The ubi_slRemoveNext() function, by necessity, removes the
* 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
* removes the 'current' node.
*
* ========================================================================== **
*/
#include "libs.h"
#include "ubi_sLinkList.h" /* Header for *this* module. */
/* ========================================================================== **
* Functions...
*/
ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr )
/* ------------------------------------------------------------------------ **
* Initialize a singly-linked list header.
*
* Input: ListPtr - A pointer to the list structure that is to be
* initialized for use.
*
* Output: A pointer to the initialized list header (i.e., same as
* <ListPtr>).
*
* ------------------------------------------------------------------------ **
*/
{
ListPtr->Head = NULL;
ListPtr->Tail = (ubi_slNodePtr)ListPtr;
ListPtr->count = 0;
return( ListPtr );
} /* ubi_slInitList */
ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
ubi_slNodePtr New,
ubi_slNodePtr After )
/* ------------------------------------------------------------------------ **
* Add a node to the list.
*
* Input: ListPtr - A pointer to the list into which the node is to
* be inserted.
* New - Pointer to the node that is to be added to the list.
* After - Pointer to a list in a node after which the new node
* will be inserted. If NULL, then the new node will
* be added at the head of the list.
*
* Output: A pointer to the node that was inserted into the list (i.e.,
* the same as <New>).
*
* ------------------------------------------------------------------------ **
*/
{
After = After ? After : (ubi_slNodePtr)ListPtr;
New->Next = After->Next;
After->Next = New;
if( !(New->Next) )
ListPtr->Tail = New;
(ListPtr->count)++;
return( New );
} /* ubi_slInsert */
ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe )
/* ------------------------------------------------------------------------ **
* Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
* the head of the list.
*
* Input: ListPtr - A pointer to the list from which the node is to be
* removed.
* AfterMe - Pointer to the node preceeding the node to be
* removed.
*
* Output: A pointer to the node that was removed, or NULL if the list is
* empty.
*
* ------------------------------------------------------------------------ **
*/
{
ubi_slNodePtr DelNode;
AfterMe = AfterMe ? AfterMe : (ubi_slNodePtr)ListPtr;
DelNode = AfterMe->Next;
if( DelNode )
{
if( !(DelNode->Next) )
ListPtr->Tail = AfterMe;
AfterMe->Next = DelNode->Next;
(ListPtr->count)--;
}
return( DelNode );
} /* ubi_slRemoveNext */
/* ================================ The End ================================= */

253
lib/ubi_sLinkList.h Normal file
View File

@ -0,0 +1,253 @@
#ifndef UBI_SLINKLIST_H
#define UBI_SLINKLIST_H
/* ========================================================================== **
* ubi_sLinkList.h
*
* Copyright (C) 1997, 1998 by Christopher R. Hertel
*
* Email: crh@ubiqx.mn.org
* -------------------------------------------------------------------------- **
* This module implements a simple singly-linked list.
* -------------------------------------------------------------------------- **
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* -------------------------------------------------------------------------- **
*
* Log: ubi_sLinkList.h,v
* Revision 0.10 1999/06/19 16:58:06 crh
* Renamed the ubi_slRemove() function in ubi_sLinkList to
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
* match the functionality of the ubi_dlRemove() function in
* ubi_dLinkList. The new name is more 'correct'.
*
* Revision 0.9 1998/07/24 07:30:20 crh
* Added the ubi_slNewList() macro.
*
* Revision 0.8 1998/06/04 21:29:27 crh
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
* This is more "standard", and is what people expect. Weird, eh?
*
* Revision 0.7 1998/06/03 18:06:03 crh
* Further fiddling with sys_include.h, which has been moved from the .c file
* to the .h file.
*
* Revision 0.6 1998/06/02 01:38:47 crh
* Changed include file name from ubi_null.h to sys_include.h to make it
* more generic.
*
* Revision 0.5 1998/05/20 04:38:05 crh
* The C file now includes ubi_null.h. See ubi_null.h for more info.
*
* Revision 0.4 1998/03/10 02:22:39 crh
* Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
* the functions and macros. Not a complete rewrite but close to it.
*
* Revision 0.3 1998/01/03 02:00:02 crh
* Added ubi_slCount() macro.
*
* Revision 0.2 1997/10/21 03:36:14 crh
* Added parameter <After> in function Insert(). Made necessary changes
* to macro AddHead() and added macro AddHere().
*
* Revision 0.1 1997/10/16 02:54:08 crh
* Initial Revision.
*
* -------------------------------------------------------------------------- **
* This module implements a singly-linked list which may also be used as a
* queue or a stack. For a queue, entries are added at the tail and removed
* from the head of the list. For a stack, the entries are entered and
* removed from the head of the list. A traversal of the list will always
* start at the head of the list and proceed toward the tail. This is all
* mind-numbingly simple, but I'm surprised by the number of programs out
* there which re-implement this a dozen or so times.
*
* Note: When the list header is initialized, the Tail pointer is set to
* point to the Head pointer. This simplifies things a great deal,
* except that you can't initialize a stack or queue by simply
* zeroing it out. One sure way to initialize the header is to call
* ubi_slInit(). Another option would be something like this:
*
* ubi_slNewList( MyList );
*
* Which translates to:
*
* ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
*
* See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
* for more info.
*
* + Also, note that this module is similar to the ubi_dLinkList
* module. There are three key differences:
* - This is a singly-linked list, the other is a doubly-linked
* list.
* - In this module, if the list is empty, the tail pointer will
* point back to the head of the list as described above. This
* is not done in ubi_dLinkList.
* - The ubi_slRemoveNext() function, by necessity, removes the
* 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
* removes the 'current' node.
*
* ========================================================================== **
*/
/* ========================================================================== **
* Typedefs...
*
* ubi_slNode - This is the basic node structure.
* ubi_slNodePtr - Pointer to a node.
* ubi_slList - This is the list header structure.
* ubi_slListPtr - Pointer to a List (i.e., a list header structure).
*
*/
typedef struct ubi_slListNode
{
struct ubi_slListNode *Next;
} ubi_slNode;
typedef ubi_slNode *ubi_slNodePtr;
typedef struct
{
ubi_slNodePtr Head;
ubi_slNodePtr Tail;
unsigned long count;
} ubi_slList;
typedef ubi_slList *ubi_slListPtr;
/* ========================================================================== **
* Macros...
*
* ubi_slNewList - Macro used to declare and initialize a list header in
* one step.
*
* ubi_slCount - Returns the current number of entries in the list.
*
* ubi_slAddHead - Add a new node at the head of the list.
* ubi_slAddNext - Add a new node following the indicated node.
* ubi_slAddTail - Add a new node to the tail of the list.
* Note: AddTail evaluates the L parameter twice.
*
* ubi_slRemHead - Remove the node at the head of the list, if any.
* ubi_slRemNext - Remove the node following the given node.
*
* ubi_slFirst - Return a pointer to the first node in the list, if any.
* ubi_slNext - Given a node, return a pointer to the next node.
* ubi_slLast - Return a pointer to the last node in the list, if any.
*
* ubi_slPush - Add a node at the head of the list (synonym of AddHead).
* ubi_slPop - Remove a node at the head of the list (synonym of RemHead).
* ubi_slEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
* ubi_slDequeue - Remove a node at the head of the list (synonym of RemHead).
*
* Note that all of these provide type casting of the parameters. The
* Add and Rem macros are nothing more than nice front-ends to the
* Insert and Remove functions.
*
* Also note that the First, Next and Last macros do no parameter checking!
*
*/
#define ubi_slNewList( L ) ubi_slList (L)[1] = {{ NULL, (ubi_slNodePtr)(L), 0 }}
#define ubi_slCount( L ) (((ubi_slListPtr)(L))->count)
#define ubi_slAddHead( L, N ) \
ubi_slInsert( (ubi_slListPtr)(L), (ubi_slNodePtr)(N), NULL )
#define ubi_slAddNext( L, N, A ) \
ubi_slInsert( (ubi_slListPtr)(L), \
(ubi_slNodePtr)(N), \
(ubi_slNodePtr)(A) )
#define ubi_slAddTail( L, N ) \
ubi_slInsert( (ubi_slListPtr)(L), \
(ubi_slNodePtr)(N), \
((ubi_slListPtr)(L))->Tail )
#define ubi_slRemHead( L ) ubi_slRemoveNext( (ubi_slListPtr)(L), NULL )
#define ubi_slRemNext( L, N ) \
ubi_slRemoveNext( (ubi_slListPtr)(L), (ubi_slNodePtr)(N) )
#define ubi_slFirst( L ) (((ubi_slListPtr)(L))->Head)
#define ubi_slNext( N ) (((ubi_slNodePtr)(N))->Next)
#define ubi_slLast( L ) (((ubi_slListPtr)(L))->Tail)
#define ubi_slPush ubi_slAddHead
#define ubi_slPop ubi_slRemHead
#define ubi_slEnqueue ubi_slAddTail
#define ubi_slDequeue ubi_slRemHead
/* ========================================================================== **
* Function prototypes...
*/
ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr );
/* ------------------------------------------------------------------------ **
* Initialize a singly-linked list header.
*
* Input: ListPtr - A pointer to the list structure that is to be
* initialized for use.
*
* Output: A pointer to the initialized list header (i.e., same as
* <ListPtr>).
*
* ------------------------------------------------------------------------ **
*/
ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
ubi_slNodePtr New,
ubi_slNodePtr After );
/* ------------------------------------------------------------------------ **
* Add a node to the list.
*
* Input: ListPtr - A pointer to the list into which the node is to
* be inserted.
* New - Pointer to the node that is to be added to the list.
* After - Pointer to a list in a node after which the new node
* will be inserted. If NULL, then the new node will
* be added at the head of the list.
*
* Output: A pointer to the node that was inserted into the list (i.e.,
* the same as <New>).
*
* ------------------------------------------------------------------------ **
*/
ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe );
/* ------------------------------------------------------------------------ **
* Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
* the head of the list.
*
* Input: ListPtr - A pointer to the list from which the node is to be
* removed.
* AfterMe - Pointer to the node preceeding the node to be
* removed.
*
* Output: A pointer to the node that was removed, or NULL if the list is
* empty.
*
* ------------------------------------------------------------------------ **
*/
/* ================================ The End ================================= */
#endif /* UBI_SLINKLIST_H */