Added UBI library
This commit is contained in:
parent
4349e984c6
commit
614bc71f09
481
lib/COPYING.LIB
Normal file
481
lib/COPYING.LIB
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||||
|
675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the library GPL. It is
|
||||||
|
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Library General Public License, applies to some
|
||||||
|
specially designated Free Software Foundation software, and to any
|
||||||
|
other libraries whose authors decide to use it. You can use it for
|
||||||
|
your libraries, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if
|
||||||
|
you distribute copies of the library, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link a program with the library, you must provide
|
||||||
|
complete object files to the recipients so that they can relink them
|
||||||
|
with the library, after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
Our method of protecting your rights has two steps: (1) copyright
|
||||||
|
the library, and (2) offer you this license which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
Also, for each distributor's protection, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
library. If the library is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original
|
||||||
|
version, so that any problems introduced by others will not reflect on
|
||||||
|
the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that companies distributing free
|
||||||
|
software will individually obtain patent licenses, thus in effect
|
||||||
|
transforming the program into proprietary software. To prevent this,
|
||||||
|
we have made it clear that any patent must be licensed for everyone's
|
||||||
|
free use or not licensed at all.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the ordinary
|
||||||
|
GNU General Public License, which was designed for utility programs. This
|
||||||
|
license, the GNU Library General Public License, applies to certain
|
||||||
|
designated libraries. This license is quite different from the ordinary
|
||||||
|
one; be sure to read it in full, and don't assume that anything in it is
|
||||||
|
the same as in the ordinary license.
|
||||||
|
|
||||||
|
The reason we have a separate public license for some libraries is that
|
||||||
|
they blur the distinction we usually make between modifying or adding to a
|
||||||
|
program and simply using it. Linking a program with a library, without
|
||||||
|
changing the library, is in some sense simply using the library, and is
|
||||||
|
analogous to running a utility program or application program. However, in
|
||||||
|
a textual and legal sense, the linked executable is a combined work, a
|
||||||
|
derivative of the original library, and the ordinary General Public License
|
||||||
|
treats it as such.
|
||||||
|
|
||||||
|
Because of this blurred distinction, using the ordinary General
|
||||||
|
Public License for libraries did not effectively promote software
|
||||||
|
sharing, because most developers did not use the libraries. We
|
||||||
|
concluded that weaker conditions might promote sharing better.
|
||||||
|
|
||||||
|
However, unrestricted linking of non-free programs would deprive the
|
||||||
|
users of those programs of all benefit from the free status of the
|
||||||
|
libraries themselves. This Library General Public License is intended to
|
||||||
|
permit developers of non-free programs to use free libraries, while
|
||||||
|
preserving your freedom as a user of such programs to change the free
|
||||||
|
libraries that are incorporated in them. (We have not seen how to achieve
|
||||||
|
this as regards changes in header files, but we have achieved it as regards
|
||||||
|
changes in the actual functions of the Library.) The hope is that this
|
||||||
|
will lead to faster development of free libraries.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, while the latter only
|
||||||
|
works together with the library.
|
||||||
|
|
||||||
|
Note that it is possible for a library to be covered by the ordinary
|
||||||
|
General Public License rather than by this special one.
|
||||||
|
|
||||||
|
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library which
|
||||||
|
contains a notice placed by the copyright holder or other authorized
|
||||||
|
party saying it may be distributed under the terms of this Library
|
||||||
|
General Public License (also called "this License"). Each licensee is
|
||||||
|
addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also compile or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
c) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
d) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the source code distributed need not include anything that is normally
|
||||||
|
distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Library General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Appendix: How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
10
lib/Makefile
10
lib/Makefile
@ -30,11 +30,15 @@ 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
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@ -71,6 +75,10 @@ libmemwatch.a: ${MEMWATCH_OBJS}
|
|||||||
ar r $@ $?
|
ar r $@ $?
|
||||||
${RANLIB} $@
|
${RANLIB} $@
|
||||||
|
|
||||||
|
libubi.a: ${UBI_OBJS}
|
||||||
|
ar r $@ $?
|
||||||
|
${RANLIB} $@
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
16
lib/README.UBI
Normal file
16
lib/README.UBI
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Sun Nov 25 23:18:30 CET 2001
|
||||||
|
|
||||||
|
The C code files in the samba/source/ubiqx directory are licensed under
|
||||||
|
the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE (LGPL). A copy of the
|
||||||
|
LGPL should also be included in this directory under the name COPYING.LIB.
|
||||||
|
If this file is not present, you can obtain a copy of the LGPL by writing
|
||||||
|
to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||||
|
USA.
|
||||||
|
|
||||||
|
The versions of the ubiqx modules distributed with MBSE BBS may have been
|
||||||
|
modified for inclusion with MBSE BBS. The main distribution, which contains
|
||||||
|
additional available modules, can be found at:
|
||||||
|
|
||||||
|
http://www.interads.co.uk/~crh/ubiqx/
|
||||||
|
|
||||||
|
Michiel Broek.
|
309
lib/debugparse.c
Normal file
309
lib/debugparse.c
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/* ========================================================================== **
|
||||||
|
* debugparse.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module is a very simple parser for Samba debug log files.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* The important function in this module is dbg_char2token(). The rest is
|
||||||
|
* basically fluff. (Potentially useful fluff, but still fluff.)
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libs.h"
|
||||||
|
#include "debugparse.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Constants...
|
||||||
|
*
|
||||||
|
* DBG_BSIZE - This internal constant is used only by dbg_test(). It is the
|
||||||
|
* size of the read buffer. I've tested the function using a
|
||||||
|
* DBG_BSIZE value of 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DBG_BSIZE 128
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *dbg_token2string( dbg_Token tok )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given a token, return a string describing the token.
|
||||||
|
*
|
||||||
|
* Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
|
||||||
|
*
|
||||||
|
* Output: A string identifying the token. This is useful for debugging,
|
||||||
|
* etc.
|
||||||
|
*
|
||||||
|
* Note: If the token is not known, this function will return the
|
||||||
|
* string "<unknown>".
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
switch( tok )
|
||||||
|
{
|
||||||
|
case dbg_null:
|
||||||
|
return( (char *)"null" );
|
||||||
|
case dbg_ignore:
|
||||||
|
return( (char *)"ignore" );
|
||||||
|
case dbg_header:
|
||||||
|
return( (char *)"header" );
|
||||||
|
case dbg_timestamp:
|
||||||
|
return( (char *)"time stamp" );
|
||||||
|
case dbg_level:
|
||||||
|
return( (char *)"level" );
|
||||||
|
case dbg_sourcefile:
|
||||||
|
return( (char *)"source file" );
|
||||||
|
case dbg_function:
|
||||||
|
return( (char *)"function" );
|
||||||
|
case dbg_lineno:
|
||||||
|
return( (char *)"line number" );
|
||||||
|
case dbg_message:
|
||||||
|
return( (char *)"message" );
|
||||||
|
case dbg_eof:
|
||||||
|
return( (char *)"[EOF]" );
|
||||||
|
}
|
||||||
|
return( (char *)"<unknown>" );
|
||||||
|
} /* dbg_token2string */
|
||||||
|
|
||||||
|
dbg_Token dbg_char2token( dbg_Token *state, int c )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Parse input one character at a time.
|
||||||
|
*
|
||||||
|
* Input: state - A pointer to a token variable. This is used to
|
||||||
|
* maintain the parser state between calls. For
|
||||||
|
* each input stream, you should set up a separate
|
||||||
|
* state variable and initialize it to dbg_null.
|
||||||
|
* Pass a pointer to it into this function with each
|
||||||
|
* character in the input stream. See dbg_test()
|
||||||
|
* for an example.
|
||||||
|
* c - The "current" character in the input stream.
|
||||||
|
*
|
||||||
|
* Output: A token.
|
||||||
|
* The token value will change when delimiters are found,
|
||||||
|
* which indicate a transition between syntactical objects.
|
||||||
|
* Possible return values are:
|
||||||
|
*
|
||||||
|
* dbg_null - The input character was an end-of-line.
|
||||||
|
* This resets the parser to its initial state
|
||||||
|
* in preparation for parsing the next line.
|
||||||
|
* dbg_eof - Same as dbg_null, except that the character
|
||||||
|
* was an end-of-file.
|
||||||
|
* dbg_ignore - Returned for whitespace and delimiters.
|
||||||
|
* These lexical tokens are only of interest
|
||||||
|
* to the parser.
|
||||||
|
* dbg_header - Indicates the start of a header line. The
|
||||||
|
* input character was '[' and was the first on
|
||||||
|
* the line.
|
||||||
|
* dbg_timestamp - Indicates that the input character was part
|
||||||
|
* of a header timestamp.
|
||||||
|
* dbg_level - Indicates that the input character was part
|
||||||
|
* of the debug-level value in the header.
|
||||||
|
* dbg_sourcefile - Indicates that the input character was part
|
||||||
|
* of the sourcefile name in the header.
|
||||||
|
* dbg_function - Indicates that the input character was part
|
||||||
|
* of the function name in the header.
|
||||||
|
* dbg_lineno - Indicates that the input character was part
|
||||||
|
* of the DEBUG call line number in the header.
|
||||||
|
* dbg_message - Indicates that the input character was part
|
||||||
|
* of the DEBUG message text.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* The terminating characters that we see will greatly depend upon
|
||||||
|
* how they are read. For example, if gets() is used instead of
|
||||||
|
* fgets(), then we will not see newline characters. A lot also
|
||||||
|
* depends on the calling function, which may handle terminators
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* '\n', '\0', and EOF are all considered line terminators. The
|
||||||
|
* dbg_eof token is sent back if an EOF is encountered.
|
||||||
|
*
|
||||||
|
* Warning: only allow the '\0' character to be sent if you are
|
||||||
|
* using gets() to read whole lines (thus replacing '\n'
|
||||||
|
* with '\0'). Sending '\0' at the wrong time will mess
|
||||||
|
* up the parsing.
|
||||||
|
*/
|
||||||
|
switch( c )
|
||||||
|
{
|
||||||
|
case EOF:
|
||||||
|
*state = dbg_null; /* Set state to null (initial state) so */
|
||||||
|
return( dbg_eof ); /* that we can restart with new input. */
|
||||||
|
case '\n':
|
||||||
|
case '\0':
|
||||||
|
*state = dbg_null; /* A newline or eoln resets to the null state. */
|
||||||
|
return( dbg_null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When within the body of the message, only a line terminator
|
||||||
|
* can cause a change of state. We've already checked for line
|
||||||
|
* terminators, so if the current state is dbg_msgtxt, simply
|
||||||
|
* return that as our current token.
|
||||||
|
*/
|
||||||
|
if( dbg_message == *state )
|
||||||
|
return( dbg_message );
|
||||||
|
|
||||||
|
/* If we are at the start of a new line, and the input character
|
||||||
|
* is an opening bracket, then the line is a header line, otherwise
|
||||||
|
* it's a message body line.
|
||||||
|
*/
|
||||||
|
if( dbg_null == *state )
|
||||||
|
{
|
||||||
|
if( '[' == c )
|
||||||
|
{
|
||||||
|
*state = dbg_timestamp;
|
||||||
|
return( dbg_header );
|
||||||
|
}
|
||||||
|
*state = dbg_message;
|
||||||
|
return( dbg_message );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've taken care of terminators, text blocks and new lines.
|
||||||
|
* The remaining possibilities are all within the header line
|
||||||
|
* itself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Within the header line, whitespace can be ignored *except*
|
||||||
|
* within the timestamp.
|
||||||
|
*/
|
||||||
|
if( isspace( c ) )
|
||||||
|
{
|
||||||
|
/* Fudge. The timestamp may contain space characters. */
|
||||||
|
if( (' ' == c) && (dbg_timestamp == *state) )
|
||||||
|
return( dbg_timestamp );
|
||||||
|
/* Otherwise, ignore whitespace. */
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Okay, at this point we know we're somewhere in the header.
|
||||||
|
* Valid header *states* are: dbg_timestamp, dbg_level,
|
||||||
|
* dbg_sourcefile, dbg_function, and dbg_lineno.
|
||||||
|
*/
|
||||||
|
switch( c )
|
||||||
|
{
|
||||||
|
case ',':
|
||||||
|
if( dbg_timestamp == *state )
|
||||||
|
{
|
||||||
|
*state = dbg_level;
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
if( dbg_level == *state )
|
||||||
|
{
|
||||||
|
*state = dbg_sourcefile;
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
if( dbg_sourcefile == *state )
|
||||||
|
{
|
||||||
|
*state = dbg_function;
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
if( dbg_function == *state )
|
||||||
|
{
|
||||||
|
*state = dbg_lineno;
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
if( dbg_lineno == *state )
|
||||||
|
{
|
||||||
|
*state = dbg_null;
|
||||||
|
return( dbg_ignore );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the previous block did not result in a state change, then
|
||||||
|
* return the current state as the current token.
|
||||||
|
*/
|
||||||
|
return( *state );
|
||||||
|
} /* dbg_char2token */
|
||||||
|
|
||||||
|
void dbg_test( void )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Simple test function.
|
||||||
|
*
|
||||||
|
* Input: none.
|
||||||
|
* Output: none.
|
||||||
|
* Notes: This function was used to test dbg_char2token(). It reads a
|
||||||
|
* Samba log file from stdin and prints parsing info to stdout.
|
||||||
|
* It also serves as a simple example.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
char bufr[DBG_BSIZE];
|
||||||
|
int i;
|
||||||
|
int linecount = 1;
|
||||||
|
dbg_Token old = dbg_null,
|
||||||
|
new = dbg_null,
|
||||||
|
state = dbg_null;
|
||||||
|
|
||||||
|
while( fgets( bufr, DBG_BSIZE, stdin ) )
|
||||||
|
{
|
||||||
|
for( i = 0; bufr[i]; i++ )
|
||||||
|
{
|
||||||
|
old = new;
|
||||||
|
new = dbg_char2token( &state, bufr[i] );
|
||||||
|
switch( new )
|
||||||
|
{
|
||||||
|
case dbg_header:
|
||||||
|
if( linecount > 1 )
|
||||||
|
(void)putchar( '\n' );
|
||||||
|
break;
|
||||||
|
case dbg_null:
|
||||||
|
linecount++;
|
||||||
|
break;
|
||||||
|
case dbg_ignore:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if( old != new )
|
||||||
|
(void)printf( "\n[%05d]%12s: ", linecount, dbg_token2string(new) );
|
||||||
|
(void)putchar( bufr[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)putchar( '\n' );
|
||||||
|
} /* dbg_test */
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* This simple main line can be uncommented and used to test the parser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* int main( void )
|
||||||
|
* {
|
||||||
|
* dbg_test();
|
||||||
|
* return( 0 );
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
127
lib/debugparse.h
Normal file
127
lib/debugparse.h
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#ifndef DEBUGPARSE_H
|
||||||
|
#define DEBUGPARSE_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* debugparse.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module is a very simple parser for Samba debug log files.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* The important function in this module is dbg_char2token(). The rest is
|
||||||
|
* basically fluff. (Potentially useful fluff, but still fluff.)
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #include "sys_include.h"
|
||||||
|
|
||||||
|
/* This module compiles quite nicely outside of the Samba environment.
|
||||||
|
* You'll need the following headers:
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* These are the tokens returned by dbg_char2token().
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
dbg_null = 0,
|
||||||
|
dbg_ignore,
|
||||||
|
dbg_header,
|
||||||
|
dbg_timestamp,
|
||||||
|
dbg_level,
|
||||||
|
dbg_sourcefile,
|
||||||
|
dbg_function,
|
||||||
|
dbg_lineno,
|
||||||
|
dbg_message,
|
||||||
|
dbg_eof
|
||||||
|
} dbg_Token;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Function prototypes...
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *dbg_token2string( dbg_Token tok );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given a token, return a string describing the token.
|
||||||
|
*
|
||||||
|
* Input: tok - One of the set of dbg_Tokens defined in debugparse.h.
|
||||||
|
*
|
||||||
|
* Output: A string identifying the token. This is useful for debugging,
|
||||||
|
* etc.
|
||||||
|
*
|
||||||
|
* Note: If the token is not known, this function will return the
|
||||||
|
* string "<unknown>".
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
dbg_Token dbg_char2token( dbg_Token *state, int c );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Parse input one character at a time.
|
||||||
|
*
|
||||||
|
* Input: state - A pointer to a token variable. This is used to
|
||||||
|
* maintain the parser state between calls. For
|
||||||
|
* each input stream, you should set up a separate
|
||||||
|
* state variable and initialize it to dbg_null.
|
||||||
|
* Pass a pointer to it into this function with each
|
||||||
|
* character in the input stream. See dbg_test()
|
||||||
|
* for an example.
|
||||||
|
* c - The "current" character in the input stream.
|
||||||
|
*
|
||||||
|
* Output: A token.
|
||||||
|
* The token value will change when delimiters are found,
|
||||||
|
* which indicate a transition between syntactical objects.
|
||||||
|
* Possible return values are:
|
||||||
|
*
|
||||||
|
* dbg_null - The input character was an end-of-line.
|
||||||
|
* This resets the parser to its initial state
|
||||||
|
* in preparation for parsing the next line.
|
||||||
|
* dbg_eof - Same as dbg_null, except that the character
|
||||||
|
* was an end-of-file.
|
||||||
|
* dbg_ignore - Returned for whitespace and delimiters.
|
||||||
|
* These lexical tokens are only of interest
|
||||||
|
* to the parser.
|
||||||
|
* dbg_header - Indicates the start of a header line. The
|
||||||
|
* input character was '[' and was the first on
|
||||||
|
* the line.
|
||||||
|
* dbg_timestamp - Indicates that the input character was part
|
||||||
|
* of a header timestamp.
|
||||||
|
* dbg_level - Indicates that the input character was part
|
||||||
|
* of the debug-level value in the header.
|
||||||
|
* dbg_sourcefile - Indicates that the input character was part
|
||||||
|
* of the sourcefile name in the header.
|
||||||
|
* dbg_function - Indicates that the input character was part
|
||||||
|
* of the function name in the header.
|
||||||
|
* dbg_lineno - Indicates that the input character was part
|
||||||
|
* of the DEBUG call line number in the header.
|
||||||
|
* dbg_message - Indicates that the input character was part
|
||||||
|
* of the DEBUG message text.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
#endif /* DEBUGPARSE_H */
|
421
lib/mangle.c
421
lib/mangle.c
@ -26,12 +26,433 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
||||||
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*****************************************************************************
|
||||||
|
* Ideas taken from Samba, Copyright (C) Andrew Tridgell 1992-1998
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "libs.h"
|
#include "libs.h"
|
||||||
#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"
|
||||||
|
|
||||||
|
typedef enum {CASE_UPPER, CASE_LOWER} CASES;
|
||||||
|
|
||||||
|
int case_default = CASE_UPPER; /* Are conforming 8.3 names all upper or lower? */
|
||||||
|
int case_mangle = TRUE; /* If true, all chars in 8.3 should be same case. */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Other stuff...
|
||||||
|
*
|
||||||
|
* magic_char - This is the magic char used for mangling. It's
|
||||||
|
* global. There is a call to lp_magicchar() in server.c
|
||||||
|
* that is used to override the initial value.
|
||||||
|
*
|
||||||
|
* MANGLE_BASE - This is the number of characters we use for name mangling.
|
||||||
|
*
|
||||||
|
* basechars - The set characters used for name mangling. This
|
||||||
|
* is static (scope is this file only).
|
||||||
|
*
|
||||||
|
* mangle() - Macro used to select a character from basechars (i.e.,
|
||||||
|
* mangle(n) will return the nth digit, modulo MANGLE_BASE).
|
||||||
|
*
|
||||||
|
* chartest - array 0..255. The index range is the set of all possible
|
||||||
|
* values of a byte. For each byte value, the content is a
|
||||||
|
* two nibble pair. See BASECHAR_MASK and ILLEGAL_MASK,
|
||||||
|
* below.
|
||||||
|
*
|
||||||
|
* ct_initialized - False until the chartest array has been initialized via
|
||||||
|
* a call to init_chartest().
|
||||||
|
*
|
||||||
|
* BASECHAR_MASK - Masks the upper nibble of a one-byte value.
|
||||||
|
*
|
||||||
|
* ILLEGAL_MASK - Masks the lower nibble of a one-byte value.
|
||||||
|
*
|
||||||
|
* isbasecahr() - Given a character, check the chartest array to see
|
||||||
|
* if that character is in the basechars set. This is
|
||||||
|
* faster than using strchr().
|
||||||
|
*
|
||||||
|
* isillegal() - Given a character, check the chartest array to see
|
||||||
|
* if that character is in the illegal characters set.
|
||||||
|
* This is faster than using strchr().
|
||||||
|
*
|
||||||
|
* mangled_cache - Cache header used for storing mangled -> original
|
||||||
|
* reverse maps.
|
||||||
|
*
|
||||||
|
* mc_initialized - False until the mangled_cache structure has been
|
||||||
|
* initialized via a call to reset_mangled_cache().
|
||||||
|
*
|
||||||
|
* MANGLED_CACHE_MAX_ENTRIES - Default maximum number of entries for the
|
||||||
|
* cache. A value of 0 indicates "infinite".
|
||||||
|
*
|
||||||
|
* MANGLED_CACHE_MAX_MEMORY - Default maximum amount of memory for the
|
||||||
|
* cache. When the cache was kept as an array of 256
|
||||||
|
* byte strings, the default cache size was 50 entries.
|
||||||
|
* This required a fixed 12.5Kbytes of memory. The
|
||||||
|
* mangled stack parameter is no longer used (though
|
||||||
|
* this might change). We're now using a fixed 16Kbyte
|
||||||
|
* maximum cache size. This will probably be much more
|
||||||
|
* than 50 entries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char magic_char = '~';
|
||||||
|
|
||||||
|
static char basechars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
|
||||||
|
#define MANGLE_BASE (sizeof(basechars)/sizeof(char)-1)
|
||||||
|
|
||||||
|
static unsigned char chartest[256] = { 0 };
|
||||||
|
static int ct_initialized = FALSE;
|
||||||
|
|
||||||
|
#define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
|
||||||
|
#define BASECHAR_MASK 0xf0
|
||||||
|
#define ILLEGAL_MASK 0x0f
|
||||||
|
#define isbasechar(C) ( (chartest[ ((C) & 0xff) ]) & BASECHAR_MASK )
|
||||||
|
#define isillegal(C) ( (chartest[ ((C) & 0xff) ]) & ILLEGAL_MASK )
|
||||||
|
|
||||||
|
// static ubi_cacheRoot mangled_cache[1] = { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 } };
|
||||||
|
static int mc_initialized = FALSE;
|
||||||
|
#define MANGLED_CACHE_MAX_ENTRIES 0
|
||||||
|
#define MANGLED_CACHE_MAX_MEMORY 16384
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Initialize the static character test array.
|
||||||
|
*
|
||||||
|
* Input: none
|
||||||
|
*
|
||||||
|
* Output: none
|
||||||
|
*
|
||||||
|
* Notes: This function changes (loads) the contents of the <chartest>
|
||||||
|
* array. The scope of <chartest> is this file.
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
static void init_chartest( void )
|
||||||
|
{
|
||||||
|
char *illegalchars = (char *)"*\\/?<>|\":";
|
||||||
|
unsigned char *s;
|
||||||
|
|
||||||
|
memset( (char *)chartest, '\0', 256 );
|
||||||
|
|
||||||
|
for( s = (unsigned char *)illegalchars; *s; s++ )
|
||||||
|
chartest[*s] = ILLEGAL_MASK;
|
||||||
|
|
||||||
|
for( s = (unsigned char *)basechars; *s; s++ )
|
||||||
|
chartest[*s] |= BASECHAR_MASK;
|
||||||
|
|
||||||
|
ct_initialized = TRUE;
|
||||||
|
} /* init_chartest */
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Return True if a name is a special msdos reserved name.
|
||||||
|
*
|
||||||
|
* Input: fname - String containing the name to be tested.
|
||||||
|
*
|
||||||
|
* Output: True, if the name matches one of the list of reserved names.
|
||||||
|
*
|
||||||
|
* Notes: This is a static function called by is_8_3(), below.
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
static int is_reserved_msdos( char *fname )
|
||||||
|
{
|
||||||
|
char upperFname[13];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
strncpy (upperFname, fname, 12);
|
||||||
|
|
||||||
|
/* lpt1.txt and con.txt etc are also illegal */
|
||||||
|
p = strchr(upperFname,'.');
|
||||||
|
if( p )
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
tu( upperFname );
|
||||||
|
p = upperFname + 1;
|
||||||
|
switch( upperFname[0] )
|
||||||
|
{
|
||||||
|
case 'A':
|
||||||
|
if( 0 == strcmp( p, "UX" ) )
|
||||||
|
return( TRUE );
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if( (0 == strcmp( p, "LOCK$" ))
|
||||||
|
|| (0 == strcmp( p, "ON" ))
|
||||||
|
|| (0 == strcmp( p, "OM1" ))
|
||||||
|
|| (0 == strcmp( p, "OM2" ))
|
||||||
|
|| (0 == strcmp( p, "OM3" ))
|
||||||
|
|| (0 == strcmp( p, "OM4" ))
|
||||||
|
)
|
||||||
|
return( TRUE );
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
if( (0 == strcmp( p, "PT1" ))
|
||||||
|
|| (0 == strcmp( p, "PT2" ))
|
||||||
|
|| (0 == strcmp( p, "PT3" ))
|
||||||
|
)
|
||||||
|
return( TRUE );
|
||||||
|
break;
|
||||||
|
case 'N':
|
||||||
|
if( 0 == strcmp( p, "UL" ) )
|
||||||
|
return( TRUE );
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
if( 0 == strcmp( p, "RN" ) )
|
||||||
|
return( TRUE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( FALSE );
|
||||||
|
} /* is_reserved_msdos */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Determine whether or not a given name contains illegal characters, even
|
||||||
|
* long names.
|
||||||
|
*
|
||||||
|
* Input: name - The name to be tested.
|
||||||
|
*
|
||||||
|
* Output: True if an illegal character was found in <name>, else False.
|
||||||
|
*
|
||||||
|
* Notes: This is used to test a name on the host system, long or short,
|
||||||
|
* for characters that would be illegal on most client systems,
|
||||||
|
* particularly DOS and Windows systems. Unix and AmigaOS, for
|
||||||
|
* example, allow a filenames which contain such oddities as
|
||||||
|
* quotes ("). If a name is found which does contain an illegal
|
||||||
|
* character, it is mangled even if it conforms to the 8.3
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
static int is_illegal_name( char *name )
|
||||||
|
{
|
||||||
|
unsigned char *s;
|
||||||
|
int skip;
|
||||||
|
|
||||||
|
if( !name )
|
||||||
|
return( TRUE );
|
||||||
|
|
||||||
|
if( !ct_initialized )
|
||||||
|
init_chartest();
|
||||||
|
|
||||||
|
s = (unsigned char *)name;
|
||||||
|
while( *s )
|
||||||
|
{
|
||||||
|
skip = get_character_len( *s );
|
||||||
|
if( skip != 0 )
|
||||||
|
{
|
||||||
|
s += skip;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( isillegal( *s ) )
|
||||||
|
return( TRUE );
|
||||||
|
else
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return( FALSE );
|
||||||
|
} /* is_illegal_name */
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Return True if the name *could be* a mangled name.
|
||||||
|
*
|
||||||
|
* Input: s - A path name - in UNIX pathname format.
|
||||||
|
*
|
||||||
|
* Output: True if the name matches the pattern described below in the
|
||||||
|
* notes, else False.
|
||||||
|
*
|
||||||
|
* Notes: The input name is *not* tested for 8.3 compliance. This must be
|
||||||
|
* done separately. This function returns true if the name contains
|
||||||
|
* a magic character followed by excactly two characters from the
|
||||||
|
* basechars list (above), which in turn are followed either by the
|
||||||
|
* nul (end of string) byte or a dot (extension) or by a '/' (end of
|
||||||
|
* a directory name).
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
int is_mangled( char *s )
|
||||||
|
{
|
||||||
|
char *magic;
|
||||||
|
|
||||||
|
if( !ct_initialized )
|
||||||
|
init_chartest();
|
||||||
|
|
||||||
|
magic = strchr( s, magic_char );
|
||||||
|
while( magic && magic[1] && magic[2] ) /* 3 chars, 1st is magic. */
|
||||||
|
{
|
||||||
|
if( ('.' == magic[3] || '/' == magic[3] || !(magic[3])) /* Ends with '.' or nul or '/' ? */
|
||||||
|
&& isbasechar( toupper(magic[1]) ) /* is 2nd char basechar? */
|
||||||
|
&& isbasechar( toupper(magic[2]) ) ) /* is 3rd char basechar? */
|
||||||
|
return( TRUE ); /* If all above, then true, */
|
||||||
|
magic = strchr( magic+1, magic_char ); /* else seek next magic. */
|
||||||
|
}
|
||||||
|
return( FALSE );
|
||||||
|
} /* is_mangled */
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Return True if the name is a valid DOS name in 8.3 DOS format.
|
||||||
|
*
|
||||||
|
* Input: fname - File name to be checked.
|
||||||
|
* check_case - If True, and if case_mangle is True, then the
|
||||||
|
* name will be checked to see if all characters
|
||||||
|
* are the correct case. See case_mangle and
|
||||||
|
* case_default above.
|
||||||
|
*
|
||||||
|
* Output: True if the name is a valid DOS name, else FALSE.
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
int is_8_3( char *fname, int check_case )
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
int l;
|
||||||
|
int skip;
|
||||||
|
char *p;
|
||||||
|
char *dot_pos;
|
||||||
|
char *slash_pos = strrchr( fname, '/' );
|
||||||
|
|
||||||
|
/* If there is a directory path, skip it. */
|
||||||
|
if( slash_pos )
|
||||||
|
fname = slash_pos + 1;
|
||||||
|
len = strlen( fname );
|
||||||
|
|
||||||
|
Syslog('f', "Checking %s for 8.3\n", fname);
|
||||||
|
|
||||||
|
/* Can't be 0 chars or longer than 12 chars */
|
||||||
|
if( (len == 0) || (len > 12) )
|
||||||
|
return( FALSE );
|
||||||
|
|
||||||
|
/* Mustn't be an MS-DOS Special file such as lpt1 or even lpt1.txt */
|
||||||
|
if( is_reserved_msdos( fname ) )
|
||||||
|
return( FALSE );
|
||||||
|
|
||||||
|
/* Check that all characters are the correct case, if asked to do so. */
|
||||||
|
if( check_case && case_mangle )
|
||||||
|
{
|
||||||
|
switch( case_default )
|
||||||
|
{
|
||||||
|
case CASE_LOWER:
|
||||||
|
if( strhasupper( fname ) )
|
||||||
|
return(FALSE);
|
||||||
|
break;
|
||||||
|
case CASE_UPPER:
|
||||||
|
if( strhaslower( fname ) )
|
||||||
|
return(FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't contain invalid dos chars */
|
||||||
|
/* Windows use the ANSI charset.
|
||||||
|
But filenames are translated in the PC charset.
|
||||||
|
This Translation may be more or less relaxed depending
|
||||||
|
the Windows application. */
|
||||||
|
|
||||||
|
/* %%% A nice improvment to name mangling would be to translate
|
||||||
|
filename to ANSI charset on the smb server host */
|
||||||
|
|
||||||
|
p = fname;
|
||||||
|
dot_pos = NULL;
|
||||||
|
while( *p )
|
||||||
|
{
|
||||||
|
if( (skip = get_character_len( *p )) != 0 )
|
||||||
|
p += skip;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( *p == '.' && !dot_pos )
|
||||||
|
dot_pos = (char *)p;
|
||||||
|
else
|
||||||
|
if( !isdoschar( *p ) )
|
||||||
|
return( FALSE );
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no dot and less than 9 means OK */
|
||||||
|
if( !dot_pos )
|
||||||
|
return( len <= 8 );
|
||||||
|
|
||||||
|
l = PTR_DIFF( dot_pos, fname );
|
||||||
|
|
||||||
|
/* base must be at least 1 char except special cases . and .. */
|
||||||
|
if( l == 0 )
|
||||||
|
return( 0 == strcmp( fname, "." ) || 0 == strcmp( fname, ".." ) );
|
||||||
|
|
||||||
|
/* base can't be greater than 8 */
|
||||||
|
if( l > 8 )
|
||||||
|
return( FALSE );
|
||||||
|
|
||||||
|
/* see smb.conf(5) for a description of the 'strip dot' parameter. */
|
||||||
|
if( lp_strip_dot()
|
||||||
|
&& len - l == 1
|
||||||
|
&& !strchr( dot_pos + 1, '.' ) )
|
||||||
|
{
|
||||||
|
*dot_pos = 0;
|
||||||
|
return( TRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extension must be between 1 and 3 */
|
||||||
|
if( (len - l < 2 ) || (len - l > 4) )
|
||||||
|
return( FALSE );
|
||||||
|
|
||||||
|
/* extensions may not have a dot */
|
||||||
|
if( strchr( dot_pos+1, '.' ) )
|
||||||
|
return( FALSE );
|
||||||
|
|
||||||
|
/* must be in 8.3 format */
|
||||||
|
return( TRUE );
|
||||||
|
} /* is_8_3 */
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Compare two cache keys and return a value indicating their ordinal
|
||||||
|
* relationship.
|
||||||
|
*
|
||||||
|
* Input: ItemPtr - Pointer to a comparison key. In this case, this will
|
||||||
|
* be a mangled name string.
|
||||||
|
* NodePtr - Pointer to a node in the cache. The node structure
|
||||||
|
* will be followed in memory by a mangled name string.
|
||||||
|
*
|
||||||
|
* Output: A signed integer, as follows:
|
||||||
|
* (x < 0) <==> Key1 less than Key2
|
||||||
|
* (x == 0) <==> Key1 equals Key2
|
||||||
|
* (x > 0) <==> Key1 greater than Key2
|
||||||
|
*
|
||||||
|
* Notes: This is a ubiqx-style comparison routine. See ubi_BinTree for
|
||||||
|
* more info.
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
static signed int cache_compare( ubi_btItemPtr ItemPtr, ubi_btNodePtr NodePtr )
|
||||||
|
{
|
||||||
|
char *Key1 = (char *)ItemPtr;
|
||||||
|
char *Key2 = (char *)(((ubi_cacheEntryPtr)NodePtr) + 1);
|
||||||
|
|
||||||
|
return( StrCaseCmp( Key1, Key2 ) );
|
||||||
|
} /* cache_compare */
|
||||||
|
|
||||||
|
/* ************************************************************************** **
|
||||||
|
* Free a cache entry.
|
||||||
|
*
|
||||||
|
* Input: WarrenZevon - Pointer to the entry that is to be returned to
|
||||||
|
* Nirvana.
|
||||||
|
* Output: none.
|
||||||
|
*
|
||||||
|
* Notes: This function gets around the possibility that the standard
|
||||||
|
* free() function may be implemented as a macro, or other evil
|
||||||
|
* subversions (oh, so much fun).
|
||||||
|
*
|
||||||
|
* ************************************************************************** **
|
||||||
|
*/
|
||||||
|
static void cache_free_entry( ubi_trNodePtr WarrenZevon )
|
||||||
|
{
|
||||||
|
ZERO_STRUCTP(WarrenZevon);
|
||||||
|
free( WarrenZevon );
|
||||||
|
} /* cache_free_entry */
|
||||||
|
|
||||||
|
1133
lib/ubi_BinTree.c
Normal file
1133
lib/ubi_BinTree.c
Normal file
File diff suppressed because it is too large
Load Diff
859
lib/ubi_BinTree.h
Normal file
859
lib/ubi_BinTree.h
Normal file
@ -0,0 +1,859 @@
|
|||||||
|
#ifndef UBI_BINTREE_H
|
||||||
|
#define UBI_BINTREE_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_BinTree.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1991-1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module implements a simple binary tree.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_BinTree.h,v
|
||||||
|
* Revision 4.10 2000/06/06 20:38:40 crh
|
||||||
|
* In the ReplaceNode() function, the old node header was being copied
|
||||||
|
* to the new node header using a byte-by-byte copy. This was causing
|
||||||
|
* the 'insure' software testing program to report a memory leak. The
|
||||||
|
* fix was to do a simple assignement: *newnode = *oldnode;
|
||||||
|
* This quieted the (errant) memory leak reports and is probably a bit
|
||||||
|
* faster than the bytewise copy.
|
||||||
|
*
|
||||||
|
* Revision 4.9 2000/01/08 23:24:30 crh
|
||||||
|
* Clarified a variety of if( pointer ) lines, replacing them with
|
||||||
|
* if( NULL != pointer ). This is more correct, and I have heard
|
||||||
|
* of at least one (obscure?) system out there that uses a non-zero
|
||||||
|
* value for NULL.
|
||||||
|
* Also, speed improvement in Neighbor(). It was comparing pointers
|
||||||
|
* when it could have compared two gender values. The pointer
|
||||||
|
* comparison was somewhat indirect (does pointer equal the pointer
|
||||||
|
* of the parent of the node pointed to by pointer). Urq.
|
||||||
|
*
|
||||||
|
* Revision 4.8 1999/09/22 03:40:30 crh
|
||||||
|
* Modified ubi_btTraverse() and ubi_btKillTree(). They now return an
|
||||||
|
* unsigned long indicating the number of nodes processed. The change
|
||||||
|
* is subtle. An empty tree formerly returned False, and now returns
|
||||||
|
* zero.
|
||||||
|
*
|
||||||
|
* Revision 4.7 1998/10/21 06:15:07 crh
|
||||||
|
* Fixed bugs in FirstOf() and LastOf() reported by Massimo Campostrini.
|
||||||
|
* See function comments.
|
||||||
|
*
|
||||||
|
* Revision 4.6 1998/07/25 17:02:10 crh
|
||||||
|
* Added the ubi_trNewTree() macro.
|
||||||
|
*
|
||||||
|
* Revision 4.5 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 4.4 1998/06/03 17:42:46 crh
|
||||||
|
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
|
||||||
|
* included by all of the binary tree files.
|
||||||
|
*
|
||||||
|
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
|
||||||
|
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
|
||||||
|
* of tree types by simply changing a header. Unfortunately, the
|
||||||
|
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
|
||||||
|
* conflict if used together. You must either choose a single tree
|
||||||
|
* type, or use the underlying function calls directly. Compare
|
||||||
|
* the two header files for more information.
|
||||||
|
*
|
||||||
|
* Revision 4.3 1998/06/02 01:28:43 crh
|
||||||
|
* Changed ubi_null.h to sys_include.h to make it more generic.
|
||||||
|
*
|
||||||
|
* Revision 4.2 1998/05/20 04:32:36 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
* Also, the balance and gender fields of the node were declared as
|
||||||
|
* signed char. As I understand it, at least one SunOS or Solaris
|
||||||
|
* compiler doesn't like "signed char". The declarations were
|
||||||
|
* wrong anyway, so I changed them to simple "char".
|
||||||
|
*
|
||||||
|
* Revision 4.1 1998/03/31 06:13:47 crh
|
||||||
|
* Thomas Aglassinger sent E'mail pointing out errors in the
|
||||||
|
* dereferencing of function pointers, and a missing typecast.
|
||||||
|
* Thanks, Thomas!
|
||||||
|
*
|
||||||
|
* Revision 4.0 1998/03/10 03:16:04 crh
|
||||||
|
* Added the AVL field 'balance' to the ubi_btNode structure. This means
|
||||||
|
* that all BinTree modules now use the same basic node structure, which
|
||||||
|
* greatly simplifies the AVL module.
|
||||||
|
* Decided that this was a big enough change to justify a new major revision
|
||||||
|
* number. 3.0 was an error, so we're at 4.0.
|
||||||
|
*
|
||||||
|
* Revision 2.6 1998/01/24 06:27:30 crh
|
||||||
|
* Added ubi_trCount() macro.
|
||||||
|
*
|
||||||
|
* Revision 2.5 1997/12/23 03:59:21 crh
|
||||||
|
* In this version, all constants & macros defined in the header file have
|
||||||
|
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
|
||||||
|
* when run with '-pedantic -fsyntax-only -Wall'.
|
||||||
|
*
|
||||||
|
* Revision 2.4 1997/07/26 04:11:14 crh
|
||||||
|
* + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
|
||||||
|
* and ubi_trFALSE.
|
||||||
|
* + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
|
||||||
|
* + There used to be something called "ubi_TypeDefs.h". I got rid of it.
|
||||||
|
* + Added function ubi_btLeafNode().
|
||||||
|
*
|
||||||
|
* Revision 2.3 1997/06/03 05:15:27 crh
|
||||||
|
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
|
||||||
|
* Also changed the interface to function InitTree(). See the comments
|
||||||
|
* for this function for more information.
|
||||||
|
*
|
||||||
|
* Revision 2.2 1995/10/03 22:00:40 CRH
|
||||||
|
* Ubisized!
|
||||||
|
*
|
||||||
|
* Revision 2.1 95/03/09 23:43:46 CRH
|
||||||
|
* Added the ModuleID static string and function. These modules are now
|
||||||
|
* self-identifying.
|
||||||
|
*
|
||||||
|
* Revision 2.0 95/02/27 22:00:33 CRH
|
||||||
|
* Revision 2.0 of this program includes the following changes:
|
||||||
|
*
|
||||||
|
* 1) A fix to a major typo in the RepaceNode() function.
|
||||||
|
* 2) The addition of the static function Border().
|
||||||
|
* 3) The addition of the public functions FirstOf() and LastOf(), which
|
||||||
|
* use Border(). These functions are used with trees that allow
|
||||||
|
* duplicate keys.
|
||||||
|
* 4) A complete rewrite of the Locate() function. Locate() now accepts
|
||||||
|
* a "comparison" operator.
|
||||||
|
* 5) Overall enhancements to both code and comments.
|
||||||
|
*
|
||||||
|
* I decided to give this a new major rev number because the interface has
|
||||||
|
* changed. In particular, there are two new functions, and changes to the
|
||||||
|
* Locate() function.
|
||||||
|
*
|
||||||
|
* Revision 1.0 93/10/15 22:55:04 CRH
|
||||||
|
* With this revision, I have added a set of #define's that provide a single,
|
||||||
|
* standard API to all existing tree modules. Until now, each of the three
|
||||||
|
* existing modules had a different function and typedef prefix, as follows:
|
||||||
|
*
|
||||||
|
* Module Prefix
|
||||||
|
* ubi_BinTree ubi_bt
|
||||||
|
* ubi_AVLtree ubi_avl
|
||||||
|
* ubi_SplayTree ubi_spt
|
||||||
|
*
|
||||||
|
* To further complicate matters, only those portions of the base module
|
||||||
|
* (ubi_BinTree) that were superceeded in the new module had the new names.
|
||||||
|
* For example, if you were using ubi_SplayTree, the locate function was
|
||||||
|
* called "ubi_sptLocate", but the next and previous functions remained
|
||||||
|
* "ubi_btNext" and "ubi_btPrev".
|
||||||
|
*
|
||||||
|
* This was not too terrible if you were familiar with the modules and knew
|
||||||
|
* exactly which tree model you wanted to use. If you wanted to be able to
|
||||||
|
* change modules (for speed comparisons, etc), things could get messy very
|
||||||
|
* quickly.
|
||||||
|
*
|
||||||
|
* So, I have added a set of defined names that get redefined in any of the
|
||||||
|
* descendant modules. To use this standardized interface in your code,
|
||||||
|
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
|
||||||
|
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
|
||||||
|
* datatype names for the module that you are using. Just remember to
|
||||||
|
* include the header for that module in your program file. Because these
|
||||||
|
* names are handled by the preprocessor, there is no added run-time
|
||||||
|
* overhead.
|
||||||
|
*
|
||||||
|
* Note that the original names do still exist, and can be used if you wish
|
||||||
|
* to write code directly to a specific module. This should probably only be
|
||||||
|
* done if you are planning to implement a new descendant type, such as
|
||||||
|
* red/black trees. CRH
|
||||||
|
*
|
||||||
|
* V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH).
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Macros and constants.
|
||||||
|
*
|
||||||
|
* General purpose:
|
||||||
|
* ubi_trTRUE - Boolean TRUE.
|
||||||
|
* ubi_trFALSE - Boolean FALSE.
|
||||||
|
*
|
||||||
|
* Flags used in the tree header:
|
||||||
|
* ubi_trOVERWRITE - This flag indicates that an existing node may be
|
||||||
|
* overwritten by a new node with a matching key.
|
||||||
|
* ubi_trDUPKEY - This flag indicates that the tree allows duplicate
|
||||||
|
* keys. If the tree does allow duplicates, the
|
||||||
|
* overwrite flag is ignored.
|
||||||
|
*
|
||||||
|
* Node link array index constants: (Each node has an array of three
|
||||||
|
* pointers. One to the left, one to the right, and one back to the
|
||||||
|
* parent.)
|
||||||
|
* ubi_trLEFT - Left child pointer.
|
||||||
|
* ubi_trPARENT - Parent pointer.
|
||||||
|
* ubi_trRIGHT - Right child pointer.
|
||||||
|
* ubi_trEQUAL - Synonym for PARENT.
|
||||||
|
*
|
||||||
|
* ubi_trCompOps: These values are used in the ubi_trLocate() function.
|
||||||
|
* ubi_trLT - request the first instance of the greatest key less than
|
||||||
|
* the search key.
|
||||||
|
* ubi_trLE - request the first instance of the greatest key that is less
|
||||||
|
* than or equal to the search key.
|
||||||
|
* ubi_trEQ - request the first instance of key that is equal to the
|
||||||
|
* search key.
|
||||||
|
* ubi_trGE - request the first instance of a key that is greater than
|
||||||
|
* or equal to the search key.
|
||||||
|
* ubi_trGT - request the first instance of the first key that is greater
|
||||||
|
* than the search key.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_trTRUE 0xFF
|
||||||
|
#define ubi_trFALSE 0x00
|
||||||
|
|
||||||
|
#define ubi_trOVERWRITE 0x01 /* Turn on allow overwrite */
|
||||||
|
#define ubi_trDUPKEY 0x02 /* Turn on allow duplicate keys */
|
||||||
|
|
||||||
|
/* Pointer array index constants... */
|
||||||
|
#define ubi_trLEFT 0x00
|
||||||
|
#define ubi_trPARENT 0x01
|
||||||
|
#define ubi_trRIGHT 0x02
|
||||||
|
#define ubi_trEQUAL ubi_trPARENT
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ubi_trLT = 1,
|
||||||
|
ubi_trLE,
|
||||||
|
ubi_trEQ,
|
||||||
|
ubi_trGE,
|
||||||
|
ubi_trGT
|
||||||
|
} ubi_trCompOps;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* These three macros allow simple manipulation of pointer index values (LEFT,
|
||||||
|
* RIGHT, and PARENT).
|
||||||
|
*
|
||||||
|
* Normalize() - converts {LEFT, PARENT, RIGHT} into {-1, 0 ,1}. C
|
||||||
|
* uses {negative, zero, positive} values to indicate
|
||||||
|
* {less than, equal to, greater than}.
|
||||||
|
* AbNormal() - converts {negative, zero, positive} to {LEFT, PARENT,
|
||||||
|
* RIGHT} (opposite of Normalize()). Note: C comparison
|
||||||
|
* functions, such as strcmp(), return {negative, zero,
|
||||||
|
* positive} values, which are not necessarily {-1, 0,
|
||||||
|
* 1}. This macro uses the the ubi_btSgn() function to
|
||||||
|
* compensate.
|
||||||
|
* RevWay() - converts LEFT to RIGHT and RIGHT to LEFT. PARENT (EQUAL)
|
||||||
|
* is left as is.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
#define ubi_trNormalize(W) ((char)( (W) - ubi_trEQUAL ))
|
||||||
|
#define ubi_trAbNormal(W) ((char)( ((char)ubi_btSgn( (long)(W) )) \
|
||||||
|
+ ubi_trEQUAL ))
|
||||||
|
#define ubi_trRevWay(W) ((char)( ubi_trEQUAL - ((W) - ubi_trEQUAL) ))
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* These macros allow us to quickly read the values of the OVERWRITE and
|
||||||
|
* DUPlicate KEY bits of the tree root flags field.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
#define ubi_trDups_OK(A) \
|
||||||
|
((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
|
||||||
|
#define ubi_trOvwt_OK(A) \
|
||||||
|
((ubi_trOVERWRITE & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Additional Macros...
|
||||||
|
*
|
||||||
|
* ubi_trCount() - Given a pointer to a tree root, this macro returns the
|
||||||
|
* number of nodes currently in the tree.
|
||||||
|
*
|
||||||
|
* ubi_trNewTree() - This macro makes it easy to declare and initialize a
|
||||||
|
* tree header in one step. The line
|
||||||
|
*
|
||||||
|
* static ubi_trNewTree( MyTree, cmpfn, ubi_trDUPKEY );
|
||||||
|
*
|
||||||
|
* is equivalent to
|
||||||
|
*
|
||||||
|
* static ubi_trRoot MyTree[1]
|
||||||
|
* = {{ NULL, cmpfn, 0, ubi_trDUPKEY }};
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_trCount( R ) (((ubi_trRootPtr)(R))->count)
|
||||||
|
|
||||||
|
#define ubi_trNewTree( N, C, F ) ubi_trRoot (N)[1] = {{ NULL, (C), 0, (F) }}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Typedefs...
|
||||||
|
*
|
||||||
|
* ubi_trBool - Your typcial true or false...
|
||||||
|
*
|
||||||
|
* Item Pointer: The ubi_btItemPtr is a generic pointer. It is used to
|
||||||
|
* indicate a key that is being searched for within the tree.
|
||||||
|
* Searching occurs whenever the ubi_trFind(), ubi_trLocate(),
|
||||||
|
* or ubi_trInsert() functions are called.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef unsigned char ubi_trBool;
|
||||||
|
|
||||||
|
typedef void *ubi_btItemPtr; /* A pointer to key data within a node. */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- **
|
||||||
|
* Binary Tree Node Structure: This structure defines the basic elements of
|
||||||
|
* the tree nodes. In general you *SHOULD NOT PLAY WITH THESE FIELDS*!
|
||||||
|
* But, of course, I have to put the structure into this header so that
|
||||||
|
* you can use it as a building block.
|
||||||
|
*
|
||||||
|
* The fields are as follows:
|
||||||
|
* Link - an array of pointers. These pointers are manipulated by
|
||||||
|
* the BT routines. The pointers indicate the left and right
|
||||||
|
* child nodes and the parent node. By keeping track of the
|
||||||
|
* parent pointer, we avoid the need for recursive routines or
|
||||||
|
* hand-tooled stacks to keep track of our path back to the
|
||||||
|
* root. The use of these pointers is subject to change without
|
||||||
|
* notice.
|
||||||
|
* gender - a one-byte field indicating whether the node is the RIGHT or
|
||||||
|
* LEFT child of its parent. If the node is the root of the
|
||||||
|
* tree, gender will be PARENT.
|
||||||
|
* balance - only used by the AVL tree module. This field indicates
|
||||||
|
* the height balance at a given node. See ubi_AVLtree for
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
typedef struct ubi_btNodeStruct {
|
||||||
|
struct ubi_btNodeStruct *Link[ 3 ];
|
||||||
|
char gender;
|
||||||
|
char balance;
|
||||||
|
} ubi_btNode;
|
||||||
|
|
||||||
|
typedef ubi_btNode *ubi_btNodePtr; /* Pointer to an ubi_btNode structure. */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- **
|
||||||
|
* The next three typedefs define standard function types used by the binary
|
||||||
|
* tree management routines. In particular:
|
||||||
|
*
|
||||||
|
* ubi_btCompFunc is a pointer to a comparison function. Comparison
|
||||||
|
* functions are passed an ubi_btItemPtr and an
|
||||||
|
* ubi_btNodePtr. They return a value that is (<0), 0,
|
||||||
|
* or (>0) to indicate that the Item is (respectively)
|
||||||
|
* "less than", "equal to", or "greater than" the Item
|
||||||
|
* contained within the node. (See ubi_btInitTree()).
|
||||||
|
* ubi_btActionRtn is a pointer to a function that may be called for each
|
||||||
|
* node visited when performing a tree traversal (see
|
||||||
|
* ubi_btTraverse()). The function will be passed two
|
||||||
|
* parameters: the first is a pointer to a node in the
|
||||||
|
* tree, the second is a generic pointer that may point to
|
||||||
|
* anything that you like.
|
||||||
|
* ubi_btKillNodeRtn is a pointer to a function that will deallocate the
|
||||||
|
* memory used by a node (see ubi_btKillTree()). Since
|
||||||
|
* memory management is left up to you, deallocation may
|
||||||
|
* mean anything that you want it to mean. Just remember
|
||||||
|
* that the tree *will* be destroyed and that none of the
|
||||||
|
* node pointers will be valid any more.
|
||||||
|
* ------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int (*ubi_btCompFunc)( ubi_btItemPtr, ubi_btNodePtr );
|
||||||
|
|
||||||
|
typedef void (*ubi_btActionRtn)( ubi_btNodePtr, void * );
|
||||||
|
|
||||||
|
typedef void (*ubi_btKillNodeRtn)( ubi_btNodePtr );
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Tree Root Structure: This structure gives us a convenient handle for
|
||||||
|
* accessing whole binary trees. The fields are:
|
||||||
|
* root - A pointer to the root node of the tree.
|
||||||
|
* count - A count of the number of nodes stored in the tree.
|
||||||
|
* cmp - A pointer to the comparison routine to be used when building or
|
||||||
|
* searching the tree.
|
||||||
|
* flags - A set of bit flags. Two flags are currently defined:
|
||||||
|
*
|
||||||
|
* ubi_trOVERWRITE - If set, this flag indicates that a new node should
|
||||||
|
* (bit 0x01) overwrite an old node if the two have identical
|
||||||
|
* keys (ie., the keys are equal).
|
||||||
|
* ubi_trDUPKEY - If set, this flag indicates that the tree is
|
||||||
|
* (bit 0x02) allowed to contain nodes with duplicate keys.
|
||||||
|
*
|
||||||
|
* NOTE: ubi_trInsert() tests ubi_trDUPKEY before ubi_trOVERWRITE.
|
||||||
|
*
|
||||||
|
* All of these values are set when you initialize the root structure by
|
||||||
|
* calling ubi_trInitTree().
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ubi_btNodePtr root; /* A pointer to the root node of the tree */
|
||||||
|
ubi_btCompFunc cmp; /* A pointer to the tree's comparison function */
|
||||||
|
unsigned long count; /* A count of the number of nodes in the tree */
|
||||||
|
char flags; /* Overwrite Y|N, Duplicate keys Y|N... */
|
||||||
|
} ubi_btRoot;
|
||||||
|
|
||||||
|
typedef ubi_btRoot *ubi_btRootPtr; /* Pointer to an ubi_btRoot structure. */
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Function Prototypes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
long ubi_btSgn( long x );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
|
||||||
|
*
|
||||||
|
* Input: x - a signed long integer value.
|
||||||
|
*
|
||||||
|
* Output: the "sign" of x, represented as follows:
|
||||||
|
* -1 == negative
|
||||||
|
* 0 == zero (no sign)
|
||||||
|
* 1 == positive
|
||||||
|
*
|
||||||
|
* Note: This utility is provided in order to facilitate the conversion
|
||||||
|
* of C comparison function return values into BinTree direction
|
||||||
|
* values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the
|
||||||
|
* AbNormal() conversion macro!
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a tree node.
|
||||||
|
*
|
||||||
|
* Input: a pointer to a ubi_btNode structure to be initialized.
|
||||||
|
* Output: a pointer to the initialized ubi_btNode structure (ie. the
|
||||||
|
* same as the input pointer).
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btCompFunc CompFunc,
|
||||||
|
char Flags );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize the fields of a Tree Root header structure.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to an ubi_btRoot structure to be
|
||||||
|
* initialized.
|
||||||
|
* CompFunc - a pointer to a comparison function that will be used
|
||||||
|
* whenever nodes in the tree must be compared against
|
||||||
|
* outside values.
|
||||||
|
* Flags - One bytes worth of flags. Flags include
|
||||||
|
* ubi_trOVERWRITE and ubi_trDUPKEY. See the header
|
||||||
|
* file for more info.
|
||||||
|
*
|
||||||
|
* Output: a pointer to the initialized ubi_btRoot structure (ie. the
|
||||||
|
* same value as RootPtr).
|
||||||
|
*
|
||||||
|
* Note: The interface to this function has changed from that of
|
||||||
|
* previous versions. The <Flags> parameter replaces two
|
||||||
|
* boolean parameters that had the same basic effect.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr NewNode,
|
||||||
|
ubi_btItemPtr ItemPtr,
|
||||||
|
ubi_btNodePtr *OldNode );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function uses a non-recursive algorithm to add a new element to the
|
||||||
|
* tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
|
||||||
|
* the root of the tree to which NewNode is to be added.
|
||||||
|
* NewNode - a pointer to an ubi_btNode structure that is NOT
|
||||||
|
* part of any tree.
|
||||||
|
* ItemPtr - A pointer to the sort key that is stored within
|
||||||
|
* *NewNode. ItemPtr MUST point to information stored
|
||||||
|
* in *NewNode or an EXACT DUPLICATE. The key data
|
||||||
|
* indicated by ItemPtr is used to place the new node
|
||||||
|
* into the tree.
|
||||||
|
* OldNode - a pointer to an ubi_btNodePtr. When searching
|
||||||
|
* the tree, a duplicate node may be found. If
|
||||||
|
* duplicates are allowed, then the new node will
|
||||||
|
* be simply placed into the tree. If duplicates
|
||||||
|
* are not allowed, however, then one of two things
|
||||||
|
* may happen.
|
||||||
|
* 1) if overwritting *is not* allowed, this
|
||||||
|
* function will return FALSE (indicating that
|
||||||
|
* the new node could not be inserted), and
|
||||||
|
* *OldNode will point to the duplicate that is
|
||||||
|
* still in the tree.
|
||||||
|
* 2) if overwritting *is* allowed, then this
|
||||||
|
* function will swap **OldNode for *NewNode.
|
||||||
|
* In this case, *OldNode will point to the node
|
||||||
|
* that was removed (thus allowing you to free
|
||||||
|
* the node).
|
||||||
|
* ** If you are using overwrite mode, ALWAYS **
|
||||||
|
* ** check the return value of this parameter! **
|
||||||
|
* Note: You may pass NULL in this parameter, the
|
||||||
|
* function knows how to cope. If you do this,
|
||||||
|
* however, there will be no way to return a
|
||||||
|
* pointer to an old (ie. replaced) node (which is
|
||||||
|
* a problem if you are using overwrite mode).
|
||||||
|
*
|
||||||
|
* Output: a boolean value indicating success or failure. The function
|
||||||
|
* will return FALSE if the node could not be added to the tree.
|
||||||
|
* Such failure will only occur if duplicates are not allowed,
|
||||||
|
* nodes cannot be overwritten, AND a duplicate key was found
|
||||||
|
* within the tree.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr DeadNode );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function removes the indicated node from the tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - A pointer to the header of the tree that contains
|
||||||
|
* the node to be removed.
|
||||||
|
* DeadNode - A pointer to the node that will be removed.
|
||||||
|
*
|
||||||
|
* Output: This function returns a pointer to the node that was removed
|
||||||
|
* from the tree (ie. the same as DeadNode).
|
||||||
|
*
|
||||||
|
* Note: The node MUST be in the tree indicated by RootPtr. If not,
|
||||||
|
* strange and evil things will happen to your trees.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe,
|
||||||
|
ubi_trCompOps CompOp );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* The purpose of ubi_btLocate() is to find a node or set of nodes given
|
||||||
|
* a target value and a "comparison operator". The Locate() function is
|
||||||
|
* more flexible and (in the case of trees that may contain dupicate keys)
|
||||||
|
* more precise than the ubi_btFind() function. The latter is faster,
|
||||||
|
* but it only searches for exact matches and, if the tree contains
|
||||||
|
* duplicates, Find() may return a pointer to any one of the duplicate-
|
||||||
|
* keyed records.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - A pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - An ubi_btItemPtr that indicates the key for which to
|
||||||
|
* search.
|
||||||
|
* CompOp - One of the following:
|
||||||
|
* CompOp Return a pointer to the node with
|
||||||
|
* ------ ---------------------------------
|
||||||
|
* ubi_trLT - the last key value that is less
|
||||||
|
* than FindMe.
|
||||||
|
* ubi_trLE - the first key matching FindMe, or
|
||||||
|
* the last key that is less than
|
||||||
|
* FindMe.
|
||||||
|
* ubi_trEQ - the first key matching FindMe.
|
||||||
|
* ubi_trGE - the first key matching FindMe, or the
|
||||||
|
* first key greater than FindMe.
|
||||||
|
* ubi_trGT - the first key greater than FindMe.
|
||||||
|
* Output:
|
||||||
|
* A pointer to the node matching the criteria listed above under
|
||||||
|
* CompOp, or NULL if no node matched the criteria.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* In the case of trees with duplicate keys, Locate() will behave as
|
||||||
|
* follows:
|
||||||
|
*
|
||||||
|
* Find: 3 Find: 3
|
||||||
|
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
|
||||||
|
* ^ ^ ^ ^ ^
|
||||||
|
* LT EQ GT LE GE
|
||||||
|
*
|
||||||
|
* That is, when returning a pointer to a node with a key that is LESS
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* LAST matching node.
|
||||||
|
* When returning a pointer to a node with a key that is GREATER
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* FIRST matching node.
|
||||||
|
*
|
||||||
|
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function performs a non-recursive search of a tree for any node
|
||||||
|
* matching a specific key.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - a pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - a pointer to the key value for which to search.
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* A pointer to a node with a key that matches the key indicated by
|
||||||
|
* FindMe, or NULL if no such node was found.
|
||||||
|
*
|
||||||
|
* Note: In a tree that allows duplicates, the pointer returned *might
|
||||||
|
* not* point to the (sequentially) first occurance of the
|
||||||
|
* desired key. In such a tree, it may be more useful to use
|
||||||
|
* ubi_btLocate().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btNext( ubi_btNodePtr P );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given the node indicated by P, find the (sorted order) Next node in the
|
||||||
|
* tree.
|
||||||
|
* Input: P - a pointer to a node that exists in a binary tree.
|
||||||
|
* Output: A pointer to the "next" node in the tree, or NULL if P pointed
|
||||||
|
* to the "last" node in the tree or was NULL.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given the node indicated by P, find the (sorted order) Previous node in
|
||||||
|
* the tree.
|
||||||
|
* Input: P - a pointer to a node that exists in a binary tree.
|
||||||
|
* Output: A pointer to the "previous" node in the tree, or NULL if P
|
||||||
|
* pointed to the "first" node in the tree or was NULL.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given the node indicated by P, find the (sorted order) First node in the
|
||||||
|
* subtree of which *P is the root.
|
||||||
|
* Input: P - a pointer to a node that exists in a binary tree.
|
||||||
|
* Output: A pointer to the "first" node in a subtree that has *P as its
|
||||||
|
* root. This function will return NULL only if P is NULL.
|
||||||
|
* Note: In general, you will be passing in the value of the root field
|
||||||
|
* of an ubi_btRoot structure.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btLast( ubi_btNodePtr P );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given the node indicated by P, find the (sorted order) Last node in the
|
||||||
|
* subtree of which *P is the root.
|
||||||
|
* Input: P - a pointer to a node that exists in a binary tree.
|
||||||
|
* Output: A pointer to the "last" node in a subtree that has *P as its
|
||||||
|
* root. This function will return NULL only if P is NULL.
|
||||||
|
* Note: In general, you will be passing in the value of the root field
|
||||||
|
* of an ubi_btRoot structure.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr MatchMe,
|
||||||
|
ubi_btNodePtr p );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given a tree that a allows duplicate keys, and a pointer to a node in
|
||||||
|
* the tree, this function will return a pointer to the first (traversal
|
||||||
|
* order) node with the same key value.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - A pointer to the root of the tree.
|
||||||
|
* MatchMe - A pointer to the key value. This should probably
|
||||||
|
* point to the key within node *p.
|
||||||
|
* p - A pointer to a node in the tree.
|
||||||
|
* Output: A pointer to the first node in the set of nodes with keys
|
||||||
|
* matching <FindMe>.
|
||||||
|
* Notes: Node *p MUST be in the set of nodes with keys matching
|
||||||
|
* <FindMe>. If not, this function will return NULL.
|
||||||
|
*
|
||||||
|
* 4.7: Bug found & fixed by Massimo Campostrini,
|
||||||
|
* Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr MatchMe,
|
||||||
|
ubi_btNodePtr p );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Given a tree that a allows duplicate keys, and a pointer to a node in
|
||||||
|
* the tree, this function will return a pointer to the last (traversal
|
||||||
|
* order) node with the same key value.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - A pointer to the root of the tree.
|
||||||
|
* MatchMe - A pointer to the key value. This should probably
|
||||||
|
* point to the key within node *p.
|
||||||
|
* p - A pointer to a node in the tree.
|
||||||
|
* Output: A pointer to the last node in the set of nodes with keys
|
||||||
|
* matching <FindMe>.
|
||||||
|
* Notes: Node *p MUST be in the set of nodes with keys matching
|
||||||
|
* <FindMe>. If not, this function will return NULL.
|
||||||
|
*
|
||||||
|
* 4.7: Bug found & fixed by Massimo Campostrini,
|
||||||
|
* Istituto Nazionale di Fisica Nucleare, Sezione di Pisa.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long ubi_btTraverse( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btActionRtn EachNode,
|
||||||
|
void *UserData );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Traverse a tree in sorted order (non-recursively). At each node, call
|
||||||
|
* (*EachNode)(), passing a pointer to the current node, and UserData as the
|
||||||
|
* second parameter.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
|
||||||
|
* the tree to be traversed.
|
||||||
|
* EachNode - a pointer to a function to be called at each node
|
||||||
|
* as the node is visited.
|
||||||
|
* UserData - a generic pointer that may point to anything that
|
||||||
|
* you choose.
|
||||||
|
*
|
||||||
|
* Output: A count of the number of nodes visited. This will be zero
|
||||||
|
* if the tree is empty.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long ubi_btKillTree( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btKillNodeRtn FreeNode );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
|
||||||
|
* structure. Return a count of the number of nodes deleted.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to an ubi_btRoot structure that indicates
|
||||||
|
* the root of the tree to delete.
|
||||||
|
* FreeNode - a function that will be called for each node in the
|
||||||
|
* tree to deallocate the memory used by the node.
|
||||||
|
*
|
||||||
|
* Output: The number of nodes removed from the tree.
|
||||||
|
* A value of 0 will be returned if:
|
||||||
|
* - The tree actually contains 0 entries.
|
||||||
|
* - the value of <RootPtr> is NULL, in which case the tree is
|
||||||
|
* assumed to be empty
|
||||||
|
* - the value of <FreeNode> is NULL, in which case entries
|
||||||
|
* cannot be removed, so 0 is returned. *Make sure that you
|
||||||
|
* provide a valid value for <FreeNode>*.
|
||||||
|
* In all other cases, you should get a positive value equal to
|
||||||
|
* the value of RootPtr->count upon entry.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a pointer to a leaf node.
|
||||||
|
*
|
||||||
|
* Input: leader - Pointer to a node at which to start the descent.
|
||||||
|
*
|
||||||
|
* Output: A pointer to a leaf node selected in a somewhat arbitrary
|
||||||
|
* manner.
|
||||||
|
*
|
||||||
|
* Notes: I wrote this function because I was using splay trees as a
|
||||||
|
* database cache. The cache had a maximum size on it, and I
|
||||||
|
* needed a way of choosing a node to sacrifice if the cache
|
||||||
|
* became full. In a splay tree, less recently accessed nodes
|
||||||
|
* tend toward the bottom of the tree, meaning that leaf nodes
|
||||||
|
* are good candidates for removal. (I really can't think of
|
||||||
|
* any other reason to use this function.)
|
||||||
|
* + In a simple binary tree or an AVL tree, the most recently
|
||||||
|
* added nodes tend to be nearer the bottom, making this a *bad*
|
||||||
|
* way to choose which node to remove from the cache.
|
||||||
|
* + Randomizing the traversal order is probably a good idea. You
|
||||||
|
* can improve the randomization of leaf node selection by passing
|
||||||
|
* in pointers to nodes other than the root node each time. A
|
||||||
|
* pointer to any node in the tree will do. Of course, if you
|
||||||
|
* pass a pointer to a leaf node you'll get the same thing back.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
int ubi_btModuleID( int size, char *list[] );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a set of strings that identify the module.
|
||||||
|
*
|
||||||
|
* Input: size - The number of elements in the array <list>.
|
||||||
|
* list - An array of pointers of type (char *). This array
|
||||||
|
* should, initially, be empty. This function will fill
|
||||||
|
* in the array with pointers to strings.
|
||||||
|
* Output: The number of elements of <list> that were used. If this value
|
||||||
|
* is less than <size>, the values of the remaining elements are
|
||||||
|
* not guaranteed.
|
||||||
|
*
|
||||||
|
* Notes: Please keep in mind that the pointers returned indicate strings
|
||||||
|
* stored in static memory. Don't free() them, don't write over
|
||||||
|
* them, etc. Just read them.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Masquarade...
|
||||||
|
*
|
||||||
|
* This set of defines allows you to write programs that will use any of the
|
||||||
|
* implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
|
||||||
|
* Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
|
||||||
|
* including the appropriate module header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_trItemPtr ubi_btItemPtr
|
||||||
|
|
||||||
|
#define ubi_trNode ubi_btNode
|
||||||
|
#define ubi_trNodePtr ubi_btNodePtr
|
||||||
|
|
||||||
|
#define ubi_trRoot ubi_btRoot
|
||||||
|
#define ubi_trRootPtr ubi_btRootPtr
|
||||||
|
|
||||||
|
#define ubi_trCompFunc ubi_btCompFunc
|
||||||
|
#define ubi_trActionRtn ubi_btActionRtn
|
||||||
|
#define ubi_trKillNodeRtn ubi_btKillNodeRtn
|
||||||
|
|
||||||
|
#define ubi_trSgn( x ) ubi_btSgn( x )
|
||||||
|
|
||||||
|
#define ubi_trInitNode( Np ) ubi_btInitNode( (ubi_btNodePtr)(Np) )
|
||||||
|
|
||||||
|
#define ubi_trInitTree( Rp, Cf, Fl ) \
|
||||||
|
ubi_btInitTree( (ubi_btRootPtr)(Rp), (ubi_btCompFunc)(Cf), (Fl) )
|
||||||
|
|
||||||
|
#define ubi_trInsert( Rp, Nn, Ip, On ) \
|
||||||
|
ubi_btInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
|
||||||
|
(ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
|
||||||
|
|
||||||
|
#define ubi_trRemove( Rp, Dn ) \
|
||||||
|
ubi_btRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
|
||||||
|
|
||||||
|
#define ubi_trLocate( Rp, Ip, Op ) \
|
||||||
|
ubi_btLocate( (ubi_btRootPtr)(Rp), \
|
||||||
|
(ubi_btItemPtr)(Ip), \
|
||||||
|
(ubi_trCompOps)(Op) )
|
||||||
|
|
||||||
|
#define ubi_trFind( Rp, Ip ) \
|
||||||
|
ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
|
||||||
|
|
||||||
|
#define ubi_trNext( P ) ubi_btNext( (ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trPrev( P ) ubi_btPrev( (ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trFirst( P ) ubi_btFirst( (ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trLast( P ) ubi_btLast( (ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trFirstOf( Rp, Ip, P ) \
|
||||||
|
ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
|
||||||
|
(ubi_btItemPtr)(Ip), \
|
||||||
|
(ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trLastOf( Rp, Ip, P ) \
|
||||||
|
ubi_btLastOf( (ubi_btRootPtr)(Rp), \
|
||||||
|
(ubi_btItemPtr)(Ip), \
|
||||||
|
(ubi_btNodePtr)(P) )
|
||||||
|
|
||||||
|
#define ubi_trTraverse( Rp, En, Ud ) \
|
||||||
|
ubi_btTraverse((ubi_btRootPtr)(Rp), (ubi_btActionRtn)(En), (void *)(Ud))
|
||||||
|
|
||||||
|
#define ubi_trKillTree( Rp, Fn ) \
|
||||||
|
ubi_btKillTree( (ubi_btRootPtr)(Rp), (ubi_btKillNodeRtn)(Fn) )
|
||||||
|
|
||||||
|
#define ubi_trLeafNode( Nd ) \
|
||||||
|
ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
|
||||||
|
|
||||||
|
#define ubi_trModuleID( s, l ) ubi_btModuleID( s, l )
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
#endif /* UBI_BINTREE_H */
|
506
lib/ubi_Cache.c
Normal file
506
lib/ubi_Cache.c
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_Cache.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module implements a generic cache.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module uses a splay tree to implement a simple cache. The cache
|
||||||
|
* module adds a thin layer of functionality to the splay tree. In
|
||||||
|
* particular:
|
||||||
|
*
|
||||||
|
* - The tree (cache) may be limited in size by the number of
|
||||||
|
* entries permitted or the amount of memory used. When either
|
||||||
|
* limit is exceeded cache entries are removed until the cache
|
||||||
|
* conforms.
|
||||||
|
* - Some statistical information is kept so that an approximate
|
||||||
|
* "hit ratio" can be calculated.
|
||||||
|
* - There are several functions available that provide access to
|
||||||
|
* and management of cache size limits, hit ratio, and tree
|
||||||
|
* trimming.
|
||||||
|
*
|
||||||
|
* The splay tree is used because recently accessed items tend toward the
|
||||||
|
* top of the tree and less recently accessed items tend toward the bottom.
|
||||||
|
* This makes it easy to purge less recently used items should the cache
|
||||||
|
* exceed its limits.
|
||||||
|
*
|
||||||
|
* To use this module, you will need to supply a comparison function of
|
||||||
|
* type ubi_trCompFunc and a node-freeing function of type
|
||||||
|
* ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
|
||||||
|
* these. (This is all basic ubiqx tree management stuff.)
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
*
|
||||||
|
* - Cache performance will start to suffer dramatically if the
|
||||||
|
* cache becomes large enough to force the OS to start swapping
|
||||||
|
* memory to disk. This is because the nodes of the underlying tree
|
||||||
|
* will be scattered across memory in an order that is completely
|
||||||
|
* unrelated to their traversal order. As more and more of the
|
||||||
|
* cache is placed into swap space, more and more swaps will be
|
||||||
|
* required for a simple traversal (...and then there's the splay
|
||||||
|
* operation).
|
||||||
|
*
|
||||||
|
* In one simple test under Linux, the load and dump of a cache of
|
||||||
|
* 400,000 entries took only 1min, 40sec of real time. The same
|
||||||
|
* test with 450,000 records took 2 *hours* and eight minutes.
|
||||||
|
*
|
||||||
|
* - In an effort to save memory, I considered using an unsigned
|
||||||
|
* short to save the per-entry entry size. I would have tucked this
|
||||||
|
* value into some unused space in the tree node structure. On
|
||||||
|
* 32-bit word aligned systems this would have saved an additional
|
||||||
|
* four bytes per entry. I may revisit this issue, but for now I've
|
||||||
|
* decided against it.
|
||||||
|
*
|
||||||
|
* Using an unsigned short would limit the size of an entry to 64K
|
||||||
|
* bytes. That's probably more than enough for most applications.
|
||||||
|
* The key word in that last sentence, however, is "probably". I
|
||||||
|
* really dislike imposing such limits on things.
|
||||||
|
*
|
||||||
|
* - Each entry keeps track of the amount of memory it used and the
|
||||||
|
* cache header keeps the total. This information is provided via
|
||||||
|
* the EntrySize parameter in ubi_cachePut(), so it is up to you to
|
||||||
|
* make sure that the numbers are accurate. (The numbers don't even
|
||||||
|
* have to represent bytes used.)
|
||||||
|
*
|
||||||
|
* As you consider this, note that the strdup() function--as an
|
||||||
|
* example--will call malloc(). The latter generally allocates a
|
||||||
|
* multiple of the system word size, which may be more than the
|
||||||
|
* number of bytes needed to store the string.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_Cache.c,v
|
||||||
|
* Revision 0.4 1999/09/22 03:42:24 crh
|
||||||
|
* Fixed a minor typo.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1998/06/03 18:00:15 crh
|
||||||
|
* Further fiddling with sys_include.h, which is no longer explicitly
|
||||||
|
* included by this module since it is inherited from ubi_BinTree.h.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1998/06/02 01:36:18 crh
|
||||||
|
* Changed include name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.1 1998/05/20 04:36:02 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.0 1997/12/18 06:24:33 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libs.h"
|
||||||
|
#include "ubi_Cache.h" /* Header for *this* module. */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Static data...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* commented out until I make use of it...
|
||||||
|
static char ModuleID[] =
|
||||||
|
"ubi_Cache\n\
|
||||||
|
\tRevision: 0.4 \n\
|
||||||
|
\tDate: 1999/09/22 03:42:24 \n\
|
||||||
|
\tAuthor: crh \n";
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Internal functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void free_entry( ubi_cacheRootPtr CachePtr, ubi_cacheEntryPtr EntryPtr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Free a ubi_cacheEntry, and adjust the mem_used counter accordingly.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache from which the entry has
|
||||||
|
* been removed.
|
||||||
|
* EntryPtr - A pointer to the already removed entry.
|
||||||
|
*
|
||||||
|
* Output: none.
|
||||||
|
*
|
||||||
|
* Notes: The entry must be removed from the cache *before* this function
|
||||||
|
* is called!!!!
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
CachePtr->mem_used -= EntryPtr->entry_size;
|
||||||
|
(*CachePtr->free_func)( (void *)EntryPtr );
|
||||||
|
} /* free_entry */
|
||||||
|
|
||||||
|
static void cachetrim( ubi_cacheRootPtr crptr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove entries from the cache until the number of entries and the amount
|
||||||
|
* of memory used are *both* below or at the maximum.
|
||||||
|
*
|
||||||
|
* Input: crptr - pointer to the cache to be trimmed.
|
||||||
|
*
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
while( ( crptr->max_entries && (crptr->max_entries < crptr->root.count) )
|
||||||
|
|| ( crptr->max_memory && (crptr->max_memory < crptr->mem_used) ) )
|
||||||
|
{
|
||||||
|
if( !ubi_cacheReduce( crptr, 1 ) )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} /* cachetrim */
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Exported functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
|
||||||
|
ubi_trCompFunc CompFunc,
|
||||||
|
ubi_trKillNodeRtn FreeFunc,
|
||||||
|
unsigned long MaxEntries,
|
||||||
|
unsigned long MaxMemory )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a cache header structure.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
|
||||||
|
* to be initialized.
|
||||||
|
* CompFunc - A pointer to the function that will be called
|
||||||
|
* to compare two cache values. See the module
|
||||||
|
* comments, above, for more information.
|
||||||
|
* FreeFunc - A pointer to a function that will be called
|
||||||
|
* to free a cache entry. If you allocated
|
||||||
|
* the cache entry using malloc(), then this
|
||||||
|
* will likely be free(). If you are allocating
|
||||||
|
* cache entries from a free list, then this will
|
||||||
|
* likely be a function that returns memory to the
|
||||||
|
* free list, etc.
|
||||||
|
* MaxEntries - The maximum number of entries that will be
|
||||||
|
* allowed to exist in the cache. If this limit
|
||||||
|
* is exceeded, then existing entries will be
|
||||||
|
* removed from the cache. A value of zero
|
||||||
|
* indicates that there is no limit on the number
|
||||||
|
* of cache entries. See ubi_cachePut().
|
||||||
|
* MaxMemory - The maximum amount of memory, in bytes, to be
|
||||||
|
* allocated to the cache (excluding the cache
|
||||||
|
* header). If this is exceeded, existing entries
|
||||||
|
* in the cache will be removed until enough memory
|
||||||
|
* has been freed to meet the condition. See
|
||||||
|
* ubi_cachePut().
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized cache (i.e., the same as CachePtr).
|
||||||
|
*
|
||||||
|
* Notes: Both MaxEntries and MaxMemory may be changed after the cache
|
||||||
|
* has been created. See
|
||||||
|
* ubi_cacheSetMaxEntries()
|
||||||
|
* ubi_cacheSetMaxMemory()
|
||||||
|
* ubi_cacheGetMaxEntries()
|
||||||
|
* ubi_cacheGetMaxMemory() (the latter two are macros).
|
||||||
|
*
|
||||||
|
* - Memory is allocated in multiples of the word size. The
|
||||||
|
* return value of the strlen() function does not reflect
|
||||||
|
* this; it will allways be less than or equal to the amount
|
||||||
|
* of memory actually allocated. Keep this in mind when
|
||||||
|
* choosing a value for MaxMemory.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if( CachePtr )
|
||||||
|
{
|
||||||
|
(void)ubi_trInitTree( CachePtr, CompFunc, ubi_trOVERWRITE );
|
||||||
|
CachePtr->free_func = FreeFunc;
|
||||||
|
CachePtr->max_entries = MaxEntries;
|
||||||
|
CachePtr->max_memory = MaxMemory;
|
||||||
|
CachePtr->mem_used = 0;
|
||||||
|
CachePtr->cache_hits = 0;
|
||||||
|
CachePtr->cache_trys = 0;
|
||||||
|
}
|
||||||
|
return( CachePtr );
|
||||||
|
} /* ubi_cacheInit */
|
||||||
|
|
||||||
|
ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove and free all entries in an existing cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache that is to be cleared.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the cache header (i.e., the same as CachePtr).
|
||||||
|
* This function re-initializes the cache header.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if( CachePtr )
|
||||||
|
{
|
||||||
|
(void)ubi_trKillTree( CachePtr, CachePtr->free_func );
|
||||||
|
CachePtr->mem_used = 0;
|
||||||
|
CachePtr->cache_hits = 0;
|
||||||
|
CachePtr->cache_trys = 0;
|
||||||
|
}
|
||||||
|
return( CachePtr );
|
||||||
|
} /* ubi_cacheClear */
|
||||||
|
|
||||||
|
void ubi_cachePut( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long EntrySize,
|
||||||
|
ubi_cacheEntryPtr EntryPtr,
|
||||||
|
ubi_trItemPtr Key )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Add an entry to the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache into which the entry
|
||||||
|
* will be added.
|
||||||
|
* EntrySize - The size, in bytes, of the memory block indicated
|
||||||
|
* by EntryPtr. This will be copied into the
|
||||||
|
* EntryPtr->entry_size field.
|
||||||
|
* EntryPtr - A pointer to a memory block that begins with a
|
||||||
|
* ubi_cacheEntry structure. The entry structure
|
||||||
|
* should be followed immediately by the data to be
|
||||||
|
* cached (even if that is a pointer to yet more data).
|
||||||
|
* Key - Pointer used to identify the lookup key within the
|
||||||
|
* Entry.
|
||||||
|
*
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* Notes: After adding the new node, the cache is "trimmed". This
|
||||||
|
* removes extra nodes if the tree has exceeded it's memory or
|
||||||
|
* entry count limits. It is unlikely that the newly added node
|
||||||
|
* will be purged from the cache (assuming a reasonably large
|
||||||
|
* cache), since new nodes in a splay tree (which is what this
|
||||||
|
* module was designed to use) are moved to the top of the tree
|
||||||
|
* and the cache purge process removes nodes from the bottom of
|
||||||
|
* the tree.
|
||||||
|
* - The underlying splay tree is opened in OVERWRITE mode. If
|
||||||
|
* the input key matches an existing key, the existing entry will
|
||||||
|
* be politely removed from the tree and freed.
|
||||||
|
* - Memory is allocated in multiples of the word size. The
|
||||||
|
* return value of the strlen() function does not reflect
|
||||||
|
* this; it will allways be less than or equal to the amount
|
||||||
|
* of memory actually allocated.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_trNodePtr OldNode;
|
||||||
|
|
||||||
|
EntryPtr->entry_size = EntrySize;
|
||||||
|
CachePtr->mem_used += EntrySize;
|
||||||
|
(void)ubi_trInsert( CachePtr, EntryPtr, Key, &OldNode );
|
||||||
|
if( OldNode )
|
||||||
|
free_entry( CachePtr, (ubi_cacheEntryPtr)OldNode );
|
||||||
|
|
||||||
|
cachetrim( CachePtr );
|
||||||
|
} /* ubi_cachePut */
|
||||||
|
|
||||||
|
ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
|
||||||
|
ubi_trItemPtr FindMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Attempt to retrieve an entry from the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A ponter to the cache that is to be searched.
|
||||||
|
* FindMe - A ubi_trItemPtr that indicates the key for which
|
||||||
|
* to search.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the cache entry that was found, or NULL if no
|
||||||
|
* matching entry was found.
|
||||||
|
*
|
||||||
|
* Notes: This function also updates the hit ratio counters.
|
||||||
|
* The counters are unsigned short. If the number of cache tries
|
||||||
|
* reaches 32768, then both the number of tries and the number of
|
||||||
|
* hits are divided by two. This prevents the counters from
|
||||||
|
* overflowing. See the comments in ubi_cacheHitRatio() for
|
||||||
|
* additional notes.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_trNodePtr FoundPtr;
|
||||||
|
|
||||||
|
FoundPtr = ubi_trFind( CachePtr, FindMe );
|
||||||
|
|
||||||
|
if( FoundPtr )
|
||||||
|
CachePtr->cache_hits++;
|
||||||
|
CachePtr->cache_trys++;
|
||||||
|
|
||||||
|
if( CachePtr->cache_trys & 0x8000 )
|
||||||
|
{
|
||||||
|
CachePtr->cache_hits = CachePtr->cache_hits / 2;
|
||||||
|
CachePtr->cache_trys = CachePtr->cache_trys / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( (ubi_cacheEntryPtr)FoundPtr );
|
||||||
|
} /* ubi_cacheGet */
|
||||||
|
|
||||||
|
ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Find and delete the specified cache entry.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache.
|
||||||
|
* DeleteMe - The key of the entry to be deleted.
|
||||||
|
*
|
||||||
|
* Output: TRUE if the entry was found & freed, else FALSE.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_trNodePtr FoundPtr;
|
||||||
|
|
||||||
|
FoundPtr = ubi_trFind( CachePtr, DeleteMe );
|
||||||
|
if( FoundPtr )
|
||||||
|
{
|
||||||
|
(void)ubi_trRemove( CachePtr, FoundPtr );
|
||||||
|
free_entry( CachePtr, (ubi_cacheEntryPtr)FoundPtr );
|
||||||
|
return( ubi_trTRUE );
|
||||||
|
}
|
||||||
|
return( ubi_trFALSE );
|
||||||
|
} /* ubi_cacheDelete */
|
||||||
|
|
||||||
|
ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove <count> entries from the bottom of the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache which is to be reduced in
|
||||||
|
* size.
|
||||||
|
* count - The number of entries to remove.
|
||||||
|
*
|
||||||
|
* Output: The function will return TRUE if <count> entries were removed,
|
||||||
|
* else FALSE. A return value of FALSE should indicate that
|
||||||
|
* there were less than <count> entries in the cache, and that the
|
||||||
|
* cache is now empty.
|
||||||
|
*
|
||||||
|
* Notes: This function forces a reduction in the number of cache entries
|
||||||
|
* without requiring that the MaxMemory or MaxEntries values be
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_trNodePtr NodePtr;
|
||||||
|
|
||||||
|
while( count )
|
||||||
|
{
|
||||||
|
NodePtr = ubi_trLeafNode( CachePtr->root.root );
|
||||||
|
if( NULL == NodePtr )
|
||||||
|
return( ubi_trFALSE );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(void)ubi_trRemove( CachePtr, NodePtr );
|
||||||
|
free_entry( CachePtr, (ubi_cacheEntryPtr)NodePtr );
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
return( ubi_trTRUE );
|
||||||
|
} /* ubi_cacheReduce */
|
||||||
|
|
||||||
|
unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long NewSize )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Change the maximum number of entries allowed to exist in the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache to be modified.
|
||||||
|
* NewSize - The new maximum number of cache entries.
|
||||||
|
*
|
||||||
|
* Output: The maximum number of entries previously allowed to exist in
|
||||||
|
* the cache.
|
||||||
|
*
|
||||||
|
* Notes: If the new size is less than the old size, this function will
|
||||||
|
* trim the cache (remove excess entries).
|
||||||
|
* - A value of zero indicates an unlimited number of entries.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned long oldsize = CachePtr->max_entries; /* Save the old value. */
|
||||||
|
|
||||||
|
CachePtr->max_entries = NewSize; /* Apply the new value. */
|
||||||
|
if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
|
||||||
|
cachetrim( CachePtr ); /* remove excess. */
|
||||||
|
return( oldsize );
|
||||||
|
} /* ubi_cacheSetMaxEntries */
|
||||||
|
|
||||||
|
unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long NewSize )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Change the maximum amount of memory to be used for storing cache
|
||||||
|
* entries.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache to be modified.
|
||||||
|
* NewSize - The new cache memory size.
|
||||||
|
*
|
||||||
|
* Output: The previous maximum memory size.
|
||||||
|
*
|
||||||
|
* Notes: If the new size is less than the old size, this function will
|
||||||
|
* trim the cache (remove excess entries).
|
||||||
|
* - A value of zero indicates that the cache has no memory limit.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned long oldsize = CachePtr->max_memory; /* Save the old value. */
|
||||||
|
|
||||||
|
CachePtr->max_memory = NewSize; /* Apply the new value. */
|
||||||
|
if( (NewSize < oldsize) || (NewSize && !oldsize) ) /* If size is smaller, */
|
||||||
|
cachetrim( CachePtr ); /* remove excess. */
|
||||||
|
return( oldsize );
|
||||||
|
} /* ubi_cacheSetMaxMemory */
|
||||||
|
|
||||||
|
int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a value that is 10,000 times the slightly weighted average hit
|
||||||
|
* ratio for the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - Pointer to the cache to be queried.
|
||||||
|
*
|
||||||
|
* Output: An integer that is 10,000 times the number of successful
|
||||||
|
* cache hits divided by the number of cache lookups, or:
|
||||||
|
* (10000 * hits) / trys
|
||||||
|
* You can easily convert this to a float, or do something
|
||||||
|
* like this (where i is the return value of this function):
|
||||||
|
*
|
||||||
|
* printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
|
||||||
|
*
|
||||||
|
* Notes: I say "slightly-weighted", because the numerator and
|
||||||
|
* denominator are both accumulated in locations of type
|
||||||
|
* 'unsigned short'. If the number of cache trys becomes
|
||||||
|
* large enough, both are divided by two. (See function
|
||||||
|
* ubi_cacheGet().)
|
||||||
|
* Dividing both numerator and denominator by two does not
|
||||||
|
* change the ratio (much...it is an integer divide), but it
|
||||||
|
* does mean that subsequent increments to either counter will
|
||||||
|
* have twice as much significance as previous ones.
|
||||||
|
*
|
||||||
|
* - The value returned by this function will be in the range
|
||||||
|
* [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
|
||||||
|
* always be true.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int tmp = 0;
|
||||||
|
|
||||||
|
if( CachePtr->cache_trys )
|
||||||
|
tmp = (int)( (10000 * (long)(CachePtr->cache_hits) )
|
||||||
|
/ (long)(CachePtr->cache_trys) );
|
||||||
|
return( tmp );
|
||||||
|
} /* ubi_cacheHitRatio */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
412
lib/ubi_Cache.h
Normal file
412
lib/ubi_Cache.h
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
#ifndef UBI_CACHE_H
|
||||||
|
#define UBI_CACHE_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_Cache.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module implements a generic cache.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module uses a splay tree to implement a simple cache. The cache
|
||||||
|
* module adds a thin layer of functionality to the splay tree. In
|
||||||
|
* particular:
|
||||||
|
*
|
||||||
|
* - The tree (cache) may be limited in size by the number of
|
||||||
|
* entries permitted or the amount of memory used. When either
|
||||||
|
* limit is exceeded cache entries are removed until the cache
|
||||||
|
* conforms.
|
||||||
|
* - Some statistical information is kept so that an approximate
|
||||||
|
* "hit ratio" can be calculated.
|
||||||
|
* - There are several functions available that provide access to
|
||||||
|
* and management of cache size limits, hit ratio, and tree
|
||||||
|
* trimming.
|
||||||
|
*
|
||||||
|
* The splay tree is used because recently accessed items tend toward the
|
||||||
|
* top of the tree and less recently accessed items tend toward the bottom.
|
||||||
|
* This makes it easy to purge less recently used items should the cache
|
||||||
|
* exceed its limits.
|
||||||
|
*
|
||||||
|
* To use this module, you will need to supply a comparison function of
|
||||||
|
* type ubi_trCompFunc and a node-freeing function of type
|
||||||
|
* ubi_trKillNodeRtn. See ubi_BinTree.h for more information on
|
||||||
|
* these. (This is all basic ubiqx tree management stuff.)
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
*
|
||||||
|
* - Cache performance will start to suffer dramatically if the
|
||||||
|
* cache becomes large enough to force the OS to start swapping
|
||||||
|
* memory to disk. This is because the nodes of the underlying tree
|
||||||
|
* will be scattered across memory in an order that is completely
|
||||||
|
* unrelated to their traversal order. As more and more of the
|
||||||
|
* cache is placed into swap space, more and more swaps will be
|
||||||
|
* required for a simple traversal (...and then there's the splay
|
||||||
|
* operation).
|
||||||
|
*
|
||||||
|
* In one simple test under Linux, the load and dump of a cache of
|
||||||
|
* 400,000 entries took only 1min, 40sec of real time. The same
|
||||||
|
* test with 450,000 records took 2 *hours* and eight minutes.
|
||||||
|
*
|
||||||
|
* - In an effort to save memory, I considered using an unsigned
|
||||||
|
* short to save the per-entry entry size. I would have tucked this
|
||||||
|
* value into some unused space in the tree node structure. On
|
||||||
|
* 32-bit word aligned systems this would have saved an additional
|
||||||
|
* four bytes per entry. I may revisit this issue, but for now I've
|
||||||
|
* decided against it.
|
||||||
|
*
|
||||||
|
* Using an unsigned short would limit the size of an entry to 64K
|
||||||
|
* bytes. That's probably more than enough for most applications.
|
||||||
|
* The key word in that last sentence, however, is "probably". I
|
||||||
|
* really dislike imposing such limits on things.
|
||||||
|
*
|
||||||
|
* - Each entry keeps track of the amount of memory it used and the
|
||||||
|
* cache header keeps the total. This information is provided via
|
||||||
|
* the EntrySize parameter in ubi_cachePut(), so it is up to you to
|
||||||
|
* make sure that the numbers are accurate. (The numbers don't even
|
||||||
|
* have to represent bytes used.)
|
||||||
|
*
|
||||||
|
* As you consider this, note that the strdup() function--as an
|
||||||
|
* example--will call malloc(). The latter generally allocates a
|
||||||
|
* multiple of the system word size, which may be more than the
|
||||||
|
* number of bytes needed to store the string.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_Cache.h,v
|
||||||
|
* Revision 0.4 1999/09/22 03:42:24 crh
|
||||||
|
* Fixed a minor typo.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1998/06/03 18:00:15 crh
|
||||||
|
* Further fiddling with sys_include.h, which is no longer explicitly
|
||||||
|
* included by this module since it is inherited from ubi_BinTree.h.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1998/06/02 01:36:18 crh
|
||||||
|
* Changed include name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.1 1998/05/20 04:36:02 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.0 1997/12/18 06:25:23 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ubi_SplayTree.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Typedefs...
|
||||||
|
*
|
||||||
|
* ubi_cacheRoot - Cache header structure, which consists of a binary
|
||||||
|
* tree root and other required housekeeping fields, as
|
||||||
|
* listed below.
|
||||||
|
* ubi_cacheRootPtr - Pointer to a Cache.
|
||||||
|
*
|
||||||
|
* ubi_cacheEntry - A cache Entry, which consists of a tree node
|
||||||
|
* structure and the size (in bytes) of the entry
|
||||||
|
* data. The entry size should be supplied via
|
||||||
|
* the EntrySize parameter of the ubi_cachePut()
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* ubi_cacheEntryPtr - Pointer to a ubi_cacheEntry.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ubi_trRoot root; /* Splay tree control structure. */
|
||||||
|
ubi_trKillNodeRtn free_func; /* Function used to free entries. */
|
||||||
|
unsigned long max_entries; /* Max cache entries. 0 == unlimited */
|
||||||
|
unsigned long max_memory; /* Max memory to use. 0 == unlimited */
|
||||||
|
unsigned long mem_used; /* Memory currently in use (bytes). */
|
||||||
|
unsigned short cache_hits; /* Incremented on succesful find. */
|
||||||
|
unsigned short cache_trys; /* Incremented on cache lookup. */
|
||||||
|
} ubi_cacheRoot;
|
||||||
|
|
||||||
|
typedef ubi_cacheRoot *ubi_cacheRootPtr;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ubi_trNode node; /* Tree node structure. */
|
||||||
|
unsigned long entry_size; /* Entry size. Used when managing
|
||||||
|
* caches with maximum memory limits.
|
||||||
|
*/
|
||||||
|
} ubi_cacheEntry;
|
||||||
|
|
||||||
|
typedef ubi_cacheEntry *ubi_cacheEntryPtr;
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Macros...
|
||||||
|
*
|
||||||
|
* ubi_cacheGetMaxEntries() - Report the current maximum number of entries
|
||||||
|
* allowed in the cache. Zero indicates no
|
||||||
|
* maximum.
|
||||||
|
* ubi_cacheGetMaxMemory() - Report the current maximum amount of memory
|
||||||
|
* that may be used in the cache. Zero
|
||||||
|
* indicates no maximum.
|
||||||
|
* ubi_cacheGetEntryCount() - Report the current number of entries in the
|
||||||
|
* cache.
|
||||||
|
* ubi_cacheGetMemUsed() - Report the amount of memory currently in use
|
||||||
|
* by the cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_cacheGetMaxEntries( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_entries)
|
||||||
|
#define ubi_cacheGetMaxMemory( Cptr ) (((ubi_cacheRootPtr)(Cptr))->max_memory)
|
||||||
|
|
||||||
|
#define ubi_cacheGetEntryCount( Cptr ) (((ubi_cacheRootPtr)(Cptr))->root.count)
|
||||||
|
#define ubi_cacheGetMemUsed( Cptr ) (((ubi_cacheRootPtr)(Cptr))->mem_used)
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Prototypes...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_cacheRootPtr ubi_cacheInit( ubi_cacheRootPtr CachePtr,
|
||||||
|
ubi_trCompFunc CompFunc,
|
||||||
|
ubi_trKillNodeRtn FreeFunc,
|
||||||
|
unsigned long MaxEntries,
|
||||||
|
unsigned long MaxMemory );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a cache header structure.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to a ubi_cacheRoot structure that is
|
||||||
|
* to be initialized.
|
||||||
|
* CompFunc - A pointer to the function that will be called
|
||||||
|
* to compare two cache values. See the module
|
||||||
|
* comments, above, for more information.
|
||||||
|
* FreeFunc - A pointer to a function that will be called
|
||||||
|
* to free a cache entry. If you allocated
|
||||||
|
* the cache entry using malloc(), then this
|
||||||
|
* will likely be free(). If you are allocating
|
||||||
|
* cache entries from a free list, then this will
|
||||||
|
* likely be a function that returns memory to the
|
||||||
|
* free list, etc.
|
||||||
|
* MaxEntries - The maximum number of entries that will be
|
||||||
|
* allowed to exist in the cache. If this limit
|
||||||
|
* is exceeded, then existing entries will be
|
||||||
|
* removed from the cache. A value of zero
|
||||||
|
* indicates that there is no limit on the number
|
||||||
|
* of cache entries. See ubi_cachePut().
|
||||||
|
* MaxMemory - The maximum amount of memory, in bytes, to be
|
||||||
|
* allocated to the cache (excluding the cache
|
||||||
|
* header). If this is exceeded, existing entries
|
||||||
|
* in the cache will be removed until enough memory
|
||||||
|
* has been freed to meet the condition. See
|
||||||
|
* ubi_cachePut().
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized cache (i.e., the same as CachePtr).
|
||||||
|
*
|
||||||
|
* Notes: Both MaxEntries and MaxMemory may be changed after the cache
|
||||||
|
* has been created. See
|
||||||
|
* ubi_cacheSetMaxEntries()
|
||||||
|
* ubi_cacheSetMaxMemory()
|
||||||
|
* ubi_cacheGetMaxEntries()
|
||||||
|
* ubi_cacheGetMaxMemory() (the latter two are macros).
|
||||||
|
*
|
||||||
|
* - Memory is allocated in multiples of the word size. The
|
||||||
|
* return value of the strlen() function does not reflect
|
||||||
|
* this; it will allways be less than or equal to the amount
|
||||||
|
* of memory actually allocated. Keep this in mind when
|
||||||
|
* choosing a value for MaxMemory.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_cacheRootPtr ubi_cacheClear( ubi_cacheRootPtr CachePtr );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove and free all entries in an existing cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache that is to be cleared.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the cache header (i.e., the same as CachePtr).
|
||||||
|
* This function re-initializes the cache header.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ubi_cachePut( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long EntrySize,
|
||||||
|
ubi_cacheEntryPtr EntryPtr,
|
||||||
|
ubi_trItemPtr Key );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Add an entry to the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache into which the entry
|
||||||
|
* will be added.
|
||||||
|
* EntrySize - The size, in bytes, of the memory block indicated
|
||||||
|
* by EntryPtr. This will be copied into the
|
||||||
|
* EntryPtr->entry_size field.
|
||||||
|
* EntryPtr - A pointer to a memory block that begins with a
|
||||||
|
* ubi_cacheEntry structure. The entry structure
|
||||||
|
* should be followed immediately by the data to be
|
||||||
|
* cached (even if that is a pointer to yet more data).
|
||||||
|
* Key - Pointer used to identify the lookup key within the
|
||||||
|
* Entry.
|
||||||
|
*
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* Notes: After adding the new node, the cache is "trimmed". This
|
||||||
|
* removes extra nodes if the tree has exceeded it's memory or
|
||||||
|
* entry count limits. It is unlikely that the newly added node
|
||||||
|
* will be purged from the cache (assuming a reasonably large
|
||||||
|
* cache), since new nodes in a splay tree (which is what this
|
||||||
|
* module was designed to use) are moved to the top of the tree
|
||||||
|
* and the cache purge process removes nodes from the bottom of
|
||||||
|
* the tree.
|
||||||
|
* - The underlying splay tree is opened in OVERWRITE mode. If
|
||||||
|
* the input key matches an existing key, the existing entry will
|
||||||
|
* be politely removed from the tree and freed.
|
||||||
|
* - Memory is allocated in multiples of the word size. The
|
||||||
|
* return value of the strlen() function does not reflect
|
||||||
|
* this; it will allways be less than or equal to the amount
|
||||||
|
* of memory actually allocated.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_cacheEntryPtr ubi_cacheGet( ubi_cacheRootPtr CachePtr,
|
||||||
|
ubi_trItemPtr FindMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Attempt to retrieve an entry from the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A ponter to the cache that is to be searched.
|
||||||
|
* FindMe - A ubi_trItemPtr that indicates the key for which
|
||||||
|
* to search.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the cache entry that was found, or NULL if no
|
||||||
|
* matching entry was found.
|
||||||
|
*
|
||||||
|
* Notes: This function also updates the hit ratio counters.
|
||||||
|
* The counters are unsigned short. If the number of cache tries
|
||||||
|
* reaches 32768, then both the number of tries and the number of
|
||||||
|
* hits are divided by two. This prevents the counters from
|
||||||
|
* overflowing. See the comments in ubi_cacheHitRatio() for
|
||||||
|
* additional notes.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_trBool ubi_cacheDelete( ubi_cacheRootPtr CachePtr, ubi_trItemPtr DeleteMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Find and delete the specified cache entry.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache.
|
||||||
|
* DeleteMe - The key of the entry to be deleted.
|
||||||
|
*
|
||||||
|
* Output: TRUE if the entry was found & freed, else FALSE.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_trBool ubi_cacheReduce( ubi_cacheRootPtr CachePtr, unsigned long count );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove <count> entries from the bottom of the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache which is to be reduced in
|
||||||
|
* size.
|
||||||
|
* count - The number of entries to remove.
|
||||||
|
*
|
||||||
|
* Output: The function will return TRUE if <count> entries were removed,
|
||||||
|
* else FALSE. A return value of FALSE should indicate that
|
||||||
|
* there were less than <count> entries in the cache, and that the
|
||||||
|
* cache is now empty.
|
||||||
|
*
|
||||||
|
* Notes: This function forces a reduction in the number of cache entries
|
||||||
|
* without requiring that the MaxMemory or MaxEntries values be
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long ubi_cacheSetMaxEntries( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long NewSize );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Change the maximum number of entries allowed to exist in the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache to be modified.
|
||||||
|
* NewSize - The new maximum number of cache entries.
|
||||||
|
*
|
||||||
|
* Output: The maximum number of entries previously allowed to exist in
|
||||||
|
* the cache.
|
||||||
|
*
|
||||||
|
* Notes: If the new size is less than the old size, this function will
|
||||||
|
* trim the cache (remove excess entries).
|
||||||
|
* - A value of zero indicates an unlimited number of entries.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long ubi_cacheSetMaxMemory( ubi_cacheRootPtr CachePtr,
|
||||||
|
unsigned long NewSize );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Change the maximum amount of memory to be used for storing cache
|
||||||
|
* entries.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - A pointer to the cache to be modified.
|
||||||
|
* NewSize - The new cache memory size.
|
||||||
|
*
|
||||||
|
* Output: The previous maximum memory size.
|
||||||
|
*
|
||||||
|
* Notes: If the new size is less than the old size, this function will
|
||||||
|
* trim the cache (remove excess entries).
|
||||||
|
* - A value of zero indicates that the cache has no memory limit.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ubi_cacheHitRatio( ubi_cacheRootPtr CachePtr );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a value that is 10,000 times the slightly weighted average hit
|
||||||
|
* ratio for the cache.
|
||||||
|
*
|
||||||
|
* Input: CachePtr - Pointer to the cache to be queried.
|
||||||
|
*
|
||||||
|
* Output: An integer that is 10,000 times the number of successful
|
||||||
|
* cache hits divided by the number of cache lookups, or:
|
||||||
|
* (10000 * hits) / trys
|
||||||
|
* You can easily convert this to a float, or do something
|
||||||
|
* like this (where i is the return value of this function):
|
||||||
|
*
|
||||||
|
* printf( "Hit rate : %d.%02d%%\n", (i/100), (i%100) );
|
||||||
|
*
|
||||||
|
* Notes: I say "slightly-weighted", because the numerator and
|
||||||
|
* denominator are both accumulated in locations of type
|
||||||
|
* 'unsigned short'. If the number of cache trys becomes
|
||||||
|
* large enough, both are divided by two. (See function
|
||||||
|
* ubi_cacheGet().)
|
||||||
|
* Dividing both numerator and denominator by two does not
|
||||||
|
* change the ratio (much...it is an integer divide), but it
|
||||||
|
* does mean that subsequent increments to either counter will
|
||||||
|
* have twice as much significance as previous ones.
|
||||||
|
*
|
||||||
|
* - The value returned by this function will be in the range
|
||||||
|
* [0..10000] because ( 0 <= cache_hits <= cache_trys ) will
|
||||||
|
* always be true.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
#endif /* ubi_CACHE_H */
|
513
lib/ubi_SplayTree.c
Normal file
513
lib/ubi_SplayTree.c
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_SplayTree.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1993-1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module implements "splay" trees. Splay trees are binary trees
|
||||||
|
* that are rearranged (splayed) whenever a node is accessed. The
|
||||||
|
* splaying process *tends* to make the tree bushier (improves balance),
|
||||||
|
* and the nodes that are accessed most frequently *tend* to be closer to
|
||||||
|
* the top.
|
||||||
|
*
|
||||||
|
* References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
|
||||||
|
* Robert Tarjan. Journal of the Association for Computing
|
||||||
|
* Machinery Vol 32, No. 3, July 1985 pp. 652-686
|
||||||
|
*
|
||||||
|
* See also: http://www.cs.cmu.edu/~sleator/
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_SplayTree.c,v
|
||||||
|
* Revision 4.5 2000/01/08 23:26:49 crh
|
||||||
|
* Added ubi_trSplay() macro, which does a type cast for us.
|
||||||
|
*
|
||||||
|
* Revision 4.4 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 4.3 1998/06/03 17:45:05 crh
|
||||||
|
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
|
||||||
|
* included by all of the binary tree files.
|
||||||
|
*
|
||||||
|
* Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
|
||||||
|
* to like syntax like this:
|
||||||
|
*
|
||||||
|
* if( (a = b) )
|
||||||
|
*
|
||||||
|
* The fix was to change lines like the above to:
|
||||||
|
*
|
||||||
|
* if( 0 != (a=b) )
|
||||||
|
*
|
||||||
|
* Which means the same thing.
|
||||||
|
*
|
||||||
|
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
|
||||||
|
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
|
||||||
|
* of tree types by simply changing a header. Unfortunately, the
|
||||||
|
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
|
||||||
|
* conflict if used together. You must either choose a single tree
|
||||||
|
* type, or use the underlying function calls directly. Compare
|
||||||
|
* the two header files for more information.
|
||||||
|
*
|
||||||
|
* Revision 4.2 1998/06/02 01:29:14 crh
|
||||||
|
* Changed ubi_null.h to sys_include.h to make it more generic.
|
||||||
|
*
|
||||||
|
* Revision 4.1 1998/05/20 04:37:54 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 4.0 1998/03/10 03:41:33 crh
|
||||||
|
* Minor comment changes. The revision number is now 4.0 to match the
|
||||||
|
* BinTree and AVLtree modules.
|
||||||
|
*
|
||||||
|
* Revision 2.7 1998/01/24 06:37:08 crh
|
||||||
|
* Added a URL for more information.
|
||||||
|
*
|
||||||
|
* Revision 2.6 1997/12/23 04:01:12 crh
|
||||||
|
* In this version, all constants & macros defined in the header file have
|
||||||
|
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
|
||||||
|
* when run with '-pedantic -fsyntax-only -Wall'.
|
||||||
|
*
|
||||||
|
* Revision 2.5 1997/07/26 04:15:42 crh
|
||||||
|
* + Cleaned up a few minor syntax annoyances that gcc discovered for me.
|
||||||
|
* + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
|
||||||
|
*
|
||||||
|
* Revision 2.4 1997/06/03 04:42:21 crh
|
||||||
|
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
|
||||||
|
* problems.
|
||||||
|
*
|
||||||
|
* Revision 2.3 1995/10/03 22:19:07 CRH
|
||||||
|
* Ubisized!
|
||||||
|
* Also, added the function ubi_sptSplay().
|
||||||
|
*
|
||||||
|
* Revision 2.1 95/03/09 23:54:42 CRH
|
||||||
|
* Added the ModuleID static string and function. These modules are now
|
||||||
|
* self-identifying.
|
||||||
|
*
|
||||||
|
* Revision 2.0 95/02/27 22:34:46 CRH
|
||||||
|
* This module was updated to match the interface changes made to the
|
||||||
|
* ubi_BinTree module. In particular, the interface to the Locate() function
|
||||||
|
* has changed. See ubi_BinTree for more information on changes and new
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* The revision number was also upped to match ubi_BinTree.
|
||||||
|
*
|
||||||
|
* Revision 1.1 93/10/18 20:35:16 CRH
|
||||||
|
* I removed the hard-coded logical device names from the include file
|
||||||
|
* specifications. CRH
|
||||||
|
*
|
||||||
|
* Revision 1.0 93/10/15 23:00:15 CRH
|
||||||
|
* With this revision, I have added a set of #define's that provide a single,
|
||||||
|
* standard API to all existing tree modules. Until now, each of the three
|
||||||
|
* existing modules had a different function and typedef prefix, as follows:
|
||||||
|
*
|
||||||
|
* Module Prefix
|
||||||
|
* ubi_BinTree ubi_bt
|
||||||
|
* ubi_AVLtree ubi_avl
|
||||||
|
* ubi_SplayTree ubi_spt
|
||||||
|
*
|
||||||
|
* To further complicate matters, only those portions of the base module
|
||||||
|
* (ubi_BinTree) that were superceeded in the new module had the new names.
|
||||||
|
* For example, if you were using ubi_SplayTree, the locate function was
|
||||||
|
* called "ubi_sptLocate", but the next and previous functions remained
|
||||||
|
* "ubi_btNext" and "ubi_btPrev".
|
||||||
|
*
|
||||||
|
* This was not too terrible if you were familiar with the modules and knew
|
||||||
|
* exactly which tree model you wanted to use. If you wanted to be able to
|
||||||
|
* change modules (for speed comparisons, etc), things could get messy very
|
||||||
|
* quickly.
|
||||||
|
*
|
||||||
|
* So, I have added a set of defined names that get redefined in any of the
|
||||||
|
* descendant modules. To use this standardized interface in your code,
|
||||||
|
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
|
||||||
|
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
|
||||||
|
* datatype names for the module that you are using. Just remember to
|
||||||
|
* include the header for that module in your program file. Because these
|
||||||
|
* names are handled by the preprocessor, there is no added run-time
|
||||||
|
* overhead.
|
||||||
|
*
|
||||||
|
* Note that the original names do still exist, and can be used if you wish
|
||||||
|
* to write code directly to a specific module. This should probably only be
|
||||||
|
* done if you are planning to implement a new descendant type, such as
|
||||||
|
* red/black trees. CRH
|
||||||
|
*
|
||||||
|
* Revision 0.1 93/04/25 22:03:32 CRH
|
||||||
|
* Simply changed the <exec/types.h> #include reference the .c file to
|
||||||
|
* use <stdlib.h> instead. The latter is portable, the former is not.
|
||||||
|
*
|
||||||
|
* Revision 0.0 93/04/21 23:05:52 CRH
|
||||||
|
* Initial version, written by Christopher R. Hertel.
|
||||||
|
* This module implements Splay Trees using the ubi_BinTree module as a basis.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libs.h"
|
||||||
|
#include "ubi_SplayTree.h" /* Header for THIS module. */
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Static data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char ModuleID[] = "ubi_SplayTree\n\
|
||||||
|
\tRevision: 4.5 \n\
|
||||||
|
\tDate: 2000/01/08 23:26:49 \n\
|
||||||
|
\tAuthor: crh \n";
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Private functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void Rotate( ubi_btNodePtr p )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function performs a single rotation, moving node *p up one level
|
||||||
|
* in the tree.
|
||||||
|
*
|
||||||
|
* Input: p - a pointer to an ubi_btNode in a tree.
|
||||||
|
*
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* Notes: This implements a single rotation in either direction (left
|
||||||
|
* or right). This is the basic building block of all splay
|
||||||
|
* tree rotations.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr parentp;
|
||||||
|
ubi_btNodePtr tmp;
|
||||||
|
char way;
|
||||||
|
char revway;
|
||||||
|
|
||||||
|
parentp = p->Link[ubi_trPARENT]; /* Find parent. */
|
||||||
|
|
||||||
|
if( parentp ) /* If no parent, then we're already the root. */
|
||||||
|
{
|
||||||
|
way = p->gender;
|
||||||
|
revway = ubi_trRevWay(way);
|
||||||
|
tmp = p->Link[(int)revway];
|
||||||
|
|
||||||
|
parentp->Link[(int)way] = tmp;
|
||||||
|
if( tmp )
|
||||||
|
{
|
||||||
|
tmp->Link[ubi_trPARENT] = parentp;
|
||||||
|
tmp->gender = way;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = parentp->Link[ubi_trPARENT];
|
||||||
|
p->Link[ubi_trPARENT] = tmp;
|
||||||
|
p->gender = parentp->gender;
|
||||||
|
if( tmp )
|
||||||
|
tmp->Link[(int)(p->gender)] = p;
|
||||||
|
|
||||||
|
parentp->Link[ubi_trPARENT] = p;
|
||||||
|
parentp->gender = revway;
|
||||||
|
p->Link[(int)revway] = parentp;
|
||||||
|
}
|
||||||
|
} /* Rotate */
|
||||||
|
|
||||||
|
static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Move the node indicated by SplayWithMe to the root of the tree by
|
||||||
|
* splaying the tree.
|
||||||
|
*
|
||||||
|
* Input: SplayWithMe - A pointer to an ubi_btNode within a tree.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the root of the splay tree (i.e., the same as
|
||||||
|
* SplayWithMe).
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr parent;
|
||||||
|
|
||||||
|
while( NULL != (parent = SplayWithMe->Link[ubi_trPARENT]) )
|
||||||
|
{
|
||||||
|
if( parent->gender == SplayWithMe->gender ) /* Zig-Zig */
|
||||||
|
Rotate( parent );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( ubi_trEQUAL != parent->gender ) /* Zig-Zag */
|
||||||
|
Rotate( SplayWithMe );
|
||||||
|
}
|
||||||
|
Rotate( SplayWithMe ); /* Zig */
|
||||||
|
} /* while */
|
||||||
|
return( SplayWithMe );
|
||||||
|
} /* Splay */
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Exported utilities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr NewNode,
|
||||||
|
ubi_btItemPtr ItemPtr,
|
||||||
|
ubi_btNodePtr *OldNode )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function uses a non-recursive algorithm to add a new element to the
|
||||||
|
* splay tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
|
||||||
|
* the root of the tree to which NewNode is to be added.
|
||||||
|
* NewNode - a pointer to an ubi_btNode structure that is NOT
|
||||||
|
* part of any tree.
|
||||||
|
* ItemPtr - A pointer to the sort key that is stored within
|
||||||
|
* *NewNode. ItemPtr MUST point to information stored
|
||||||
|
* in *NewNode or an EXACT DUPLICATE. The key data
|
||||||
|
* indicated by ItemPtr is used to place the new node
|
||||||
|
* into the tree.
|
||||||
|
* OldNode - a pointer to an ubi_btNodePtr. When searching
|
||||||
|
* the tree, a duplicate node may be found. If
|
||||||
|
* duplicates are allowed, then the new node will
|
||||||
|
* be simply placed into the tree. If duplicates
|
||||||
|
* are not allowed, however, then one of two things
|
||||||
|
* may happen.
|
||||||
|
* 1) if overwritting *is not* allowed, this
|
||||||
|
* function will return FALSE (indicating that
|
||||||
|
* the new node could not be inserted), and
|
||||||
|
* *OldNode will point to the duplicate that is
|
||||||
|
* still in the tree.
|
||||||
|
* 2) if overwritting *is* allowed, then this
|
||||||
|
* function will swap **OldNode for *NewNode.
|
||||||
|
* In this case, *OldNode will point to the node
|
||||||
|
* that was removed (thus allowing you to free
|
||||||
|
* the node).
|
||||||
|
* ** If you are using overwrite mode, ALWAYS **
|
||||||
|
* ** check the return value of this parameter! **
|
||||||
|
* Note: You may pass NULL in this parameter, the
|
||||||
|
* function knows how to cope. If you do this,
|
||||||
|
* however, there will be no way to return a
|
||||||
|
* pointer to an old (ie. replaced) node (which is
|
||||||
|
* a problem if you are using overwrite mode).
|
||||||
|
*
|
||||||
|
* Output: a boolean value indicating success or failure. The function
|
||||||
|
* will return FALSE if the node could not be added to the tree.
|
||||||
|
* Such failure will only occur if duplicates are not allowed,
|
||||||
|
* nodes cannot be overwritten, AND a duplicate key was found
|
||||||
|
* within the tree.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr OtherP;
|
||||||
|
|
||||||
|
if( !(OldNode) )
|
||||||
|
OldNode = &OtherP;
|
||||||
|
|
||||||
|
if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
|
||||||
|
{
|
||||||
|
RootPtr->root = Splay( NewNode );
|
||||||
|
return( ubi_trTRUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Splay the unreplacable, duplicate keyed, unique, old node. */
|
||||||
|
RootPtr->root = Splay( (*OldNode) );
|
||||||
|
return( ubi_trFALSE );
|
||||||
|
} /* ubi_sptInsert */
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function removes the indicated node from the tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - A pointer to the header of the tree that contains
|
||||||
|
* the node to be removed.
|
||||||
|
* DeadNode - A pointer to the node that will be removed.
|
||||||
|
*
|
||||||
|
* Output: This function returns a pointer to the node that was removed
|
||||||
|
* from the tree (ie. the same as DeadNode).
|
||||||
|
*
|
||||||
|
* Note: The node MUST be in the tree indicated by RootPtr. If not,
|
||||||
|
* strange and evil things will happen to your trees.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr p;
|
||||||
|
|
||||||
|
(void)Splay( DeadNode ); /* Move dead node to root. */
|
||||||
|
if( NULL != (p = DeadNode->Link[ubi_trLEFT]) )
|
||||||
|
{ /* If left subtree exists... */
|
||||||
|
ubi_btNodePtr q = DeadNode->Link[ubi_trRIGHT];
|
||||||
|
|
||||||
|
p->Link[ubi_trPARENT] = NULL; /* Left subtree node becomes root.*/
|
||||||
|
p->gender = ubi_trPARENT;
|
||||||
|
p = ubi_btLast( p ); /* Find rightmost left node... */
|
||||||
|
p->Link[ubi_trRIGHT] = q; /* ...attach right tree. */
|
||||||
|
if( q )
|
||||||
|
q->Link[ubi_trPARENT] = p;
|
||||||
|
RootPtr->root = Splay( p ); /* Resplay at p. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( NULL != (p = DeadNode->Link[ubi_trRIGHT]) )
|
||||||
|
{ /* No left, but right subtree exists... */
|
||||||
|
p->Link[ubi_trPARENT] = NULL; /* Right subtree root becomes... */
|
||||||
|
p->gender = ubi_trPARENT; /* ...overall tree root. */
|
||||||
|
RootPtr->root = p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RootPtr->root = NULL; /* No subtrees => empty tree. */
|
||||||
|
}
|
||||||
|
|
||||||
|
(RootPtr->count)--; /* Decrement node count. */
|
||||||
|
return( DeadNode ); /* Return pointer to pruned node. */
|
||||||
|
} /* ubi_sptRemove */
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe,
|
||||||
|
ubi_trCompOps CompOp )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* The purpose of ubi_btLocate() is to find a node or set of nodes given
|
||||||
|
* a target value and a "comparison operator". The Locate() function is
|
||||||
|
* more flexible and (in the case of trees that may contain dupicate keys)
|
||||||
|
* more precise than the ubi_btFind() function. The latter is faster,
|
||||||
|
* but it only searches for exact matches and, if the tree contains
|
||||||
|
* duplicates, Find() may return a pointer to any one of the duplicate-
|
||||||
|
* keyed records.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - A pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - An ubi_btItemPtr that indicates the key for which to
|
||||||
|
* search.
|
||||||
|
* CompOp - One of the following:
|
||||||
|
* CompOp Return a pointer to the node with
|
||||||
|
* ------ ---------------------------------
|
||||||
|
* ubi_trLT - the last key value that is less
|
||||||
|
* than FindMe.
|
||||||
|
* ubi_trLE - the first key matching FindMe, or
|
||||||
|
* the last key that is less than
|
||||||
|
* FindMe.
|
||||||
|
* ubi_trEQ - the first key matching FindMe.
|
||||||
|
* ubi_trGE - the first key matching FindMe, or the
|
||||||
|
* first key greater than FindMe.
|
||||||
|
* ubi_trGT - the first key greater than FindMe.
|
||||||
|
* Output:
|
||||||
|
* A pointer to the node matching the criteria listed above under
|
||||||
|
* CompOp, or NULL if no node matched the criteria.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* In the case of trees with duplicate keys, Locate() will behave as
|
||||||
|
* follows:
|
||||||
|
*
|
||||||
|
* Find: 3 Find: 3
|
||||||
|
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
|
||||||
|
* ^ ^ ^ ^ ^
|
||||||
|
* LT EQ GT LE GE
|
||||||
|
*
|
||||||
|
* That is, when returning a pointer to a node with a key that is LESS
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* LAST matching node.
|
||||||
|
* When returning a pointer to a node with a key that is GREATER
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* FIRST matching node.
|
||||||
|
*
|
||||||
|
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr p;
|
||||||
|
|
||||||
|
p = ubi_btLocate( RootPtr, FindMe, CompOp );
|
||||||
|
if( p )
|
||||||
|
RootPtr->root = Splay( p );
|
||||||
|
return( p );
|
||||||
|
} /* ubi_sptLocate */
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function performs a non-recursive search of a tree for any node
|
||||||
|
* matching a specific key.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - a pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - a pointer to the key value for which to search.
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* A pointer to a node with a key that matches the key indicated by
|
||||||
|
* FindMe, or NULL if no such node was found.
|
||||||
|
*
|
||||||
|
* Note: In a tree that allows duplicates, the pointer returned *might
|
||||||
|
* not* point to the (sequentially) first occurance of the
|
||||||
|
* desired key. In such a tree, it may be more useful to use
|
||||||
|
* ubi_sptLocate().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_btNodePtr p;
|
||||||
|
|
||||||
|
p = ubi_btFind( RootPtr, FindMe );
|
||||||
|
if( p )
|
||||||
|
RootPtr->root = Splay( p );
|
||||||
|
return( p );
|
||||||
|
} /* ubi_sptFind */
|
||||||
|
|
||||||
|
void ubi_sptSplay( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr SplayMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function allows you to splay the tree at a given node, thus moving
|
||||||
|
* the node to the top of the tree.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - a pointer to the header of the tree to be splayed.
|
||||||
|
* SplayMe - a pointer to a node within the tree. This will become
|
||||||
|
* the new root node.
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* Notes: This is an uncharacteristic function for this group of modules
|
||||||
|
* in that it provides access to the internal balancing routines,
|
||||||
|
* which would normally be hidden.
|
||||||
|
* Splaying the tree will not damage it (assuming that I've done
|
||||||
|
* *my* job), but there is overhead involved. I don't recommend
|
||||||
|
* that you use this function unless you understand the underlying
|
||||||
|
* Splay Tree principles involved.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
RootPtr->root = Splay( SplayMe );
|
||||||
|
} /* ubi_sptSplay */
|
||||||
|
|
||||||
|
int ubi_sptModuleID( int size, char *list[] )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a set of strings that identify the module.
|
||||||
|
*
|
||||||
|
* Input: size - The number of elements in the array <list>.
|
||||||
|
* list - An array of pointers of type (char *). This array
|
||||||
|
* should, initially, be empty. This function will fill
|
||||||
|
* in the array with pointers to strings.
|
||||||
|
* Output: The number of elements of <list> that were used. If this value
|
||||||
|
* is less than <size>, the values of the remaining elements are
|
||||||
|
* not guaranteed.
|
||||||
|
*
|
||||||
|
* Notes: Please keep in mind that the pointers returned indicate strings
|
||||||
|
* stored in static memory. Don't free() them, don't write over
|
||||||
|
* them, etc. Just read them.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if( size > 0 )
|
||||||
|
{
|
||||||
|
list[0] = ModuleID;
|
||||||
|
if( size > 1 )
|
||||||
|
return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
|
||||||
|
return( 1 );
|
||||||
|
}
|
||||||
|
return( 0 );
|
||||||
|
} /* ubi_sptModuleID */
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
||||||
|
|
377
lib/ubi_SplayTree.h
Normal file
377
lib/ubi_SplayTree.h
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
#ifndef UBI_SPLAYTREE_H
|
||||||
|
#define UBI_SPLAYTREE_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_SplayTree.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1993-1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This module implements "splay" trees. Splay trees are binary trees
|
||||||
|
* that are rearranged (splayed) whenever a node is accessed. The
|
||||||
|
* splaying process *tends* to make the tree bushier (improves balance),
|
||||||
|
* and the nodes that are accessed most frequently *tend* to be closer to
|
||||||
|
* the top.
|
||||||
|
*
|
||||||
|
* References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
|
||||||
|
* Robert Tarjan. Journal of the Association for Computing
|
||||||
|
* Machinery Vol 32, No. 3, July 1985 pp. 652-686
|
||||||
|
*
|
||||||
|
* See also: http://www.cs.cmu.edu/~sleator/
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_SplayTree.h,v
|
||||||
|
* Revision 4.5 2000/01/08 23:26:49 crh
|
||||||
|
* Added ubi_trSplay() macro, which does a type cast for us.
|
||||||
|
*
|
||||||
|
* Revision 4.4 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 4.3 1998/06/03 17:45:05 crh
|
||||||
|
* Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is
|
||||||
|
* included by all of the binary tree files.
|
||||||
|
*
|
||||||
|
* Also fixed some warnings produced by lint on Irix 6.2, which doesn't seem
|
||||||
|
* to like syntax like this:
|
||||||
|
*
|
||||||
|
* if( (a = b) )
|
||||||
|
*
|
||||||
|
* The fix was to change lines like the above to:
|
||||||
|
*
|
||||||
|
* if( 0 != (a=b) )
|
||||||
|
*
|
||||||
|
* Which means the same thing.
|
||||||
|
*
|
||||||
|
* Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in
|
||||||
|
* ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping
|
||||||
|
* of tree types by simply changing a header. Unfortunately, the
|
||||||
|
* macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will
|
||||||
|
* conflict if used together. You must either choose a single tree
|
||||||
|
* type, or use the underlying function calls directly. Compare
|
||||||
|
* the two header files for more information.
|
||||||
|
*
|
||||||
|
* Revision 4.2 1998/06/02 01:29:14 crh
|
||||||
|
* Changed ubi_null.h to sys_include.h to make it more generic.
|
||||||
|
*
|
||||||
|
* Revision 4.1 1998/05/20 04:37:54 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 4.0 1998/03/10 03:40:57 crh
|
||||||
|
* Minor comment changes. The revision number is now 4.0 to match the
|
||||||
|
* BinTree and AVLtree modules.
|
||||||
|
*
|
||||||
|
* Revision 2.7 1998/01/24 06:37:57 crh
|
||||||
|
* Added a URL for more information.
|
||||||
|
*
|
||||||
|
* Revision 2.6 1997/12/23 04:02:20 crh
|
||||||
|
* In this version, all constants & macros defined in the header file have
|
||||||
|
* the ubi_tr prefix. Also cleaned up anything that gcc complained about
|
||||||
|
* when run with '-pedantic -fsyntax-only -Wall'.
|
||||||
|
*
|
||||||
|
* Revision 2.5 1997/07/26 04:15:46 crh
|
||||||
|
* + Cleaned up a few minor syntax annoyances that gcc discovered for me.
|
||||||
|
* + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
|
||||||
|
*
|
||||||
|
* Revision 2.4 1997/06/03 05:22:56 crh
|
||||||
|
* Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
|
||||||
|
* problems.
|
||||||
|
*
|
||||||
|
* Revision 2.3 1995/10/03 22:19:37 CRH
|
||||||
|
* Ubisized!
|
||||||
|
* Also, added the function ubi_sptSplay().
|
||||||
|
*
|
||||||
|
* Revision 2.1 95/03/09 23:55:04 CRH
|
||||||
|
* Added the ModuleID static string and function. These modules are now
|
||||||
|
* self-identifying.
|
||||||
|
*
|
||||||
|
* Revision 2.0 95/02/27 22:34:55 CRH
|
||||||
|
* This module was updated to match the interface changes made to the
|
||||||
|
* ubi_BinTree module. In particular, the interface to the Locate() function
|
||||||
|
* has changed. See ubi_BinTree for more information on changes and new
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* The revision number was also upped to match ubi_BinTree.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Revision 1.0 93/10/15 22:59:36 CRH
|
||||||
|
* With this revision, I have added a set of #define's that provide a single,
|
||||||
|
* standard API to all existing tree modules. Until now, each of the three
|
||||||
|
* existing modules had a different function and typedef prefix, as follows:
|
||||||
|
*
|
||||||
|
* Module Prefix
|
||||||
|
* ubi_BinTree ubi_bt
|
||||||
|
* ubi_AVLtree ubi_avl
|
||||||
|
* ubi_SplayTree ubi_spt
|
||||||
|
*
|
||||||
|
* To further complicate matters, only those portions of the base module
|
||||||
|
* (ubi_BinTree) that were superceeded in the new module had the new names.
|
||||||
|
* For example, if you were using ubi_SplayTree, the locate function was
|
||||||
|
* called "ubi_sptLocate", but the next and previous functions remained
|
||||||
|
* "ubi_btNext" and "ubi_btPrev".
|
||||||
|
*
|
||||||
|
* This was not too terrible if you were familiar with the modules and knew
|
||||||
|
* exactly which tree model you wanted to use. If you wanted to be able to
|
||||||
|
* change modules (for speed comparisons, etc), things could get messy very
|
||||||
|
* quickly.
|
||||||
|
*
|
||||||
|
* So, I have added a set of defined names that get redefined in any of the
|
||||||
|
* descendant modules. To use this standardized interface in your code,
|
||||||
|
* simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
|
||||||
|
* "ubi_tr". The "ubi_tr" names will resolve to the correct function or
|
||||||
|
* datatype names for the module that you are using. Just remember to
|
||||||
|
* include the header for that module in your program file. Because these
|
||||||
|
* names are handled by the preprocessor, there is no added run-time
|
||||||
|
* overhead.
|
||||||
|
*
|
||||||
|
* Note that the original names do still exist, and can be used if you wish
|
||||||
|
* to write code directly to a specific module. This should probably only be
|
||||||
|
* done if you are planning to implement a new descendant type, such as
|
||||||
|
* red/black trees. CRH
|
||||||
|
*
|
||||||
|
* Revision 0.0 93/04/21 23:07:13 CRH
|
||||||
|
* Initial version, written by Christopher R. Hertel.
|
||||||
|
* This module implements Splay Trees using the ubi_BinTree module as a basis.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ubi_BinTree.h" /* Base binary tree functions, types, etc. */
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Function prototypes...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_trBool ubi_sptInsert( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr NewNode,
|
||||||
|
ubi_btItemPtr ItemPtr,
|
||||||
|
ubi_btNodePtr *OldNode );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function uses a non-recursive algorithm to add a new element to the
|
||||||
|
* splay tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - a pointer to the ubi_btRoot structure that indicates
|
||||||
|
* the root of the tree to which NewNode is to be added.
|
||||||
|
* NewNode - a pointer to an ubi_btNode structure that is NOT
|
||||||
|
* part of any tree.
|
||||||
|
* ItemPtr - A pointer to the sort key that is stored within
|
||||||
|
* *NewNode. ItemPtr MUST point to information stored
|
||||||
|
* in *NewNode or an EXACT DUPLICATE. The key data
|
||||||
|
* indicated by ItemPtr is used to place the new node
|
||||||
|
* into the tree.
|
||||||
|
* OldNode - a pointer to an ubi_btNodePtr. When searching
|
||||||
|
* the tree, a duplicate node may be found. If
|
||||||
|
* duplicates are allowed, then the new node will
|
||||||
|
* be simply placed into the tree. If duplicates
|
||||||
|
* are not allowed, however, then one of two things
|
||||||
|
* may happen.
|
||||||
|
* 1) if overwritting *is not* allowed, this
|
||||||
|
* function will return FALSE (indicating that
|
||||||
|
* the new node could not be inserted), and
|
||||||
|
* *OldNode will point to the duplicate that is
|
||||||
|
* still in the tree.
|
||||||
|
* 2) if overwritting *is* allowed, then this
|
||||||
|
* function will swap **OldNode for *NewNode.
|
||||||
|
* In this case, *OldNode will point to the node
|
||||||
|
* that was removed (thus allowing you to free
|
||||||
|
* the node).
|
||||||
|
* ** If you are using overwrite mode, ALWAYS **
|
||||||
|
* ** check the return value of this parameter! **
|
||||||
|
* Note: You may pass NULL in this parameter, the
|
||||||
|
* function knows how to cope. If you do this,
|
||||||
|
* however, there will be no way to return a
|
||||||
|
* pointer to an old (ie. replaced) node (which is
|
||||||
|
* a problem if you are using overwrite mode).
|
||||||
|
*
|
||||||
|
* Output: a boolean value indicating success or failure. The function
|
||||||
|
* will return FALSE if the node could not be added to the tree.
|
||||||
|
* Such failure will only occur if duplicates are not allowed,
|
||||||
|
* nodes cannot be overwritten, AND a duplicate key was found
|
||||||
|
* within the tree.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function removes the indicated node from the tree.
|
||||||
|
*
|
||||||
|
* Input: RootPtr - A pointer to the header of the tree that contains
|
||||||
|
* the node to be removed.
|
||||||
|
* DeadNode - A pointer to the node that will be removed.
|
||||||
|
*
|
||||||
|
* Output: This function returns a pointer to the node that was removed
|
||||||
|
* from the tree (ie. the same as DeadNode).
|
||||||
|
*
|
||||||
|
* Note: The node MUST be in the tree indicated by RootPtr. If not,
|
||||||
|
* strange and evil things will happen to your trees.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe,
|
||||||
|
ubi_trCompOps CompOp );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* The purpose of ubi_btLocate() is to find a node or set of nodes given
|
||||||
|
* a target value and a "comparison operator". The Locate() function is
|
||||||
|
* more flexible and (in the case of trees that may contain dupicate keys)
|
||||||
|
* more precise than the ubi_btFind() function. The latter is faster,
|
||||||
|
* but it only searches for exact matches and, if the tree contains
|
||||||
|
* duplicates, Find() may return a pointer to any one of the duplicate-
|
||||||
|
* keyed records.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - A pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - An ubi_btItemPtr that indicates the key for which to
|
||||||
|
* search.
|
||||||
|
* CompOp - One of the following:
|
||||||
|
* CompOp Return a pointer to the node with
|
||||||
|
* ------ ---------------------------------
|
||||||
|
* ubi_trLT - the last key value that is less
|
||||||
|
* than FindMe.
|
||||||
|
* ubi_trLE - the first key matching FindMe, or
|
||||||
|
* the last key that is less than
|
||||||
|
* FindMe.
|
||||||
|
* ubi_trEQ - the first key matching FindMe.
|
||||||
|
* ubi_trGE - the first key matching FindMe, or the
|
||||||
|
* first key greater than FindMe.
|
||||||
|
* ubi_trGT - the first key greater than FindMe.
|
||||||
|
* Output:
|
||||||
|
* A pointer to the node matching the criteria listed above under
|
||||||
|
* CompOp, or NULL if no node matched the criteria.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* In the case of trees with duplicate keys, Locate() will behave as
|
||||||
|
* follows:
|
||||||
|
*
|
||||||
|
* Find: 3 Find: 3
|
||||||
|
* Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6
|
||||||
|
* ^ ^ ^ ^ ^
|
||||||
|
* LT EQ GT LE GE
|
||||||
|
*
|
||||||
|
* That is, when returning a pointer to a node with a key that is LESS
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* LAST matching node.
|
||||||
|
* When returning a pointer to a node with a key that is GREATER
|
||||||
|
* THAN the target key (FindMe), Locate() will return a pointer to the
|
||||||
|
* FIRST matching node.
|
||||||
|
*
|
||||||
|
* See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btItemPtr FindMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function performs a non-recursive search of a tree for any node
|
||||||
|
* matching a specific key.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - a pointer to the header of the tree to be searched.
|
||||||
|
* FindMe - a pointer to the key value for which to search.
|
||||||
|
*
|
||||||
|
* Output:
|
||||||
|
* A pointer to a node with a key that matches the key indicated by
|
||||||
|
* FindMe, or NULL if no such node was found.
|
||||||
|
*
|
||||||
|
* Note: In a tree that allows duplicates, the pointer returned *might
|
||||||
|
* not* point to the (sequentially) first occurance of the
|
||||||
|
* desired key. In such a tree, it may be more useful to use
|
||||||
|
* ubi_sptLocate().
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ubi_sptSplay( ubi_btRootPtr RootPtr,
|
||||||
|
ubi_btNodePtr SplayMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* This function allows you to splay the tree at a given node, thus moving
|
||||||
|
* the node to the top of the tree.
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* RootPtr - a pointer to the header of the tree to be splayed.
|
||||||
|
* SplayMe - a pointer to a node within the tree. This will become
|
||||||
|
* the new root node.
|
||||||
|
* Output: None.
|
||||||
|
*
|
||||||
|
* Notes: This is an uncharacteristic function for this group of modules
|
||||||
|
* in that it provides access to the internal balancing routines,
|
||||||
|
* which would normally be hidden.
|
||||||
|
* Splaying the tree will not damage it (assuming that I've done
|
||||||
|
* *my* job), but there is overhead involved. I don't recommend
|
||||||
|
* that you use this function unless you understand the underlying
|
||||||
|
* Splay Tree principles involved.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ubi_sptModuleID( int size, char *list[] );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Returns a set of strings that identify the module.
|
||||||
|
*
|
||||||
|
* Input: size - The number of elements in the array <list>.
|
||||||
|
* list - An array of pointers of type (char *). This array
|
||||||
|
* should, initially, be empty. This function will fill
|
||||||
|
* in the array with pointers to strings.
|
||||||
|
* Output: The number of elements of <list> that were used. If this value
|
||||||
|
* is less than <size>, the values of the remaining elements are
|
||||||
|
* not guaranteed.
|
||||||
|
*
|
||||||
|
* Notes: Please keep in mind that the pointers returned indicate strings
|
||||||
|
* stored in static memory. Don't free() them, don't write over
|
||||||
|
* them, etc. Just read them.
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- **
|
||||||
|
* Masquarade...
|
||||||
|
*
|
||||||
|
* This set of defines allows you to write programs that will use any of the
|
||||||
|
* implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
|
||||||
|
* Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
|
||||||
|
* including the appropriate module header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef ubi_trInsert
|
||||||
|
#undef ubi_trRemove
|
||||||
|
#undef ubi_trLocate
|
||||||
|
#undef ubi_trFind
|
||||||
|
#undef ubi_trModuleID
|
||||||
|
|
||||||
|
#define ubi_trInsert( Rp, Nn, Ip, On ) \
|
||||||
|
ubi_sptInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
|
||||||
|
(ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
|
||||||
|
|
||||||
|
#define ubi_trRemove( Rp, Dn ) \
|
||||||
|
ubi_sptRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
|
||||||
|
|
||||||
|
#define ubi_trLocate( Rp, Ip, Op ) \
|
||||||
|
ubi_sptLocate( (ubi_btRootPtr)(Rp), \
|
||||||
|
(ubi_btItemPtr)(Ip), \
|
||||||
|
(ubi_trCompOps)(Op) )
|
||||||
|
|
||||||
|
#define ubi_trFind( Rp, Ip ) \
|
||||||
|
ubi_sptFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
|
||||||
|
|
||||||
|
#define ubi_trSplay( Rp, Sm ) \
|
||||||
|
ubi_sptSplay( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Sm) )
|
||||||
|
|
||||||
|
#define ubi_trModuleID( s, l ) ubi_sptModuleID( s, l )
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
||||||
|
#endif /* UBI_SPLAYTREE_H */
|
172
lib/ubi_dLinkList.c
Normal file
172
lib/ubi_dLinkList.c
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_dLinkList.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997, 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements simple doubly-linked lists.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_dLinkList.c,v
|
||||||
|
* Revision 0.11 1999/06/19 16:58:06 crh
|
||||||
|
* Renamed the ubi_slRemove() function in ubi_sLinkList to
|
||||||
|
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
|
||||||
|
* match the functionality of the ubi_dlRemove() function in
|
||||||
|
* ubi_dLinkList. The new name is more 'correct'.
|
||||||
|
*
|
||||||
|
* Revision 0.10 1998/07/24 07:30:20 crh
|
||||||
|
* Added the ubi_dlNewList() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.9 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 0.8 1998/06/03 18:06:03 crh
|
||||||
|
* Further fiddling with sys_include.h, which has been moved from the .c file
|
||||||
|
* to the .h file.
|
||||||
|
*
|
||||||
|
* Revision 0.7 1998/06/02 01:38:47 crh
|
||||||
|
* Changed include file name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.6 1998/05/20 04:38:05 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.5 1998/03/10 02:55:00 crh
|
||||||
|
* Simplified the code and added macros for stack & queue manipulations.
|
||||||
|
*
|
||||||
|
* Revision 0.4 1998/01/03 01:53:56 crh
|
||||||
|
* Added ubi_dlCount() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1997/10/15 03:05:39 crh
|
||||||
|
* Added some handy type casting to the macros. Added AddHere and RemThis
|
||||||
|
* macros.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1997/10/08 03:07:21 crh
|
||||||
|
* Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
|
||||||
|
* macro, which was passing the wrong value for <After> to Insert().
|
||||||
|
*
|
||||||
|
* Revision 0.1 1997/10/07 04:34:07 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module is similar to the ubi_sLinkList module, but it is neither a
|
||||||
|
* descendant type nor an easy drop-in replacement for the latter. One key
|
||||||
|
* difference is that the ubi_dlRemove() function removes the indicated node,
|
||||||
|
* while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
|
||||||
|
* *following* the indicated node.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libs.h"
|
||||||
|
#include "ubi_dLinkList.h" /* Header for *this* module. */
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a doubly-linked list header.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list structure that is to be
|
||||||
|
* initialized for use.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized list header (i.e., same as
|
||||||
|
* <ListPtr>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ListPtr->Head = NULL;
|
||||||
|
ListPtr->Tail = NULL;
|
||||||
|
ListPtr->count = 0;
|
||||||
|
return( ListPtr );
|
||||||
|
} /* ubi_dlInitList */
|
||||||
|
|
||||||
|
ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
|
||||||
|
ubi_dlNodePtr New,
|
||||||
|
ubi_dlNodePtr After )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Insert a new node into the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list into which the node is to
|
||||||
|
* be inserted.
|
||||||
|
* New - Pointer to the new node.
|
||||||
|
* After - NULL, or a pointer to a node that is already in the
|
||||||
|
* list.
|
||||||
|
* If NULL, then <New> will be added at the head of the
|
||||||
|
* list, else it will be added following <After>.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was inserted into the list (i.e.,
|
||||||
|
* the same as <New>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_dlNodePtr PredNode = After ? After : (ubi_dlNodePtr)ListPtr;
|
||||||
|
|
||||||
|
New->Next = PredNode->Next;
|
||||||
|
New->Prev = After;
|
||||||
|
PredNode->Next = New;
|
||||||
|
if( New->Next )
|
||||||
|
New->Next->Prev = New;
|
||||||
|
else
|
||||||
|
ListPtr->Tail = New;
|
||||||
|
|
||||||
|
(ListPtr->count)++;
|
||||||
|
|
||||||
|
return( New );
|
||||||
|
} /* ubi_dlInsert */
|
||||||
|
|
||||||
|
ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove a node from the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list from which <Old> is to be
|
||||||
|
* removed.
|
||||||
|
* Old - A pointer to the node that is to be removed from the
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was removed (i.e., <Old>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if( Old )
|
||||||
|
{
|
||||||
|
if( Old->Next )
|
||||||
|
Old->Next->Prev = Old->Prev;
|
||||||
|
else
|
||||||
|
ListPtr->Tail = Old->Prev;
|
||||||
|
|
||||||
|
if( Old->Prev )
|
||||||
|
Old->Prev->Next = Old->Next;
|
||||||
|
else
|
||||||
|
ListPtr->Head = Old->Next;
|
||||||
|
|
||||||
|
(ListPtr->count)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( Old );
|
||||||
|
} /* ubi_dlRemove */
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
241
lib/ubi_dLinkList.h
Normal file
241
lib/ubi_dLinkList.h
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
#ifndef UBI_DLINKLIST_H
|
||||||
|
#define UBI_DLINKLIST_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_dLinkList.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997, 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements simple doubly-linked lists.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_dLinkList.h,v
|
||||||
|
* Revision 0.11 1999/06/19 16:58:06 crh
|
||||||
|
* Renamed the ubi_slRemove() function in ubi_sLinkList to
|
||||||
|
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
|
||||||
|
* match the functionality of the ubi_dlRemove() function in
|
||||||
|
* ubi_dLinkList. The new name is more 'correct'.
|
||||||
|
*
|
||||||
|
* Revision 0.10 1998/07/24 07:30:20 crh
|
||||||
|
* Added the ubi_dlNewList() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.9 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 0.8 1998/06/03 18:06:03 crh
|
||||||
|
* Further fiddling with sys_include.h, which has been moved from the .c file
|
||||||
|
* to the .h file.
|
||||||
|
*
|
||||||
|
* Revision 0.7 1998/06/02 01:38:47 crh
|
||||||
|
* Changed include file name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.6 1998/05/20 04:38:05 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.5 1998/03/10 02:54:04 crh
|
||||||
|
* Simplified the code and added macros for stack & queue manipulations.
|
||||||
|
*
|
||||||
|
* Revision 0.4 1998/01/03 01:53:44 crh
|
||||||
|
* Added ubi_dlCount() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1997/10/15 03:04:31 crh
|
||||||
|
* Added some handy type casting to the macros. Added AddHere and RemThis
|
||||||
|
* macros.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1997/10/08 03:08:16 crh
|
||||||
|
* Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
|
||||||
|
* macro, which was passing the wrong value for <After> to Insert().
|
||||||
|
*
|
||||||
|
* Revision 0.1 1997/10/07 04:34:38 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module is similar to the ubi_sLinkList module, but it is neither a
|
||||||
|
* descendant type nor an easy drop-in replacement for the latter. One key
|
||||||
|
* difference is that the ubi_dlRemove() function removes the indicated node,
|
||||||
|
* while the ubi_slRemoveNext() function (in ubi_sLinkList) removes the node
|
||||||
|
* *following* the indicated node.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Typedefs...
|
||||||
|
*
|
||||||
|
* ubi_dlNode - This is the basic node structure.
|
||||||
|
* ubi_dlNodePtr - Pointer to a node.
|
||||||
|
* ubi_dlList - This is the list header structure.
|
||||||
|
* ubi_dlListPtr - Pointer to a List (i.e., a list header structure).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ubi_dlListNode
|
||||||
|
{
|
||||||
|
struct ubi_dlListNode *Next;
|
||||||
|
struct ubi_dlListNode *Prev;
|
||||||
|
} ubi_dlNode;
|
||||||
|
|
||||||
|
typedef ubi_dlNode *ubi_dlNodePtr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ubi_dlNodePtr Head;
|
||||||
|
ubi_dlNodePtr Tail;
|
||||||
|
unsigned long count;
|
||||||
|
} ubi_dlList;
|
||||||
|
|
||||||
|
typedef ubi_dlList *ubi_dlListPtr;
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Macros...
|
||||||
|
*
|
||||||
|
* ubi_dlNewList - Macro used to declare and initialize a new list in one
|
||||||
|
* swell foop. It is used when defining a variable of
|
||||||
|
* type ubi_dlList. The definition
|
||||||
|
* static ubi_dlNewList( gerbil );
|
||||||
|
* is translated to
|
||||||
|
* static ubi_dlList gerbil[1] = {{ NULL, NULL, 0 }};
|
||||||
|
*
|
||||||
|
* ubi_dlCount - Return the number of entries currently in the list.
|
||||||
|
*
|
||||||
|
* ubi_dlAddHead - Add a new node at the head of the list.
|
||||||
|
* ubi_dlAddNext - Add a node following the given node.
|
||||||
|
* ubi_dlAddTail - Add a new node at the tail of the list.
|
||||||
|
* Note: AddTail evaluates the L parameter twice.
|
||||||
|
*
|
||||||
|
* ubi_dlRemHead - Remove the node at the head of the list, if any.
|
||||||
|
* Note: RemHead evaluates the L parameter twice.
|
||||||
|
* ubi_dlRemThis - Remove the indicated node.
|
||||||
|
* ubi_dlRemTail - Remove the node at the tail of the list, if any.
|
||||||
|
* Note: RemTail evaluates the L parameter twice.
|
||||||
|
*
|
||||||
|
* ubi_dlFirst - Return a pointer to the first node in the list, if any.
|
||||||
|
* ubi_dlLast - Return a pointer to the last node in the list, if any.
|
||||||
|
* ubi_dlNext - Given a node, return a pointer to the next node.
|
||||||
|
* ubi_dlPrev - Given a node, return a pointer to the previous node.
|
||||||
|
*
|
||||||
|
* ubi_dlPush - Add a node at the head of the list (synonym of AddHead).
|
||||||
|
* ubi_dlPop - Remove a node at the head of the list (synonym of RemHead).
|
||||||
|
* ubi_dlEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
|
||||||
|
* ubi_dlDequeue - Remove a node at the head of the list (synonym of RemHead).
|
||||||
|
*
|
||||||
|
* Note that all of these provide type casting of the parameters. The
|
||||||
|
* Add and Rem macros are nothing more than nice front-ends to the
|
||||||
|
* Insert and Remove operations.
|
||||||
|
*
|
||||||
|
* Also note that the First, Next and Last macros do no parameter checking!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_dlNewList( L ) ubi_dlList (L)[1] = {{ NULL, NULL, 0 }}
|
||||||
|
|
||||||
|
#define ubi_dlCount( L ) (((ubi_dlListPtr)(L))->count)
|
||||||
|
|
||||||
|
#define ubi_dlAddHead( L, N ) \
|
||||||
|
ubi_dlInsert( (ubi_dlListPtr)(L), (ubi_dlNodePtr)(N), NULL )
|
||||||
|
|
||||||
|
#define ubi_dlAddNext( L, N, A ) \
|
||||||
|
ubi_dlInsert( (ubi_dlListPtr)(L), \
|
||||||
|
(ubi_dlNodePtr)(N), \
|
||||||
|
(ubi_dlNodePtr)(A) )
|
||||||
|
|
||||||
|
#define ubi_dlAddTail( L, N ) \
|
||||||
|
ubi_dlInsert( (ubi_dlListPtr)(L), \
|
||||||
|
(ubi_dlNodePtr)(N), \
|
||||||
|
(((ubi_dlListPtr)(L))->Tail) )
|
||||||
|
|
||||||
|
#define ubi_dlRemHead( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
|
||||||
|
(((ubi_dlListPtr)(L))->Head) )
|
||||||
|
|
||||||
|
#define ubi_dlRemThis( L, N ) ubi_dlRemove( (ubi_dlListPtr)(L), \
|
||||||
|
(ubi_dlNodePtr)(N) )
|
||||||
|
|
||||||
|
#define ubi_dlRemTail( L ) ubi_dlRemove( (ubi_dlListPtr)(L), \
|
||||||
|
(((ubi_dlListPtr)(L))->Tail) )
|
||||||
|
|
||||||
|
#define ubi_dlFirst( L ) (((ubi_dlListPtr)(L))->Head)
|
||||||
|
|
||||||
|
#define ubi_dlLast( L ) (((ubi_dlListPtr)(L))->Tail)
|
||||||
|
|
||||||
|
#define ubi_dlNext( N ) (((ubi_dlNodePtr)(N))->Next)
|
||||||
|
|
||||||
|
#define ubi_dlPrev( N ) (((ubi_dlNodePtr)(N))->Prev)
|
||||||
|
|
||||||
|
#define ubi_dlPush ubi_dlAddHead
|
||||||
|
#define ubi_dlPop ubi_dlRemHead
|
||||||
|
#define ubi_dlEnqueue ubi_dlAddTail
|
||||||
|
#define ubi_dlDequeue ubi_dlRemHead
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Function prototypes...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a doubly-linked list header.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list structure that is to be
|
||||||
|
* initialized for use.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized list header (i.e., same as
|
||||||
|
* <ListPtr>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
|
||||||
|
ubi_dlNodePtr New,
|
||||||
|
ubi_dlNodePtr After );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Insert a new node into the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list into which the node is to
|
||||||
|
* be inserted.
|
||||||
|
* New - Pointer to the new node.
|
||||||
|
* After - NULL, or a pointer to a node that is already in the
|
||||||
|
* list.
|
||||||
|
* If NULL, then <New> will be added at the head of the
|
||||||
|
* list, else it will be added following <After>.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was inserted into the list (i.e.,
|
||||||
|
* the same as <New>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove a node from the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list from which <Old> is to be
|
||||||
|
* removed.
|
||||||
|
* Old - A pointer to the node that is to be removed from the
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was removed (i.e., <Old>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
||||||
|
#endif /* UBI_DLINKLIST_H */
|
188
lib/ubi_sLinkList.c
Normal file
188
lib/ubi_sLinkList.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_sLinkList.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997, 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements a simple singly-linked list.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_sLinkList.c,v
|
||||||
|
* Revision 0.10 1999/06/19 16:58:06 crh
|
||||||
|
* Renamed the ubi_slRemove() function in ubi_sLinkList to
|
||||||
|
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
|
||||||
|
* match the functionality of the ubi_dlRemove() function in
|
||||||
|
* ubi_dLinkList. The new name is more 'correct'.
|
||||||
|
*
|
||||||
|
* Revision 0.9 1998/07/24 07:30:20 crh
|
||||||
|
* Added the ubi_slNewList() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.8 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 0.7 1998/06/03 18:06:03 crh
|
||||||
|
* Further fiddling with sys_include.h, which has been moved from the .c file
|
||||||
|
* to the .h file.
|
||||||
|
*
|
||||||
|
* Revision 0.6 1998/06/02 01:38:47 crh
|
||||||
|
* Changed include file name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.5 1998/05/20 04:38:05 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.4 1998/03/10 02:23:20 crh
|
||||||
|
* Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
|
||||||
|
* the functions and macros. Not a complete rewrite but close to it.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1998/01/03 01:59:52 crh
|
||||||
|
* Added ubi_slCount() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1997/10/21 03:35:18 crh
|
||||||
|
* Added parameter <After> in function Insert(). Made necessary changes
|
||||||
|
* to macro AddHead() and added macro AddHere().
|
||||||
|
*
|
||||||
|
* Revision 0.1 1997/10/16 02:53:45 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements a singly-linked list which may also be used as a
|
||||||
|
* queue or a stack. For a queue, entries are added at the tail and removed
|
||||||
|
* from the head of the list. For a stack, the entries are entered and
|
||||||
|
* removed from the head of the list. A traversal of the list will always
|
||||||
|
* start at the head of the list and proceed toward the tail. This is all
|
||||||
|
* mind-numbingly simple, but I'm surprised by the number of programs out
|
||||||
|
* there which re-implement this a dozen or so times.
|
||||||
|
*
|
||||||
|
* Note: When the list header is initialized, the Tail pointer is set to
|
||||||
|
* point to the Head pointer. This simplifies things a great deal,
|
||||||
|
* except that you can't initialize a stack or queue by simply
|
||||||
|
* zeroing it out. One sure way to initialize the header is to call
|
||||||
|
* ubi_slInit(). Another option would be something like this:
|
||||||
|
*
|
||||||
|
* ubi_slNewList( MyList );
|
||||||
|
*
|
||||||
|
* Which translates to:
|
||||||
|
*
|
||||||
|
* ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
|
||||||
|
*
|
||||||
|
* See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
|
||||||
|
* for more info.
|
||||||
|
*
|
||||||
|
* + Also, note that this module is similar to the ubi_dLinkList
|
||||||
|
* module. There are three key differences:
|
||||||
|
* - This is a singly-linked list, the other is a doubly-linked
|
||||||
|
* list.
|
||||||
|
* - In this module, if the list is empty, the tail pointer will
|
||||||
|
* point back to the head of the list as described above. This
|
||||||
|
* is not done in ubi_dLinkList.
|
||||||
|
* - The ubi_slRemoveNext() function, by necessity, removes the
|
||||||
|
* 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
|
||||||
|
* removes the 'current' node.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libs.h"
|
||||||
|
#include "ubi_sLinkList.h" /* Header for *this* module. */
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Functions...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a singly-linked list header.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list structure that is to be
|
||||||
|
* initialized for use.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized list header (i.e., same as
|
||||||
|
* <ListPtr>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ListPtr->Head = NULL;
|
||||||
|
ListPtr->Tail = (ubi_slNodePtr)ListPtr;
|
||||||
|
ListPtr->count = 0;
|
||||||
|
return( ListPtr );
|
||||||
|
} /* ubi_slInitList */
|
||||||
|
|
||||||
|
ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
|
||||||
|
ubi_slNodePtr New,
|
||||||
|
ubi_slNodePtr After )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Add a node to the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list into which the node is to
|
||||||
|
* be inserted.
|
||||||
|
* New - Pointer to the node that is to be added to the list.
|
||||||
|
* After - Pointer to a list in a node after which the new node
|
||||||
|
* will be inserted. If NULL, then the new node will
|
||||||
|
* be added at the head of the list.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was inserted into the list (i.e.,
|
||||||
|
* the same as <New>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
After = After ? After : (ubi_slNodePtr)ListPtr;
|
||||||
|
New->Next = After->Next;
|
||||||
|
After->Next = New;
|
||||||
|
if( !(New->Next) )
|
||||||
|
ListPtr->Tail = New;
|
||||||
|
(ListPtr->count)++;
|
||||||
|
return( New );
|
||||||
|
} /* ubi_slInsert */
|
||||||
|
|
||||||
|
ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe )
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
|
||||||
|
* the head of the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list from which the node is to be
|
||||||
|
* removed.
|
||||||
|
* AfterMe - Pointer to the node preceeding the node to be
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was removed, or NULL if the list is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ubi_slNodePtr DelNode;
|
||||||
|
|
||||||
|
AfterMe = AfterMe ? AfterMe : (ubi_slNodePtr)ListPtr;
|
||||||
|
DelNode = AfterMe->Next;
|
||||||
|
if( DelNode )
|
||||||
|
{
|
||||||
|
if( !(DelNode->Next) )
|
||||||
|
ListPtr->Tail = AfterMe;
|
||||||
|
AfterMe->Next = DelNode->Next;
|
||||||
|
(ListPtr->count)--;
|
||||||
|
}
|
||||||
|
return( DelNode );
|
||||||
|
} /* ubi_slRemoveNext */
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
253
lib/ubi_sLinkList.h
Normal file
253
lib/ubi_sLinkList.h
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
#ifndef UBI_SLINKLIST_H
|
||||||
|
#define UBI_SLINKLIST_H
|
||||||
|
/* ========================================================================== **
|
||||||
|
* ubi_sLinkList.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997, 1998 by Christopher R. Hertel
|
||||||
|
*
|
||||||
|
* Email: crh@ubiqx.mn.org
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements a simple singly-linked list.
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
*
|
||||||
|
* Log: ubi_sLinkList.h,v
|
||||||
|
* Revision 0.10 1999/06/19 16:58:06 crh
|
||||||
|
* Renamed the ubi_slRemove() function in ubi_sLinkList to
|
||||||
|
* ubi_slRemoveNext(). I was bothered by the fact that it didn't
|
||||||
|
* match the functionality of the ubi_dlRemove() function in
|
||||||
|
* ubi_dLinkList. The new name is more 'correct'.
|
||||||
|
*
|
||||||
|
* Revision 0.9 1998/07/24 07:30:20 crh
|
||||||
|
* Added the ubi_slNewList() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.8 1998/06/04 21:29:27 crh
|
||||||
|
* Upper-cased defined constants (eg UBI_BINTREE_H) in some header files.
|
||||||
|
* This is more "standard", and is what people expect. Weird, eh?
|
||||||
|
*
|
||||||
|
* Revision 0.7 1998/06/03 18:06:03 crh
|
||||||
|
* Further fiddling with sys_include.h, which has been moved from the .c file
|
||||||
|
* to the .h file.
|
||||||
|
*
|
||||||
|
* Revision 0.6 1998/06/02 01:38:47 crh
|
||||||
|
* Changed include file name from ubi_null.h to sys_include.h to make it
|
||||||
|
* more generic.
|
||||||
|
*
|
||||||
|
* Revision 0.5 1998/05/20 04:38:05 crh
|
||||||
|
* The C file now includes ubi_null.h. See ubi_null.h for more info.
|
||||||
|
*
|
||||||
|
* Revision 0.4 1998/03/10 02:22:39 crh
|
||||||
|
* Combined ubi_StackQueue and ubi_sLinkList into one module. Redesigned
|
||||||
|
* the functions and macros. Not a complete rewrite but close to it.
|
||||||
|
*
|
||||||
|
* Revision 0.3 1998/01/03 02:00:02 crh
|
||||||
|
* Added ubi_slCount() macro.
|
||||||
|
*
|
||||||
|
* Revision 0.2 1997/10/21 03:36:14 crh
|
||||||
|
* Added parameter <After> in function Insert(). Made necessary changes
|
||||||
|
* to macro AddHead() and added macro AddHere().
|
||||||
|
*
|
||||||
|
* Revision 0.1 1997/10/16 02:54:08 crh
|
||||||
|
* Initial Revision.
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------- **
|
||||||
|
* This module implements a singly-linked list which may also be used as a
|
||||||
|
* queue or a stack. For a queue, entries are added at the tail and removed
|
||||||
|
* from the head of the list. For a stack, the entries are entered and
|
||||||
|
* removed from the head of the list. A traversal of the list will always
|
||||||
|
* start at the head of the list and proceed toward the tail. This is all
|
||||||
|
* mind-numbingly simple, but I'm surprised by the number of programs out
|
||||||
|
* there which re-implement this a dozen or so times.
|
||||||
|
*
|
||||||
|
* Note: When the list header is initialized, the Tail pointer is set to
|
||||||
|
* point to the Head pointer. This simplifies things a great deal,
|
||||||
|
* except that you can't initialize a stack or queue by simply
|
||||||
|
* zeroing it out. One sure way to initialize the header is to call
|
||||||
|
* ubi_slInit(). Another option would be something like this:
|
||||||
|
*
|
||||||
|
* ubi_slNewList( MyList );
|
||||||
|
*
|
||||||
|
* Which translates to:
|
||||||
|
*
|
||||||
|
* ubi_slList MyList[1] = { NULL, (ubi_slNodePtr)MyList, 0 };
|
||||||
|
*
|
||||||
|
* See ubi_slInit(), ubi_slNewList(), and the ubi_slList structure
|
||||||
|
* for more info.
|
||||||
|
*
|
||||||
|
* + Also, note that this module is similar to the ubi_dLinkList
|
||||||
|
* module. There are three key differences:
|
||||||
|
* - This is a singly-linked list, the other is a doubly-linked
|
||||||
|
* list.
|
||||||
|
* - In this module, if the list is empty, the tail pointer will
|
||||||
|
* point back to the head of the list as described above. This
|
||||||
|
* is not done in ubi_dLinkList.
|
||||||
|
* - The ubi_slRemoveNext() function, by necessity, removes the
|
||||||
|
* 'next' node. In ubi_dLinkList, the ubi_dlRemove() function
|
||||||
|
* removes the 'current' node.
|
||||||
|
*
|
||||||
|
* ========================================================================== **
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Typedefs...
|
||||||
|
*
|
||||||
|
* ubi_slNode - This is the basic node structure.
|
||||||
|
* ubi_slNodePtr - Pointer to a node.
|
||||||
|
* ubi_slList - This is the list header structure.
|
||||||
|
* ubi_slListPtr - Pointer to a List (i.e., a list header structure).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ubi_slListNode
|
||||||
|
{
|
||||||
|
struct ubi_slListNode *Next;
|
||||||
|
} ubi_slNode;
|
||||||
|
|
||||||
|
typedef ubi_slNode *ubi_slNodePtr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ubi_slNodePtr Head;
|
||||||
|
ubi_slNodePtr Tail;
|
||||||
|
unsigned long count;
|
||||||
|
} ubi_slList;
|
||||||
|
|
||||||
|
typedef ubi_slList *ubi_slListPtr;
|
||||||
|
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Macros...
|
||||||
|
*
|
||||||
|
* ubi_slNewList - Macro used to declare and initialize a list header in
|
||||||
|
* one step.
|
||||||
|
*
|
||||||
|
* ubi_slCount - Returns the current number of entries in the list.
|
||||||
|
*
|
||||||
|
* ubi_slAddHead - Add a new node at the head of the list.
|
||||||
|
* ubi_slAddNext - Add a new node following the indicated node.
|
||||||
|
* ubi_slAddTail - Add a new node to the tail of the list.
|
||||||
|
* Note: AddTail evaluates the L parameter twice.
|
||||||
|
*
|
||||||
|
* ubi_slRemHead - Remove the node at the head of the list, if any.
|
||||||
|
* ubi_slRemNext - Remove the node following the given node.
|
||||||
|
*
|
||||||
|
* ubi_slFirst - Return a pointer to the first node in the list, if any.
|
||||||
|
* ubi_slNext - Given a node, return a pointer to the next node.
|
||||||
|
* ubi_slLast - Return a pointer to the last node in the list, if any.
|
||||||
|
*
|
||||||
|
* ubi_slPush - Add a node at the head of the list (synonym of AddHead).
|
||||||
|
* ubi_slPop - Remove a node at the head of the list (synonym of RemHead).
|
||||||
|
* ubi_slEnqueue - Add a node at the tail of the list (sysnonym of AddTail).
|
||||||
|
* ubi_slDequeue - Remove a node at the head of the list (synonym of RemHead).
|
||||||
|
*
|
||||||
|
* Note that all of these provide type casting of the parameters. The
|
||||||
|
* Add and Rem macros are nothing more than nice front-ends to the
|
||||||
|
* Insert and Remove functions.
|
||||||
|
*
|
||||||
|
* Also note that the First, Next and Last macros do no parameter checking!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ubi_slNewList( L ) ubi_slList (L)[1] = {{ NULL, (ubi_slNodePtr)(L), 0 }}
|
||||||
|
|
||||||
|
#define ubi_slCount( L ) (((ubi_slListPtr)(L))->count)
|
||||||
|
|
||||||
|
#define ubi_slAddHead( L, N ) \
|
||||||
|
ubi_slInsert( (ubi_slListPtr)(L), (ubi_slNodePtr)(N), NULL )
|
||||||
|
|
||||||
|
#define ubi_slAddNext( L, N, A ) \
|
||||||
|
ubi_slInsert( (ubi_slListPtr)(L), \
|
||||||
|
(ubi_slNodePtr)(N), \
|
||||||
|
(ubi_slNodePtr)(A) )
|
||||||
|
|
||||||
|
#define ubi_slAddTail( L, N ) \
|
||||||
|
ubi_slInsert( (ubi_slListPtr)(L), \
|
||||||
|
(ubi_slNodePtr)(N), \
|
||||||
|
((ubi_slListPtr)(L))->Tail )
|
||||||
|
|
||||||
|
#define ubi_slRemHead( L ) ubi_slRemoveNext( (ubi_slListPtr)(L), NULL )
|
||||||
|
|
||||||
|
#define ubi_slRemNext( L, N ) \
|
||||||
|
ubi_slRemoveNext( (ubi_slListPtr)(L), (ubi_slNodePtr)(N) )
|
||||||
|
|
||||||
|
#define ubi_slFirst( L ) (((ubi_slListPtr)(L))->Head)
|
||||||
|
|
||||||
|
#define ubi_slNext( N ) (((ubi_slNodePtr)(N))->Next)
|
||||||
|
|
||||||
|
#define ubi_slLast( L ) (((ubi_slListPtr)(L))->Tail)
|
||||||
|
|
||||||
|
#define ubi_slPush ubi_slAddHead
|
||||||
|
#define ubi_slPop ubi_slRemHead
|
||||||
|
#define ubi_slEnqueue ubi_slAddTail
|
||||||
|
#define ubi_slDequeue ubi_slRemHead
|
||||||
|
|
||||||
|
/* ========================================================================== **
|
||||||
|
* Function prototypes...
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Initialize a singly-linked list header.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list structure that is to be
|
||||||
|
* initialized for use.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the initialized list header (i.e., same as
|
||||||
|
* <ListPtr>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
|
||||||
|
ubi_slNodePtr New,
|
||||||
|
ubi_slNodePtr After );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Add a node to the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list into which the node is to
|
||||||
|
* be inserted.
|
||||||
|
* New - Pointer to the node that is to be added to the list.
|
||||||
|
* After - Pointer to a list in a node after which the new node
|
||||||
|
* will be inserted. If NULL, then the new node will
|
||||||
|
* be added at the head of the list.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was inserted into the list (i.e.,
|
||||||
|
* the same as <New>).
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
ubi_slNodePtr ubi_slRemoveNext( ubi_slListPtr ListPtr, ubi_slNodePtr AfterMe );
|
||||||
|
/* ------------------------------------------------------------------------ **
|
||||||
|
* Remove the node followng <AfterMe>. If <AfterMe> is NULL, remove from
|
||||||
|
* the head of the list.
|
||||||
|
*
|
||||||
|
* Input: ListPtr - A pointer to the list from which the node is to be
|
||||||
|
* removed.
|
||||||
|
* AfterMe - Pointer to the node preceeding the node to be
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* Output: A pointer to the node that was removed, or NULL if the list is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------ **
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ================================ The End ================================= */
|
||||||
|
#endif /* UBI_SLINKLIST_H */
|
Reference in New Issue
Block a user