more updates to mangle code
This commit is contained in:
parent
614bc71f09
commit
406abe81e6
@ -4331,7 +4331,8 @@ v0.33.19 26-Oct-2001
|
|||||||
that one gives a complete dump and is for developer use.
|
that one gives a complete dump and is for developer use.
|
||||||
The "mbfile index" function now also writes files.bbs files,
|
The "mbfile index" function now also writes files.bbs files,
|
||||||
the index.html files for http download and 00index files in
|
the index.html files for http download and 00index files in
|
||||||
all available areas.
|
all available areas. The files.bbs files have download
|
||||||
|
counters included.
|
||||||
|
|
||||||
mball:
|
mball:
|
||||||
The index function is now obsolete, this is added to mbfile.
|
The index function is now obsolete, this is added to mbfile.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<HEAD>
|
<HEAD>
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=ISO 8859-1">
|
<META http-equiv="Content-Type" content="text/html; charset=ISO 8859-1">
|
||||||
<META http-equiv="Content-Style-Type" content="text/css">
|
<META http-equiv="Content-Style-Type" content="text/css">
|
||||||
<META name="author" lang="en" "content="Michiel Broek">
|
<META name="author" lang="en" content="Michiel Broek">
|
||||||
<META name="copyright" lang="en" content="Copyright Michiel Broek">
|
<META name="copyright" lang="en" content="Copyright Michiel Broek">
|
||||||
<META name="description" lang="en" content="MBSE BBS Manual">
|
<META name="description" lang="en" content="MBSE BBS Manual">
|
||||||
<META name="keywords" lang="en" content="MBSE BBS, MBSE, BBS, manual, fido, fidonet, gateway, tosser, mail, tic, mailer">
|
<META name="keywords" lang="en" content="MBSE BBS, MBSE, BBS, manual, fido, fidonet, gateway, tosser, mail, tic, mailer">
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</HEAD>
|
</HEAD>
|
||||||
<BODY>
|
<BODY>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<h5>Last update 30-Jan-2001</h5>
|
<h5>Last update 25-Nov-2001</h5>
|
||||||
<P> <P>
|
<P> <P>
|
||||||
|
|
||||||
<H1>mball - Allfiles listing generator</H1>
|
<H1>mball - Allfiles listing generator</H1>
|
||||||
@ -32,15 +32,6 @@ resulting files are created in the current directory. After the creation of
|
|||||||
these files you can hatch them into your bbs with the programs <strong>
|
these files you can hatch them into your bbs with the programs <strong>
|
||||||
mbfido tic</strong> when you properly setup a .tic file area for this purpose
|
mbfido tic</strong> when you properly setup a .tic file area for this purpose
|
||||||
and create records for the hatch manager.
|
and create records for the hatch manager.
|
||||||
<P>
|
|
||||||
It can also create <strong>00index</strong> files in each download directory
|
|
||||||
for FTP users. Because this file starts with double zero it is most likely the
|
|
||||||
file at the top in each directory. At the same time HTTP pages are created in
|
|
||||||
the download directories of your filebase. These are named index.html,
|
|
||||||
index1.html and so on, there are as many as needed. The main index is created in the root
|
|
||||||
of your filebase. If you use the default setup then a user browsing at your bbs
|
|
||||||
can type <strong>http://yoursite.org/files/index.html</strong> to see the list
|
|
||||||
of fileareas.
|
|
||||||
<P> <P>
|
<P> <P>
|
||||||
|
|
||||||
<H3>Environment.</H3>
|
<H3>Environment.</H3>
|
||||||
@ -53,7 +44,6 @@ must be present in the ~/etc directory.
|
|||||||
|
|
||||||
<H3>Commands.</H3>
|
<H3>Commands.</H3>
|
||||||
<P>
|
<P>
|
||||||
<code><strong>mball index</strong></code> - Create 00index and HTTP files in all download directories.<br>
|
|
||||||
<code><strong>mball list</strong> </code> - Create allfiles.txt and newfiles.txt files.
|
<code><strong>mball list</strong> </code> - Create allfiles.txt and newfiles.txt files.
|
||||||
<p> <P>
|
<p> <P>
|
||||||
|
|
||||||
@ -65,7 +55,7 @@ must be present in the ~/etc directory.
|
|||||||
|
|
||||||
<H3>Setup.</H3>
|
<H3>Setup.</H3>
|
||||||
<P>
|
<P>
|
||||||
In <strong>mbsetup</strong> menu 1.15 you need to set the public FTP base,
|
In <strong>mbsetup</strong> menu 1.16 you need to set the public FTP base,
|
||||||
the days to include in newfiles listings and the maximum security level.
|
the days to include in newfiles listings and the maximum security level.
|
||||||
<P>
|
<P>
|
||||||
|
|
||||||
|
@ -81,7 +81,11 @@ virussed before the are added the the bbs.
|
|||||||
|
|
||||||
<code><strong>mbfile</strong> index</code>
|
<code><strong>mbfile</strong> index</code>
|
||||||
Create fast filerequest index for the <strong>mbcico</strong> filerequest
|
Create fast filerequest index for the <strong>mbcico</strong> filerequest
|
||||||
processor.
|
processor. In each directory with the downloadable files is also a
|
||||||
|
<strong>files.bbs</strong> file written is msdos cr/lf format. This includes a
|
||||||
|
download counter.
|
||||||
|
Also, if defined, in each available download area for ftp/http, index files are
|
||||||
|
created, starting at the ftp pub directory.
|
||||||
<P>
|
<P>
|
||||||
|
|
||||||
<code><strong>mbfile</strong> kill</code>
|
<code><strong>mbfile</strong> kill</code>
|
||||||
@ -118,6 +122,12 @@ that the added file(s) will be announced. This can be usefull if you add lots of
|
|||||||
files that you don't want to announce these as new files.
|
files that you don't want to announce these as new files.
|
||||||
<P>
|
<P>
|
||||||
|
|
||||||
|
<H3>Setup.</H3>
|
||||||
|
<P>
|
||||||
|
In <strong>mbsetup</strong> menu 1.16 you need to set the public FTP base
|
||||||
|
and the maximum security level.
|
||||||
|
<P>
|
||||||
|
|
||||||
<A HREF="index.htm"><IMG SRC="../images/larrow.gif" ALT="Index" Border="0" width="40" height="30"> Back to index</A>
|
<A HREF="index.htm"><IMG SRC="../images/larrow.gif" ALT="Index" Border="0" width="40" height="30"> Back to index</A>
|
||||||
<A HREF="../index.htm"><IMG SRC="../images/b_arrow.gif" ALT="Main" Border="0" width="33" height="35"> Back to Main index</A>
|
<A HREF="../index.htm"><IMG SRC="../images/b_arrow.gif" ALT="Main" Border="0" width="33" height="35"> Back to Main index</A>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
481
lib/COPYING.LIB
481
lib/COPYING.LIB
@ -1,481 +0,0 @@
|
|||||||
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!
|
|
10
lib/Makefile
10
lib/Makefile
@ -30,15 +30,11 @@ MBINET_HDRS = mbinet.h
|
|||||||
MEMWATCH_SRCS = memwatch.c
|
MEMWATCH_SRCS = memwatch.c
|
||||||
MEMWATCH_OBJS = memwatch.o
|
MEMWATCH_OBJS = memwatch.o
|
||||||
MEMWATCH_HDRS = memwatch.h
|
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
|
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}
|
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}
|
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}
|
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
|
TARGET = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -75,10 +71,6 @@ libmemwatch.a: ${MEMWATCH_OBJS}
|
|||||||
ar r $@ $?
|
ar r $@ $?
|
||||||
${RANLIB} $@
|
${RANLIB} $@
|
||||||
|
|
||||||
libubi.a: ${UBI_OBJS}
|
|
||||||
ar r $@ $?
|
|
||||||
${RANLIB} $@
|
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
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
309
lib/debugparse.c
@ -1,309 +0,0 @@
|
|||||||
/* ========================================================================== **
|
|
||||||
* 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
127
lib/debugparse.h
@ -1,127 +0,0 @@
|
|||||||
#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 */
|
|
611
lib/mangle.c
611
lib/mangle.c
@ -34,15 +34,156 @@
|
|||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
#include "clcomm.h"
|
#include "clcomm.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ubi_sLinkList.h"
|
|
||||||
#include "ubi_dLinkList.h"
|
|
||||||
#include "ubi_Cache.h"
|
/*
|
||||||
|
* Prototype functions
|
||||||
|
*/
|
||||||
|
int strequal(const char *, const char *);
|
||||||
|
int strhasupper(const char *);
|
||||||
|
int strhaslower(const char *);
|
||||||
|
int strisnormal(char *);
|
||||||
|
int str_checksum(const char *);
|
||||||
|
char *safe_strcpy(char *, const char *, size_t);
|
||||||
|
static void init_chartest(void);
|
||||||
|
static int is_reserved_msdos(char *);
|
||||||
|
static int is_illegal_name(char *);
|
||||||
|
int is_mangled(char *);
|
||||||
|
int is_8_3( char *, int);
|
||||||
|
static char *map_filename(char *, char *, int);
|
||||||
|
static void do_fwd_mangled_map(char *, char *);
|
||||||
|
void mangle_name_83( char *);
|
||||||
|
int name_map_mangle(char *, int, int, int);
|
||||||
|
|
||||||
|
|
||||||
|
#define pstrcpy(d,s) safe_strcpy((d),(s),sizeof(pstring)-1)
|
||||||
|
#define pstrcat(d,s) safe_strcat((d),(s),sizeof(pstring)-1)
|
||||||
|
#define PTR_DIFF(p1,p2) ((int)(((const char *)(p1)) - (const char *)(p2)))
|
||||||
|
|
||||||
|
#define isdoschar(c) (dos_char_map[(c&0xff)] != 0)
|
||||||
|
|
||||||
typedef enum {CASE_UPPER, CASE_LOWER} CASES;
|
typedef enum {CASE_UPPER, CASE_LOWER} CASES;
|
||||||
|
|
||||||
int case_default = CASE_UPPER; /* Are conforming 8.3 names all upper or lower? */
|
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. */
|
int case_mangle = TRUE; /* If true, all chars in 8.3 should be same case. */
|
||||||
|
|
||||||
|
#define PSTRING_LEN 1024
|
||||||
|
typedef char pstring[PSTRING_LEN];
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
compare 2 strings
|
||||||
|
********************************************************************/
|
||||||
|
int strequal(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
if (s1 == s2)
|
||||||
|
return(TRUE);
|
||||||
|
if (!s1 || !s2)
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
return(strcasecmp(s1,s2)==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
does a string have any uppercase chars in it?
|
||||||
|
****************************************************************************/
|
||||||
|
int strhasupper(const char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
if (isupper(*s))
|
||||||
|
return TRUE;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
does a string have any lowercase chars in it?
|
||||||
|
****************************************************************************/
|
||||||
|
int strhaslower(const char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
if (islower(*s))
|
||||||
|
return TRUE;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* check if a string is in "normal" case
|
||||||
|
* ********************************************************************/
|
||||||
|
int strisnormal(char *s)
|
||||||
|
{
|
||||||
|
if (case_default == CASE_UPPER)
|
||||||
|
return(!strhaslower(s));
|
||||||
|
|
||||||
|
return(!strhasupper(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Provide a checksum on a string
|
||||||
|
*
|
||||||
|
* Input: s - the null-terminated character string for which the checksum
|
||||||
|
* will be calculated.
|
||||||
|
*
|
||||||
|
* Output: The checksum value calculated for s.
|
||||||
|
*
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
int str_checksum(const char *s)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
int c;
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while(*s) {
|
||||||
|
c = *s;
|
||||||
|
res ^= (c << (i % 15)) ^ (c >> (15-(i%15)));
|
||||||
|
s++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} /* str_checksum */
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
safe string copy into a known length string. maxlength does not
|
||||||
|
include the terminating zero.
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
char *safe_strcpy(char *dest,const char *src, size_t maxlength)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!dest) {
|
||||||
|
Syslog('f', "ERROR: NULL dest in safe_strcpy");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src) {
|
||||||
|
*dest = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(src);
|
||||||
|
|
||||||
|
if (len > maxlength) {
|
||||||
|
Syslog('f', "ERROR: string overflow by %d in safe_strcpy [%.50s]", (int)(len-maxlength), src);
|
||||||
|
len = maxlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dest, src, len);
|
||||||
|
dest[len] = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- **
|
/* -------------------------------------------------------------------------- **
|
||||||
* Other stuff...
|
* Other stuff...
|
||||||
*
|
*
|
||||||
@ -112,9 +253,9 @@ static int ct_initialized = FALSE;
|
|||||||
#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_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 ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
|
||||||
static int mc_initialized = FALSE;
|
//static int mc_initialized = FALSE;
|
||||||
#define MANGLED_CACHE_MAX_ENTRIES 0
|
//#define MANGLED_CACHE_MAX_ENTRIES 0
|
||||||
#define MANGLED_CACHE_MAX_MEMORY 16384
|
//#define MANGLED_CACHE_MAX_MEMORY 16384
|
||||||
|
|
||||||
/* ************************************************************************** **
|
/* ************************************************************************** **
|
||||||
* Initialize the static character test array.
|
* Initialize the static character test array.
|
||||||
@ -170,40 +311,31 @@ static int is_reserved_msdos( char *fname )
|
|||||||
|
|
||||||
tu(upperFname);
|
tu(upperFname);
|
||||||
p = upperFname + 1;
|
p = upperFname + 1;
|
||||||
switch( upperFname[0] )
|
switch (upperFname[0]) {
|
||||||
{
|
|
||||||
case 'A':
|
case 'A':
|
||||||
if( 0 == strcmp( p, "UX" ) )
|
if( 0 == strcmp( p, "UX" ) )
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
if( (0 == strcmp( p, "LOCK$" ))
|
if ((0 == strcmp( p, "LOCK$" )) || (0 == strcmp( p, "ON" )) || (0 == strcmp( p, "OM1" ))
|
||||||
|| (0 == strcmp( p, "ON" ))
|
|| (0 == strcmp( p, "OM2" )) || (0 == strcmp( p, "OM3" )) || (0 == strcmp( p, "OM4" )))
|
||||||
|| (0 == strcmp( p, "OM1" ))
|
return TRUE;
|
||||||
|| (0 == strcmp( p, "OM2" ))
|
|
||||||
|| (0 == strcmp( p, "OM3" ))
|
|
||||||
|| (0 == strcmp( p, "OM4" ))
|
|
||||||
)
|
|
||||||
return( TRUE );
|
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
if( (0 == strcmp( p, "PT1" ))
|
if( (0 == strcmp( p, "PT1" )) || (0 == strcmp( p, "PT2" )) || (0 == strcmp( p, "PT3" )))
|
||||||
|| (0 == strcmp( p, "PT2" ))
|
return TRUE;
|
||||||
|| (0 == strcmp( p, "PT3" ))
|
|
||||||
)
|
|
||||||
return( TRUE );
|
|
||||||
break;
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
if( 0 == strcmp( p, "UL" ) )
|
if( 0 == strcmp( p, "UL" ) )
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if( 0 == strcmp( p, "RN" ) )
|
if( 0 == strcmp( p, "RN" ) )
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
} /* is_reserved_msdos */
|
} /* is_reserved_msdos */
|
||||||
|
|
||||||
|
|
||||||
@ -229,32 +361,22 @@ static int is_reserved_msdos( char *fname )
|
|||||||
static int is_illegal_name(char *name)
|
static int is_illegal_name(char *name)
|
||||||
{
|
{
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
int skip;
|
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
|
|
||||||
if (!ct_initialized)
|
if (!ct_initialized)
|
||||||
init_chartest();
|
init_chartest();
|
||||||
|
|
||||||
s = (unsigned char *)name;
|
s = (unsigned char *)name;
|
||||||
while( *s )
|
while (*s) {
|
||||||
{
|
|
||||||
skip = get_character_len( *s );
|
|
||||||
if( skip != 0 )
|
|
||||||
{
|
|
||||||
s += skip;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isillegal(*s))
|
if (isillegal(*s))
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
else
|
else
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
} /* is_illegal_name */
|
} /* is_illegal_name */
|
||||||
|
|
||||||
|
|
||||||
@ -283,15 +405,14 @@ int is_mangled( char *s )
|
|||||||
init_chartest();
|
init_chartest();
|
||||||
|
|
||||||
magic = strchr(s, magic_char);
|
magic = strchr(s, magic_char);
|
||||||
while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */
|
while (magic && magic[1] && magic[2]) { /* 3 chars, 1st is magic. */
|
||||||
{
|
|
||||||
if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
|
if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
|
||||||
&& isbasechar(toupper(magic[1])) /* is 2nd char basechar? */
|
&& isbasechar(toupper(magic[1])) /* is 2nd char basechar? */
|
||||||
&& isbasechar(toupper(magic[2]))) /* is 3rd char basechar? */
|
&& isbasechar(toupper(magic[2]))) /* is 3rd char basechar? */
|
||||||
return( TRUE ); /* If all above, then true, */
|
return TRUE; /* If all above, then true, */
|
||||||
magic = strchr(magic+1, magic_char); /* else seek next magic. */
|
magic = strchr(magic+1, magic_char); /* else seek next magic. */
|
||||||
}
|
}
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
} /* is_mangled */
|
} /* is_mangled */
|
||||||
|
|
||||||
|
|
||||||
@ -312,7 +433,6 @@ int is_8_3( char *fname, int check_case )
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
int l;
|
int l;
|
||||||
int skip;
|
|
||||||
char *p;
|
char *p;
|
||||||
char *dot_pos;
|
char *dot_pos;
|
||||||
char *slash_pos = strrchr( fname, '/' );
|
char *slash_pos = strrchr( fname, '/' );
|
||||||
@ -326,24 +446,22 @@ int is_8_3( char *fname, int check_case )
|
|||||||
|
|
||||||
/* Can't be 0 chars or longer than 12 chars */
|
/* Can't be 0 chars or longer than 12 chars */
|
||||||
if( (len == 0) || (len > 12) )
|
if( (len == 0) || (len > 12) )
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
|
|
||||||
/* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
|
/* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
|
||||||
if (is_reserved_msdos(fname))
|
if (is_reserved_msdos(fname))
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
|
|
||||||
/* Check that all characters are the correct case, if asked to do so. */
|
/* Check that all characters are the correct case, if asked to do so. */
|
||||||
if( check_case && case_mangle )
|
if (check_case && case_mangle) {
|
||||||
{
|
switch (case_default) {
|
||||||
switch( case_default )
|
|
||||||
{
|
|
||||||
case CASE_LOWER:
|
case CASE_LOWER:
|
||||||
if (strhasupper(fname))
|
if (strhasupper(fname))
|
||||||
return(FALSE);
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
case CASE_UPPER:
|
case CASE_UPPER:
|
||||||
if (strhaslower(fname))
|
if (strhaslower(fname))
|
||||||
return(FALSE);
|
return FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,20 +477,14 @@ int is_8_3( char *fname, int check_case )
|
|||||||
|
|
||||||
p = fname;
|
p = fname;
|
||||||
dot_pos = NULL;
|
dot_pos = NULL;
|
||||||
while( *p )
|
while (*p) {
|
||||||
{
|
|
||||||
if( (skip = get_character_len( *p )) != 0 )
|
|
||||||
p += skip;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*p == '.' && !dot_pos)
|
if (*p == '.' && !dot_pos)
|
||||||
dot_pos = (char *)p;
|
dot_pos = (char *)p;
|
||||||
else
|
// else
|
||||||
if( !isdoschar( *p ) )
|
// if (!isdoschar(*p))
|
||||||
return( FALSE );
|
// return FALSE;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* no dot and less than 9 means OK */
|
/* no dot and less than 9 means OK */
|
||||||
if (!dot_pos)
|
if (!dot_pos)
|
||||||
@ -386,73 +498,364 @@ int is_8_3( char *fname, int check_case )
|
|||||||
|
|
||||||
/* base can't be greater than 8 */
|
/* base can't be greater than 8 */
|
||||||
if (l > 8)
|
if (l > 8)
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
|
|
||||||
/* see smb.conf(5) for a description of the 'strip dot' parameter. */
|
/* see smb.conf(5) for a description of the 'strip dot' parameter. */
|
||||||
if( lp_strip_dot()
|
/* strip_dot defaults to no */
|
||||||
&& len - l == 1
|
if (/* lp_strip_dot() && */ len - l == 1 && !strchr( dot_pos + 1, '.' )) {
|
||||||
&& !strchr( dot_pos + 1, '.' ) )
|
|
||||||
{
|
|
||||||
*dot_pos = 0;
|
*dot_pos = 0;
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extension must be between 1 and 3 */
|
/* extension must be between 1 and 3 */
|
||||||
if ((len - l < 2 ) || (len - l > 4))
|
if ((len - l < 2 ) || (len - l > 4))
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
|
|
||||||
/* extensions may not have a dot */
|
/* extensions may not have a dot */
|
||||||
if (strchr( dot_pos+1, '.' ))
|
if (strchr( dot_pos+1, '.' ))
|
||||||
return( FALSE );
|
return FALSE;
|
||||||
|
|
||||||
/* must be in 8.3 format */
|
/* must be in 8.3 format */
|
||||||
return( TRUE );
|
return TRUE;
|
||||||
} /* is_8_3 */
|
} /* is_8_3 */
|
||||||
|
|
||||||
|
|
||||||
/* ************************************************************************** **
|
/* ************************************************************************** **
|
||||||
* Compare two cache keys and return a value indicating their ordinal
|
* Used only in do_fwd_mangled_map(), below.
|
||||||
* 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 )
|
static char *map_filename( char *s, /* This is null terminated */
|
||||||
|
char *pattern, /* This isn't. */
|
||||||
|
int len ) /* This is the length of pattern. */
|
||||||
{
|
{
|
||||||
char *Key1 = (char *)ItemPtr;
|
static pstring matching_bit; /* The bit of the string which matches */
|
||||||
char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
|
/* a * in pattern if indeed there is a * */
|
||||||
|
char *sp; /* Pointer into s. */
|
||||||
|
char *pp; /* Pointer into p. */
|
||||||
|
char *match_start; /* Where the matching bit starts. */
|
||||||
|
pstring pat;
|
||||||
|
|
||||||
|
strncpy( pat, pattern, len ); /* Get pattern into a proper string! */
|
||||||
|
pstrcpy( matching_bit, "" ); /* Match but no star gets this. */
|
||||||
|
pp = pat; /* Initialize the pointers. */
|
||||||
|
sp = s;
|
||||||
|
|
||||||
|
if( strequal(s, ".") || strequal(s, "..")) {
|
||||||
|
return NULL; /* Do not map '.' and '..' */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((len == 1) && (*pattern == '*')) {
|
||||||
|
return NULL; /* Impossible, too ambiguous for */
|
||||||
|
} /* words! */
|
||||||
|
|
||||||
|
while ((*sp) /* Not the end of the string. */
|
||||||
|
&& (*pp) /* Not the end of the pattern. */
|
||||||
|
&& (*sp == *pp) /* The two match. */
|
||||||
|
&& (*pp != '*')) { /* No wildcard. */
|
||||||
|
sp++; /* Keep looking. */
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*sp && !*pp) /* End of pattern. */
|
||||||
|
return (matching_bit); /* Simple match. Return empty string. */
|
||||||
|
|
||||||
|
if (*pp == '*') {
|
||||||
|
pp++; /* Always interrested in the chacter */
|
||||||
|
/* after the '*' */
|
||||||
|
if (!*pp) { /* It is at the end of the pattern. */
|
||||||
|
strncpy(matching_bit, s, sp-s);
|
||||||
|
return matching_bit;
|
||||||
|
} else {
|
||||||
|
/* The next character in pattern must match a character further */
|
||||||
|
/* along s than sp so look for that character. */
|
||||||
|
match_start = sp;
|
||||||
|
while ((*sp) /* Not the end of s. */
|
||||||
|
&& (*sp != *pp)) /* Not the same */
|
||||||
|
sp++; /* Keep looking. */
|
||||||
|
if (!*sp) { /* Got to the end without a match. */
|
||||||
|
return( NULL );
|
||||||
|
} else { /* Still hope for a match. */
|
||||||
|
/* Now sp should point to a matching character. */
|
||||||
|
strncpy(matching_bit, match_start, sp-match_start);
|
||||||
|
/* Back to needing a stright match again. */
|
||||||
|
while ((*sp) /* Not the end of the string. */
|
||||||
|
&& (*pp) /* Not the end of the pattern. */
|
||||||
|
&& (*sp == *pp)) { /* The two match. */
|
||||||
|
sp++; /* Keep looking. */
|
||||||
|
pp++;
|
||||||
|
}
|
||||||
|
if (!*sp && !*pp) /* Both at end so it matched */
|
||||||
|
return matching_bit;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* No match. */
|
||||||
|
} /* map_filename */
|
||||||
|
|
||||||
return( StrCaseCmp( Key1, Key2 ) );
|
|
||||||
} /* cache_compare */
|
|
||||||
|
|
||||||
/* ************************************************************************** **
|
/* ************************************************************************** **
|
||||||
* Free a cache entry.
|
* MangledMap is a series of name pairs in () separated by spaces.
|
||||||
|
* If s matches the first of the pair then the name given is the
|
||||||
|
* second of the pair. A * means any number of any character and if
|
||||||
|
* present in the second of the pair as well as the first the
|
||||||
|
* matching part of the first string takes the place of the * in the
|
||||||
|
* second.
|
||||||
*
|
*
|
||||||
* Input: WarrenZevon - Pointer to the entry that is to be returned to
|
* I wanted this so that we could have RCS files which can be used
|
||||||
* Nirvana.
|
* by UNIX and DOS programs. My mapping string is (RCS rcs) which
|
||||||
* Output: none.
|
* converts the UNIX RCS file subdirectory to lowercase thus
|
||||||
|
* preventing mangling.
|
||||||
*
|
*
|
||||||
* Notes: This function gets around the possibility that the standard
|
* (I think Andrew wrote the above, but I'm not sure. -- CRH)
|
||||||
* free() function may be implemented as a macro, or other evil
|
*
|
||||||
* subversions (oh, so much fun).
|
* See 'mangled map' in smb.conf(5).
|
||||||
*
|
*
|
||||||
* ************************************************************************** **
|
* ************************************************************************** **
|
||||||
*/
|
*/
|
||||||
static void cache_free_entry( ubi_trNodePtr WarrenZevon )
|
|
||||||
{
|
static void do_fwd_mangled_map(char *s, char *MangledMap)
|
||||||
ZERO_STRUCTP(WarrenZevon);
|
{
|
||||||
free( WarrenZevon );
|
char *start=MangledMap; /* Use this to search for mappings. */
|
||||||
} /* cache_free_entry */
|
char *end; /* Used to find the end of strings. */
|
||||||
|
char *match_string;
|
||||||
|
pstring new_string; /* Make up the result here. */
|
||||||
|
char *np; /* Points into new_string. */
|
||||||
|
|
||||||
|
Syslog('f', "Mangled Mapping '%s' map '%s'\n", s, MangledMap);
|
||||||
|
while( *start )
|
||||||
|
{
|
||||||
|
while( (*start) && (*start != '(') )
|
||||||
|
start++;
|
||||||
|
if( !*start )
|
||||||
|
continue; /* Always check for the end. */
|
||||||
|
start++; /* Skip the ( */
|
||||||
|
end = start; /* Search for the ' ' or a ')' */
|
||||||
|
Syslog('f', "Start of first in pair '%s'\n", start);
|
||||||
|
while( (*end) && !((*end == ' ') || (*end == ')')) )
|
||||||
|
end++;
|
||||||
|
if( !*end )
|
||||||
|
{
|
||||||
|
start = end;
|
||||||
|
continue; /* Always check for the end. */
|
||||||
|
}
|
||||||
|
Syslog('f', "End of first in pair '%s'\n", end);
|
||||||
|
if( (match_string = map_filename( s, start, end-start )) )
|
||||||
|
{
|
||||||
|
Syslog('f', "Found a match\n");
|
||||||
|
/* Found a match. */
|
||||||
|
start = end + 1; /* Point to start of what it is to become. */
|
||||||
|
Syslog('f', "Start of second in pair '%s'\n", start);
|
||||||
|
end = start;
|
||||||
|
np = new_string;
|
||||||
|
while( (*end) /* Not the end of string. */
|
||||||
|
&& (*end != ')') /* Not the end of the pattern. */
|
||||||
|
&& (*end != '*') ) /* Not a wildcard. */
|
||||||
|
*np++ = *end++;
|
||||||
|
if( !*end )
|
||||||
|
{
|
||||||
|
start = end;
|
||||||
|
continue; /* Always check for the end. */
|
||||||
|
}
|
||||||
|
if( *end == '*' )
|
||||||
|
{
|
||||||
|
pstrcpy( np, match_string );
|
||||||
|
np += strlen( match_string );
|
||||||
|
end++; /* Skip the '*' */
|
||||||
|
while( (*end) /* Not the end of string. */
|
||||||
|
&& (*end != ')') /* Not the end of the pattern. */
|
||||||
|
&& (*end != '*') ) /* Not a wildcard. */
|
||||||
|
*np++ = *end++;
|
||||||
|
}
|
||||||
|
if( !*end )
|
||||||
|
{
|
||||||
|
start = end;
|
||||||
|
continue; /* Always check for the end. */
|
||||||
|
}
|
||||||
|
*np++ = '\0'; /* NULL terminate it. */
|
||||||
|
Syslog('f', "End of second in pair '%s'\n", end);
|
||||||
|
pstrcpy( s, new_string ); /* Substitute with the new name. */
|
||||||
|
Syslog('f', "s is now '%s'\n", s);
|
||||||
|
}
|
||||||
|
start = end; /* Skip a bit which cannot be wanted anymore. */
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
} /* do_fwd_mangled_map */
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* do the actual mangling to 8.3 format
|
||||||
|
* the buffer must be able to hold 13 characters (including the null)
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
void mangle_name_83(char *s)
|
||||||
|
{
|
||||||
|
int csum;
|
||||||
|
char *p;
|
||||||
|
char extension[4];
|
||||||
|
char base[9];
|
||||||
|
int baselen = 0;
|
||||||
|
int extlen = 0;
|
||||||
|
int skip;
|
||||||
|
|
||||||
|
extension[0] = 0;
|
||||||
|
base[0] = 0;
|
||||||
|
|
||||||
|
p = strrchr(s,'.');
|
||||||
|
if (p && (strlen(p+1) < (size_t)4)) {
|
||||||
|
int all_normal = (strisnormal(p+1)); /* XXXXXXXXX */
|
||||||
|
|
||||||
|
if( all_normal && p[1] != 0 ) {
|
||||||
|
*p = 0;
|
||||||
|
csum = str_checksum( s );
|
||||||
|
*p = '.';
|
||||||
|
} else
|
||||||
|
csum = str_checksum(s);
|
||||||
|
} else
|
||||||
|
csum = str_checksum(s);
|
||||||
|
|
||||||
|
tu(s);
|
||||||
|
Syslog('f', "Mangling name %s to ",s);
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
if( p == s )
|
||||||
|
safe_strcpy( extension, "___", 3 );
|
||||||
|
else {
|
||||||
|
*p++ = 0;
|
||||||
|
while (*p && extlen < 3) {
|
||||||
|
skip = get_character_len(*p);
|
||||||
|
switch(skip) {
|
||||||
|
case 2:
|
||||||
|
if( extlen < 2 ) {
|
||||||
|
extension[extlen++] = p[0];
|
||||||
|
extension[extlen++] = p[1];
|
||||||
|
} else {
|
||||||
|
extension[extlen++] = mangle( (unsigned char)*p );
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
extension[extlen++] = p[0];
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(/* isdoschar (*p) && */ *p != '.' )
|
||||||
|
extension[extlen++] = p[0];
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extension[extlen] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = s;
|
||||||
|
|
||||||
|
while( *p && baselen < 5 ) {
|
||||||
|
skip = get_character_len(*p);
|
||||||
|
switch( skip ) {
|
||||||
|
case 2:
|
||||||
|
if( baselen < 4 ) {
|
||||||
|
base[baselen++] = p[0];
|
||||||
|
base[baselen++] = p[1];
|
||||||
|
} else {
|
||||||
|
base[baselen++] = mangle( (unsigned char)*p );
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
base[baselen++] = p[0];
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
if(/* isdoschar( *p ) && */ *p != '.' )
|
||||||
|
base[baselen++] = p[0];
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base[baselen] = 0;
|
||||||
|
|
||||||
|
csum = csum % (MANGLE_BASE*MANGLE_BASE);
|
||||||
|
|
||||||
|
(void)slprintf(s, 12, "%s%c%c%c",
|
||||||
|
base, magic_char, mangle( csum/MANGLE_BASE ), mangle( csum ) );
|
||||||
|
|
||||||
|
if( *extension ) {
|
||||||
|
(void)pstrcat( s, "." );
|
||||||
|
(void)pstrcat( s, extension );
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog('f', "%s\n", s);
|
||||||
|
|
||||||
|
} /* mangle_name_83 */
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Convert a filename to DOS format. Return True if successful.
|
||||||
|
*
|
||||||
|
* Input: OutName - Source *and* destination buffer.
|
||||||
|
*
|
||||||
|
* NOTE that OutName must point to a memory space that
|
||||||
|
* is at least 13 bytes in size!
|
||||||
|
*
|
||||||
|
* need83 - If False, name mangling will be skipped unless the
|
||||||
|
* name contains illegal characters. Mapping will still
|
||||||
|
* be done, if appropriate. This is probably used to
|
||||||
|
* signal that a client does not require name mangling,
|
||||||
|
* thus skipping the name mangling even on shares which
|
||||||
|
* have name-mangling turned on.
|
||||||
|
* cache83 - If False, the mangled name cache will not be updated.
|
||||||
|
* This is usually used to prevent that we overwrite
|
||||||
|
* a conflicting cache entry prematurely, i.e. before
|
||||||
|
* we know whether the client is really interested in the
|
||||||
|
* current name. (See PR#13758). UKD.
|
||||||
|
* snum - Share number. This identifies the share in which the
|
||||||
|
* name exists.
|
||||||
|
*
|
||||||
|
* Output: Returns False only if the name wanted mangling but the share does
|
||||||
|
* not have name mangling turned on.
|
||||||
|
*
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
int name_map_mangle(char *OutName, int need83, int cache83, int snum)
|
||||||
|
{
|
||||||
|
char *map;
|
||||||
|
Syslog('f',"name_map_mangle( %s, need83 = %s, cache83 = %s, %d )\n", OutName,
|
||||||
|
need83 ? "TRUE" : "FALSE", cache83 ? "TRUE" : "FALSE", snum);
|
||||||
|
|
||||||
|
#ifdef MANGLE_LONG_FILENAMES
|
||||||
|
if( !need83 && is_illegal_name(OutName) )
|
||||||
|
need83 = TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* apply any name mappings */
|
||||||
|
map = lp_mangled_map(snum);
|
||||||
|
|
||||||
|
if (map && *map) {
|
||||||
|
do_fwd_mangled_map( OutName, map );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if it's already in 8.3 format */
|
||||||
|
if (need83 && !is_8_3(OutName, TRUE)) {
|
||||||
|
char *tmp = NULL;
|
||||||
|
|
||||||
|
if (!lp_manglednames(snum)) {
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mangle it into 8.3 */
|
||||||
|
if (cache83)
|
||||||
|
tmp = strdup(OutName);
|
||||||
|
|
||||||
|
mangle_name_83(OutName);
|
||||||
|
|
||||||
|
if(tmp != NULL) {
|
||||||
|
cache_mangled_name(OutName, tmp);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog('f',"name_map_mangle() ==> [%s]\n", OutName);
|
||||||
|
return(TRUE);
|
||||||
|
} /* name_map_mangle */
|
||||||
|
|
||||||
|
|
||||||
|
1133
lib/ubi_BinTree.c
1133
lib/ubi_BinTree.c
File diff suppressed because it is too large
Load Diff
@ -1,859 +0,0 @@
|
|||||||
#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
506
lib/ubi_Cache.c
@ -1,506 +0,0 @@
|
|||||||
/* ========================================================================== **
|
|
||||||
* 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
412
lib/ubi_Cache.h
@ -1,412 +0,0 @@
|
|||||||
#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 */
|
|
@ -1,513 +0,0 @@
|
|||||||
/* ========================================================================== **
|
|
||||||
* 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 ================================= */
|
|
||||||
|
|
@ -1,377 +0,0 @@
|
|||||||
#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 */
|
|
@ -1,172 +0,0 @@
|
|||||||
/* ========================================================================== **
|
|
||||||
* 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 ================================= */
|
|
@ -1,241 +0,0 @@
|
|||||||
#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 */
|
|
@ -1,188 +0,0 @@
|
|||||||
/* ========================================================================== **
|
|
||||||
* 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 ================================= */
|
|
@ -1,253 +0,0 @@
|
|||||||
#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 */
|
|
@ -539,7 +539,7 @@ void Index(void)
|
|||||||
while (fread(&file, sizeof(file), 1, pFile) == 1) {
|
while (fread(&file, sizeof(file), 1, pFile) == 1) {
|
||||||
if ((!file.Deleted) && (!file.Missing)) {
|
if ((!file.Deleted) && (!file.Missing)) {
|
||||||
fbFiles++;
|
fbFiles++;
|
||||||
fprintf(fp, "%-12s %s\r\n", file.Name, file.Desc[0]);
|
fprintf(fp, "%-12s [%ld] %s\r\n", file.Name, file.TimesDL + file.TimesFTP + file.TimesReq, file.Desc[0]);
|
||||||
for (j = 1; j < 25; j++)
|
for (j = 1; j < 25; j++)
|
||||||
if (strlen(file.Desc[j]))
|
if (strlen(file.Desc[j]))
|
||||||
fprintf(fp, " +%s\r\n", file.Desc[j]);
|
fprintf(fp, " +%s\r\n", file.Desc[j]);
|
||||||
|
@ -113,7 +113,7 @@ void Help()
|
|||||||
colour(9, 0);
|
colour(9, 0);
|
||||||
printf(" Commands are:\n\n");
|
printf(" Commands are:\n\n");
|
||||||
colour(3, 0);
|
colour(3, 0);
|
||||||
printf(" i index Create \"00index\" files and WWW pages in areas\n");
|
printf(" l list Create allfiles and newfiles lists\n");
|
||||||
colour(9, 0);
|
colour(9, 0);
|
||||||
printf("\n Options are:\n\n");
|
printf("\n Options are:\n\n");
|
||||||
colour(3, 0);
|
colour(3, 0);
|
||||||
|
Reference in New Issue
Block a user