From: Richard W.M. Jones Date: Fri, 25 Apr 2014 10:38:47 +0000 (+0100) Subject: Add to git. X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=c2lib.git Add to git. --- 2b18c31fb295d0f1325570a65aac498cb42f5b96 diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..1964f99 --- /dev/null +++ b/.cvsignore @@ -0,0 +1 @@ +build-* \ No newline at end of file diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/COPYING.LIB @@ -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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..4710da2 --- /dev/null +++ b/INSTALL @@ -0,0 +1,30 @@ +Required packages +----------------- + +Before installing c2lib, you need to make sure you have the following +packages installed: + +cdoc http://www.annexia.org/freeware/cdoc/ +make+ http://www.annexia.org/freeware/makeplus/ +pcre http://www.pcre.org/ + +Building and installing +----------------------- + +./configure [--prefix=/usr --sysconfdir=/etc] +make+ +make+ test +make+ install + +See the make+ documentation for additional targets (eg. building RPMs). + +Problems +-------- + +If the build fails, please examine the following files for clues: + +build-*/config.h +build-*/config.mk +build-*/config.log + +If you discover a bug, please contact the package author. diff --git a/Makefile+ b/Makefile+ new file mode 100644 index 0000000..82f2b14 --- /dev/null +++ b/Makefile+ @@ -0,0 +1,411 @@ +# -*- Makefile -*- +# +# This is a make+ file. Make+ is a set of scripts which enhance GNU +# make and let you build RPMs, and other package types with just one +# control file. To build this package you will need to download make+ +# from this site: http://www.annexia.org/freeware/makeplus/ + +PACKAGE := c2lib +VERSION_MAJOR := 1 +VERSION_MINOR := 4.2 +VERSION := $(VERSION_MAJOR).$(VERSION_MINOR) + +SUMMARY := A library of useful functions for C. +COPYRIGHT := GNU LGPL (see http://www.gnu.org/) +AUTHOR := Richard Jones + +define DESCRIPTION +c2lib is a library of useful functions which augment those found in +the standard libc. It contains a pool allocator, many string +functions, STL-like vector and hash types and miscellaneous utilities. +endef + +RPM_REQUIRES := pcre >= 3.9 +RPM_GROUP := Development/Libraries + +CFLAGS += -Wall -Werror -g -O2 -D_GNU_SOURCE +ifneq ($(shell uname), SunOS) +# Avoid a warning about reordering system include paths. +CFLAGS += $(shell pcre-config --cflags) +endif +LIBS += $(shell pcre-config --libs) -lm + +OBJS := hash.o matvec.o pool.o pre.o pstring.o tree.o vector.o +LOBJS := $(OBJS:.o=.lo) +HEADERS := $(srcdir)/hash.h $(srcdir)/matvec.h \ + $(srcdir)/pool.h $(srcdir)/pre.h $(srcdir)/pstring.h \ + $(srcdir)/tree.h $(srcdir)/vector.h + +all: static dynamic manpages syms + +# Configure the system. + +configure: + $(MP_CONFIGURE_START) + $(MP_REQUIRE_PROG) pcre-config + $(MP_CHECK_HEADERS) alloca.h assert.h ctype.h fcntl.h string.h unistd.h + $(MP_CHECK_FUNCS) vasprintf + $(MP_CONFIGURE_END) + +# Build the static library. + +static: libc2lib.a + +libc2lib.a: $(OBJS) + $(MP_LINK_STATIC) $@ $^ + +# Build the dynamic library. + +dynamic: libc2lib.so + +libc2lib.so: $(LOBJS) + $(MP_LINK_DYNAMIC) $@ $^ $(LIBS) + +# Build the manual pages. + +manpages: $(srcdir)/*.h + if cdoc; then \ + rm -f *.3; \ + cdoc \ + --author '$(AUTHOR)' \ + --license '$(COPYRIGHT)' \ + --version '$(PACKAGE)-$(VERSION)' \ + $^; \ + fi + +# Build the symbols table. + +syms: libc2lib.syms + +libc2lib.syms: libc2lib.so + nm $< | sort | grep -i '^[0-9a-f]' | awk '{print $$1 " " $$3}' > $@ + +# Test. + +test: test_hash test_matvec test_pool test_pre test_pstring test_sash \ + test_shash test_tree test_vector + LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH $(MP_RUN_TESTS) $^ + +test_hash: test_hash.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_matvec: test_matvec.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_pool: test_pool.o + $(CC) $(CFLAGS) $^ -o $@ $(LIBS) +test_pre: test_pre.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_pstring: test_pstring.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_sash: test_sash.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_shash: test_shash.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_tree: test_tree.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) +test_vector: test_vector.o + $(CC) $(CFLAGS) $^ -o $@ -L. -lc2lib $(LIBS) + +# Install. + +install: + install -d $(DESTDIR)$(libdir) + install -d $(DESTDIR)$(pkgincludedir) + install -d $(DESTDIR)$(man3dir) + install -d $(DESTDIR)$(datadir)/rws/symtabs/ + + $(MP_INSTALL_STATIC_LIB) libc2lib.a + $(MP_INSTALL_DYNAMIC_LIB) libc2lib.so + install -m 0644 $(HEADERS) $(DESTDIR)$(pkgincludedir) + install -m 0644 *.3 $(DESTDIR)$(man3dir) + install -m 0644 *.syms $(DESTDIR)$(datadir)/rws/symtabs/ + +force: + +define WEBSITE +<% include page_header.msp %> + +

c2lib - a Perl/STL-like library of basics for C

+ +

+ c2lib is a library of basic tools for use by C + programmers. It contains features heavily influenced + by both Perl's string handling and C++'s Standard + Template Library (STL). The library has been designed + to be very easy to use and is fully documented in + manual pages. +

+ +

+ There is extensive documentation and + a tutorial here. +

+ +

Download

+ + + + + + + + + + + + + + + + + + + + + + +
File Format Contents
$(PACKAGE)-$(VERSION).tar.gz tar.gz Latest source distribution
$(PACKAGE)-$(VERSION)-1.i686.rpm i686 binary RPM Binary development libraries, header files, man pages + for Red Hat Linux
$(PACKAGE)-$(VERSION)-1.src.rpm source RPM Source files for Red Hat Linux
+ +

+ Dependencies: +

+ + + +

+ Patches between versions + ... +

+ +

News

+ +

+Sat Mar 1 2003: +Created README and INSTALL files (thanks to David Chappell). Updated +Makefile+ to work with the new version of make+. +NB: The RPMs were built on Debian and may not work on Red Hat +Linux.

+ +

+Sat Feb 8 17:00:47 GMT 2003: +Ported to Solaris, OpenBSD and FreeBSD (thanks to +Jeremy Sowden +and Richard Baker +for help and equipment). Don't link c2lib itself into the +test_pool program. Link test programs correctly +with pcre. +

+ +

+Attn: Solaris +has a library called libc2. I have had to rename this +library to libc2lib, so you will need to link your +programs against -lc2lib. I have also moved the +header files into the c2lib/ subdirectory of +includedir, so you may need to specify -I/usr/include/c2lib +when building. +

+ +

+Sat Dec 7 17:18:02 GMT 2002: Updated to use the +make+ build system. +

+ +

+Mon Nov 25 09:31:37 GMT 2002: Added symbols file for full +symbol resolution in monolith. +

+ +

+ Sun Nov 17 23:31:32 GMT 2002: Debian packages. Added MSP files. + pmalloc now initialises memory to 0xefefefef + so we can catch uninitialised memory problems. Further fixes + to compile on RH 7.3. Added vector_push_back_vector etc. +

+ +

+ Tue Oct 15 23:40:42 BST 2002: Multiple bug fixes. +

+ +

+ Sun Oct 13 12:55:08 BST 2002: Added pmap + and pgrep functions. +

+ +

+ Tue Oct 8 16:18:02 BST 2002: Fix issues with building on + Red Hat Linux 7.3 (thanks to Adam Monsen). The supplied + RPM should now install on Red Hat Linux systems. +

+ +

+ Sun Oct 6 18:07:39 BST 2002: Completely rewrote + the pstr*split functions so they produce the + same results as the Perl equivalents in all the corner + cases. Added pstr*split2 functions (see + the manual pages). +

+ +

+ Sun Oct 6 13:00:39 BST 2002: Added a tree + type (required by monolith). Removed the old pmatch* and + psubst* functions. These were badly thought + out and implemented. Replaced with precomp, + prematch, presubst functions + which are wrappers around the Perl + Compatible Regular Expressions (PCRE) library. + pstrresplit has also changed to use PCRE. +

+ +

+ Sat Sep 7 15:24:32 BST 2002: Packages are + now available as i686 binary RPMs and source RPMs. +

+ +

Old news and old versions

+ +

+ Fri May 2 19:49:25 BST 2002 +

+ +

+ c2lib-1.2.14.tar.gz released. + Added an extensive tutorial and online manual pages. +

+ +

+ Thu Jun 21 23:12:26 BST 2001 +

+ +

+ c2lib-1.2.12.tar.gz released. + Fixed psort function and updated documentation. +

+ +

+ Fri Jun 15 15:40:35 BST 2001 +

+ +

+ c2lib-1.2.11.tar.gz released. + Profiling support. Added pstrncat, + psubst and psubstx functions. + Fixed a memory leak and did rigorous memory leak + checking -- I\'m pretty sure there are none left now. + Removed arbitrary limit on number of substring + matches in pmatch function. + Documentation updates. +

+ +

+ Mon Apr 9 17:18:38 BST 2001 +

+ +

+ c2lib-1.2.8.tar.gz released. + Documentation fixes. +

+ +

+ Wed Mar 28 14:25:42 BST 2001 +

+ +

+ c2lib-1.2.7.tar.gz released. + Fixed a problem with calling isspace on + Solaris (thanks to Tomonori Manome again). +

+ +

+ Mon Mar 26 12:59:15 BST 2001 +

+ +

+ c2lib-1.2.6.tar.gz released. + pstrresplit fixed. + pvector and pvectora functions + added: use these to quickly build vectors from lists of strings. + ptrimfront, ptrimback and ptrim + functions added for trimming whitespace from strings. + pgetline* and pmatch* functions + added which make it trivial to read in configuration files. + new_subvector added for creating sub-vectors + of existing vectors. + Some minor const-correctness changes. + Documentation updates. + Test suite updates. +

+ +

+ Mon Mar 19 11:40:34 GMT 2001 +

+ +

+ c2lib-1.2.3.tar.gz released. + This adds the shash type: a mapping of strings + to anything (another specialized hash). + Port to Solaris/Intel and Solaris/Sparc (thanks to + Tomonori Manome for this). +

+ +

+ Mon Mar 12 12:12:49 GMT 2001 +

+ +

+ c2lib-1.2.1.tar.gz released. + This fixes a bug in the way the library was calling + pstrcat. Upgrading is highly recommended. +

+ +

+ Fri Mar 9 17:26:45 GMT 2001 +

+ +

+ c2lib-1.2.0.tar.gz released. + The pool allocator has been completely rewritten for this + release, and is much more efficient. +

+ +

+ Wed Mar 7 14:56:43 GMT 2001 +

+ +

+ c2lib-1.1.12.tar.gz released. + Added pchrs and pstrs string + functions. Added pvsprintf. Changed + psprintf to make it much more memory efficient + (it uses vasprintf(3) if available). + Const-correctness fixes. +

+ +

+ Fri Feb 16 17:46:41 GMT 2001 +

+ +

+ c2lib-1.1.10.tar.gz released. + All functions are documented in manual pages. +

+ +<% include page_footer.msp %> +endef + +upload_website: + scp $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION)-1.*.rpm \ + $(PACKAGE)-$(VERSION).bin.tar.gz \ + 10.0.0.248:annexia.org/freeware/$(PACKAGE)/ + scp index.html \ + 10.0.0.248:annexia.org/freeware/$(PACKAGE)/index.msp + +.PHONY: static dynamic manpages syms diff --git a/README b/README new file mode 100644 index 0000000..bb9105d --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +This is c2lib from http://www.annexia.org/freeware/c2lib/ + +c2lib is a library of basic tools for use by C programmers. It contains +features heavily influenced by both Perl's string handling and C++'s +Standard Template Library (STL). The library has been designed to be very +easy to use and is fully documented in manual pages. diff --git a/README.Solaris b/README.Solaris new file mode 100644 index 0000000..ddb7726 --- /dev/null +++ b/README.Solaris @@ -0,0 +1 @@ +Ported to Solaris 9 by RWMJ on 2003/02/02. \ No newline at end of file diff --git a/configure b/configure new file mode 100755 index 0000000..04d9db0 --- /dev/null +++ b/configure @@ -0,0 +1,66 @@ +#!/bin/sh - +# +# This is make+. Make+ is a set of scripts which enhance GNU make and +# let you build RPMs, and other packages types with just one control +# file. Read more at http://www.annexia.org/freeware/makeplus/ +# +# The original author is Richard W.M. Jones . +# +# This software has been explicitly placed in the PUBLIC DOMAIN. You +# do not need any sort of license or agreement to use or copy this +# software. You may also copyright this software yourself, and/or +# relicense it under any terms you want, at any time and at no cost. +# This allows you (among other things) to include this software with +# other packages so that the user does not need to download and +# install make+ separately. + +mp_options="" + +usage () +{ + cat < $$f.html; done + rm *.3 man3 + @echo "Now you need to import the HTML files into index.html" diff --git a/doc/collision_moving_sphere_and_face.3.html b/doc/collision_moving_sphere_and_face.3.html new file mode 100644 index 0000000..aa34dfb --- /dev/null +++ b/doc/collision_moving_sphere_and_face.3.html @@ -0,0 +1,105 @@ + + + + +collision_moving_sphere_and_face + + + +

collision_moving_sphere_and_face

+NAME
+SYNOPSIS
+DESCRIPTION
+RETURNS
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+collision_moving_sphere_and_face - detect collision between a moving sphere and a fixed face
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+int collision_moving_sphere_and_face (const float *p0, const float *p1, float radius, const float *points, int nr_points, const float *plane, float *collision_point);
+
+ +

DESCRIPTION

+ + + +
+This function detects collisions between a sphere which is +moving at constant speed along a linear path and a fixed +bounded convex polygon ("face").
+ + + +
+The centre of the sphere moves from point p0 to point +p1. The sphere has radius radius.
+ + + +
+The face is described by the list of bounding points, and +the plane coefficients of the plane of the face (you may +pass plane as NULL in which case the function +works out the plane coefficients for you, although this is +generally less efficient).
+ +

RETURNS

+ + + +
+If there was a collision, this function returns true and +sets the collision point in collision_point. Note +that the collision point is the position of the centre of +the sphere at the point of collision, NOT the place where +the sphere touches the face. If there was no collision, this +function returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/copy_hash.3.html b/doc/copy_hash.3.html new file mode 100644 index 0000000..68eb9fb --- /dev/null +++ b/doc/copy_hash.3.html @@ -0,0 +1,74 @@ + + + + +copy_hash + + + +

copy_hash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+copy_hash - copy a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+hash copy_hash (pool, hash);
+
+ +

DESCRIPTION

+ + + +
+Copy a hash into a new pool. This function copies the keys +and values, but if keys and values are pointers, then it +does not perform a 'deep' copy.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/copy_sash.3.html b/doc/copy_sash.3.html new file mode 100644 index 0000000..34af6c0 --- /dev/null +++ b/doc/copy_sash.3.html @@ -0,0 +1,74 @@ + + + + +copy_sash + + + +

copy_sash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+copy_sash - copy a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+sash copy_sash (pool, sash);
+
+ +

DESCRIPTION

+ + + +
+Copy a sash into a new pool. This function copies the keys +and values, but if keys and values are pointers, then it +does not perform a 'deep' copy.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/copy_shash.3.html b/doc/copy_shash.3.html new file mode 100644 index 0000000..cb8c430 --- /dev/null +++ b/doc/copy_shash.3.html @@ -0,0 +1,74 @@ + + + + +copy_shash + + + +

copy_shash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+copy_shash - copy a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+shash copy_shash (pool, shash);
+
+ +

DESCRIPTION

+ + + +
+Copy a shash into a new pool. This function copies the keys +and values, but if keys and values are pointers, then it +does not perform a 'deep' copy.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/copy_vector.3.html b/doc/copy_vector.3.html new file mode 100644 index 0000000..e96798e --- /dev/null +++ b/doc/copy_vector.3.html @@ -0,0 +1,85 @@ + + + + +copy_vector + + + +

copy_vector

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+copy_vector, new_subvector - copy a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+vector copy_vector (pool, vector v);
+vector new_subvector (pool, vector v, int i, int j);
+
+ +

DESCRIPTION

+ + + +
+Copy a vector v into pool pool. If the vector +contains pointers, then this function will not copy the +pointed-to data as well: you will need to copy this yourself +if appropriate.
+ + + +
+new_subvector creates a copy of part of an existing +vector. The new vector contains the j-i elements of +the old vector starting at element number i and +finishing at element number j-1.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/delete_pool.3.html b/doc/delete_pool.3.html new file mode 100644 index 0000000..86f8412 --- /dev/null +++ b/doc/delete_pool.3.html @@ -0,0 +1,74 @@ + + + + +delete_pool + + + +

delete_pool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+delete_pool - delete a pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void delete_pool (pool);
+
+ +

DESCRIPTION

+ + + +
+Delete a pool or subpool. This also deletes any subpools +that the pool may own (and recursively subpools of those +subpools, etc.)
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/eg_join.c b/doc/eg_join.c new file mode 100644 index 0000000..5592193 --- /dev/null +++ b/doc/eg_join.c @@ -0,0 +1,11 @@ +#include +#include + +const char *strings[] = { "John", "Paul", "George", "Ringo" }; + +main () +{ + pool pool = global_pool; + vector v = pvectora (pool, strings, 4); + printf ("Introducing the Beatles: %s\n", pjoin (pool, v, ", ")); +} diff --git a/doc/eg_sash.c b/doc/eg_sash.c new file mode 100644 index 0000000..0bddc9d --- /dev/null +++ b/doc/eg_sash.c @@ -0,0 +1,31 @@ +#include +#include +#include + +main () +{ + pool pool = global_pool; + sash h = new_sash (pool); + char *fruit; + const char *color; + + sash_insert (h, "banana", "yellow"); + sash_insert (h, "orange", "orange"); + sash_insert (h, "apple", "red"); + sash_insert (h, "kiwi", "green"); + sash_insert (h, "grapefruit", "yellow"); + sash_insert (h, "pear", "green"); + sash_insert (h, "tomato", "red"); + sash_insert (h, "tangerine", "orange"); + + for (;;) + { + printf ("Please type in the name of a fruit: "); + fruit = pgetline (pool, stdin, 0); + + if (sash_get (h, fruit, color)) + printf ("The color of that fruit is %s.\n", color); + else + printf ("Sorry, I don't know anything about that fruit.\n"); + } +} diff --git a/doc/eg_string.c b/doc/eg_string.c new file mode 100644 index 0000000..5a18995 --- /dev/null +++ b/doc/eg_string.c @@ -0,0 +1,37 @@ +#include +#include + +char *given_name = "Richard"; +char *family_name = "Jones"; +char *email_address = "rich@annexia.org"; + +main () +{ + pool pool = global_pool; + char *email, *s; + vector v; + + email = + psprintf (pool, "%s %s <%s>", given_name, family_name, email_address); + + printf ("full email address is: %s\n", email); + + v = pstrcsplit (pool, email, ' '); + + printf ("split email into %d components\n", vector_size (v)); + + vector_get (v, 0, s); + printf ("first component is: %s\n", s); + assert (strcmp (s, given_name) == 0); + + vector_get (v, 1, s); + printf ("second component is: %s\n", s); + assert (strcmp (s, family_name) == 0); + + vector_get (v, 2, s); + printf ("third component is: %s\n", s); + s = pstrdup (pool, s); + s++; + s[strlen(s)-1] = '\0'; + assert (strcmp (s, email_address) == 0); +} diff --git a/doc/eg_vectorint.c b/doc/eg_vectorint.c new file mode 100644 index 0000000..d279d9e --- /dev/null +++ b/doc/eg_vectorint.c @@ -0,0 +1,25 @@ +#include +#include +#include + +main () +{ + pool pool = global_pool; + vector v = new_vector (pool, int); + int i, prod = 1; + + for (i = 1; i <= 10; ++i) + vector_push_back (v, i); + + for (i = 0; i < vector_size (v); ++i) + { + int elem; + + vector_get (v, i, elem); + prod *= elem; + } + + printf ("product of integers: %s = %d\n", + pjoin (pool, pvitostr (pool, v), " * "), + prod); +} diff --git a/doc/eg_vectorint2.c b/doc/eg_vectorint2.c new file mode 100644 index 0000000..e8b96b8 --- /dev/null +++ b/doc/eg_vectorint2.c @@ -0,0 +1,33 @@ +#include +#include +#include + +main () +{ + pool pool = global_pool; + vector v = pvector (pool, + "a", "b", "c", "d", "e", + "f", "g", "h", "i", "j", 0); + const char *X = "X"; + + printf ("Original vector contains: %s\n", + pjoin (pool, v, ", ")); + + vector_erase_range (v, 3, 6); + + printf ("After erasing elements 3-5, vector contains: %s\n", + pjoin (pool, v, ", ")); + + vector_insert (v, 3, X); + vector_insert (v, 4, X); + vector_insert (v, 5, X); + + printf ("After inserting 3 Xs, vector contains: %s\n", + pjoin (pool, v, ", ")); + + vector_clear (v); + vector_fill (v, X, 10); + + printf ("After clearing and inserting 10 Xs, vector contains: %s\n", + pjoin (pool, v, ", ")); +} diff --git a/doc/face_translate_along_normal.3.html b/doc/face_translate_along_normal.3.html new file mode 100644 index 0000000..c589481 --- /dev/null +++ b/doc/face_translate_along_normal.3.html @@ -0,0 +1,94 @@ + + + + +plane_translate_along_normal + + + +

plane_translate_along_normal

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+plane_translate_along_normal, face_translate_along_normal - translate a plane or face some distance in the direction of the normal
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+void plane_translate_along_normal (const float *plane, float distance, float *new_plane);
+void face_translate_along_normal (const float *points, int nr_points, const float *plane, float distance, float *new_points, float *new_plane);
+
+ +

DESCRIPTION

+ + + +
+Given an existing plane (expressed as plane +coefficients), produce a new plane new_plane which +has been translated by distance units along the +direction of the normal. The new plane is also returned as +plane coefficients.
+ + + +
+face_translate_along_normal is similar, except that +it also translates a list of points by the same +distance.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3).
+
+ + diff --git a/doc/global_pool.3.html b/doc/global_pool.3.html new file mode 100644 index 0000000..c845c55 --- /dev/null +++ b/doc/global_pool.3.html @@ -0,0 +1,76 @@ + + + + +global_pool + + + +

global_pool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+global_pool - the global pool for global allocations
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+pool global_pool;
+
+ +

DESCRIPTION

+ + + +
+This is the global pool which is allocated before +main() is called and deleted automatically upon +program exit. Items allocated on this pool cannot be deleted +until the program ends, and so it is a good idea not to +allocate short-lived items here.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_erase.3.html b/doc/hash_erase.3.html new file mode 100644 index 0000000..a364f56 --- /dev/null +++ b/doc/hash_erase.3.html @@ -0,0 +1,74 @@ + + + + +hash_erase + + + +

hash_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_erase, _hash_erase - erase a key from a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define hash_erase(h,key) _hash_erase((h),&(key))
+int _hash_erase (hash, const void *key);
+
+ +

DESCRIPTION

+ + + +
+Erase key from the hash. If an element was erased, +this returns true, else this returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_exists.3.html b/doc/hash_exists.3.html new file mode 100644 index 0000000..b22537f --- /dev/null +++ b/doc/hash_exists.3.html @@ -0,0 +1,97 @@ + + + + +hash_get + + + +

hash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_get, _hash_get, hash_get_ptr, _hash_get_ptr, hash_exists - look up in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define hash_get(h,key,value) _hash_get ((h), &(key), &(value))
+int _hash_get (hash, const void *key, void *value);
+#define hash_get_ptr(h,key,ptr) _hash_get_ptr ((h), &(key), &(ptr))
+int _hash_get_ptr (hash, const void *key, void **ptr);
+#define hash_exists(h,key) _hash_get_ptr ((h), &(key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the hash, +this pointer may become invalid.
+ + + +
+hash_exists simply tests whether or not key +exists in the hash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_get.3.html b/doc/hash_get.3.html new file mode 100644 index 0000000..6f6ce73 --- /dev/null +++ b/doc/hash_get.3.html @@ -0,0 +1,97 @@ + + + + +hash_get + + + +

hash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_get, _hash_get, hash_get_ptr, _hash_get_ptr, hash_exists - look up in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define hash_get(h,key,value) _hash_get ((h), &(key), &(value))
+int _hash_get (hash, const void *key, void *value);
+#define hash_get_ptr(h,key,ptr) _hash_get_ptr ((h), &(key), &(ptr))
+int _hash_get_ptr (hash, const void *key, void **ptr);
+#define hash_exists(h,key) _hash_get_ptr ((h), &(key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the hash, +this pointer may become invalid.
+ + + +
+hash_exists simply tests whether or not key +exists in the hash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_get_buckets_allocated.3.html b/doc/hash_get_buckets_allocated.3.html new file mode 100644 index 0000000..aa3003a --- /dev/null +++ b/doc/hash_get_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +hash_get_buckets_used + + + +

hash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_get_buckets_used, hash_get_buckets_allocated - return the number of buckets in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int hash_get_buckets_used (hash);
+int hash_get_buckets_allocated (hash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of hash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +hash_set_buckets_allocated to change the number used +in the hash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_get_buckets_used.3.html b/doc/hash_get_buckets_used.3.html new file mode 100644 index 0000000..d6bd884 --- /dev/null +++ b/doc/hash_get_buckets_used.3.html @@ -0,0 +1,76 @@ + + + + +hash_get_buckets_used + + + +

hash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_get_buckets_used, hash_get_buckets_allocated - return the number of buckets in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int hash_get_buckets_used (hash);
+int hash_get_buckets_allocated (hash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of hash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +hash_set_buckets_allocated to change the number used +in the hash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_get_ptr.3.html b/doc/hash_get_ptr.3.html new file mode 100644 index 0000000..18881e4 --- /dev/null +++ b/doc/hash_get_ptr.3.html @@ -0,0 +1,97 @@ + + + + +hash_get + + + +

hash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_get, _hash_get, hash_get_ptr, _hash_get_ptr, hash_exists - look up in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define hash_get(h,key,value) _hash_get ((h), &(key), &(value))
+int _hash_get (hash, const void *key, void *value);
+#define hash_get_ptr(h,key,ptr) _hash_get_ptr ((h), &(key), &(ptr))
+int _hash_get_ptr (hash, const void *key, void **ptr);
+#define hash_exists(h,key) _hash_get_ptr ((h), &(key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the hash, +this pointer may become invalid.
+ + + +
+hash_exists simply tests whether or not key +exists in the hash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_insert.3.html b/doc/hash_insert.3.html new file mode 100644 index 0000000..9fc4042 --- /dev/null +++ b/doc/hash_insert.3.html @@ -0,0 +1,77 @@ + + + + +hash_insert + + + +

hash_insert

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_insert, _hash_insert - insert a (key, value) pair into a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define hash_insert(h,key,value) _hash_insert((h),&(key),&(value))
+int _hash_insert (hash, const void *key, const void *value);
+
+ +

DESCRIPTION

+ + + +
+Insert an element (key, value) into the hash. +If key already exists in the hash, then the existing +value is replaced by value and the function returns +true. If there was no previous key in the hash then +this function returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_keys.3.html b/doc/hash_keys.3.html new file mode 100644 index 0000000..b0ee4e7 --- /dev/null +++ b/doc/hash_keys.3.html @@ -0,0 +1,78 @@ + + + + +hash_keys + + + +

hash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_keys, hash_keys_in_pool, hash_values, hash_values_in_pool - return a vector of the keys or values in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector hash_keys (hash);
+vector hash_keys_in_pool (hash, pool);
+vector hash_values (hash);
+vector hash_values_in_pool (hash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of hash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the hash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_keys_in_pool.3.html b/doc/hash_keys_in_pool.3.html new file mode 100644 index 0000000..dde4dcb --- /dev/null +++ b/doc/hash_keys_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +hash_keys + + + +

hash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_keys, hash_keys_in_pool, hash_values, hash_values_in_pool - return a vector of the keys or values in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector hash_keys (hash);
+vector hash_keys_in_pool (hash, pool);
+vector hash_values (hash);
+vector hash_values_in_pool (hash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of hash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the hash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_set_buckets_allocated.3.html b/doc/hash_set_buckets_allocated.3.html new file mode 100644 index 0000000..eed8862 --- /dev/null +++ b/doc/hash_set_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +hash_set_buckets_allocated + + + +

hash_set_buckets_allocated

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_set_buckets_allocated - set the number of buckets
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+void hash_set_buckets_allocated (hash, int);
+
+ +

DESCRIPTION

+ + + +
+Set the number of buckets allocated. You may ONLY do this +when you have just created the hash and before you have +inserted any elements. Otherwise the results are undefined +(and probably bad). The number of buckets MUST be a power of +2.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_size.3.html b/doc/hash_size.3.html new file mode 100644 index 0000000..2348617 --- /dev/null +++ b/doc/hash_size.3.html @@ -0,0 +1,73 @@ + + + + +hash_size + + + +

hash_size

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_size - return the number of (key, value) pairs in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int hash_size (hash);
+
+ +

DESCRIPTION

+ + + +
+Count the number of (key, value) pairs in the +hash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_values.3.html b/doc/hash_values.3.html new file mode 100644 index 0000000..52392d2 --- /dev/null +++ b/doc/hash_values.3.html @@ -0,0 +1,78 @@ + + + + +hash_keys + + + +

hash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_keys, hash_keys_in_pool, hash_values, hash_values_in_pool - return a vector of the keys or values in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector hash_keys (hash);
+vector hash_keys_in_pool (hash, pool);
+vector hash_values (hash);
+vector hash_values_in_pool (hash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of hash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the hash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/hash_values_in_pool.3.html b/doc/hash_values_in_pool.3.html new file mode 100644 index 0000000..19d71b8 --- /dev/null +++ b/doc/hash_values_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +hash_keys + + + +

hash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+hash_keys, hash_keys_in_pool, hash_values, hash_values_in_pool - return a vector of the keys or values in a hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector hash_keys (hash);
+vector hash_keys_in_pool (hash, pool);
+vector hash_values (hash);
+vector hash_values_in_pool (hash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of hash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the hash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/identity_matrix.3.html b/doc/identity_matrix.3.html new file mode 100644 index 0000000..f194699 --- /dev/null +++ b/doc/identity_matrix.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..4c3113c --- /dev/null +++ b/doc/index.html @@ -0,0 +1,852 @@ + + + + c2lib documentation index + + + + +

c2lib documentation index

+ +

+ c2lib is a library of basic tools for use by C + programmers. It contains features heavily influenced by + both Perl's string handling and C++'s Standard Template + Library (STL). +

+ +

+ The primary aims of c2lib are: +

+ +
    +
  • Be very simple to use. +
  • Provide rich abstract data types (ADTs) for C programmers + to use. +
  • Provide some of the advantages of Perl with only + around a factor of 2-3 code-size expansion over Perl itself. +
  • Retain most of the efficiency advantages of C. +
  • Remain compatible with existing libc functions (particularly + existing string and regular expression functions). +
  • Clean, fully documented API. +
+ +

Tutorial and programming examples

+ +

Join a list of strings and print

+ +
+   #include <pool.h>
+   #include <pstring.h>
+  
+   const char *strings[] = { "John", "Paul", "George", "Ringo" };
+5 
+   main ()
+   {
+     pool pool = global_pool;
+     vector v = pvectora (pool, strings, 4);
+10   printf ("Introducing the Beatles: %s\n", pjoin (pool, v, ", "));
+   }
+
+ +

+ When run, this program prints: +

+ +
+Introducing the Beatles: John, Paul, George, Ringo
+
+ +

+ Compare this to the equivalent Perl code: +

+ +
+#!/usr/bin/perl
+
+printf "Introducing the Beatles: %s\n",
+    join(", ", "John", "Paul", "George", "Ringo");
+
+ +

+ The pjoin(3) function on line 10 is + equivalent to the plain join function + in Perl. It takes a list of strings and joins them + with a separator string (in this case ", "), + and creates a new string which is returned and printed. +

+ +

+ The pvectora(3) function (line 9) takes a normal C + array of strings and converts it into a c2lib + vector. You will find out more about + vectors later. +

+ +

+ In this case all our allocations are done in a standard + pool which is created automatically before main is + called and deleted after main returns. This pool is + called global_pool(3). You will find out + more about pools below. +

+ +

+ Notice that, as with most c2lib programs, there is + no need to explicitly deallocate (free) objects once you + have finished using them. Almost all of the time, objects + are freed automatically for you by the system. +

+ +

A vector of integers

+ +
+   #include <pool.h>
+   #include <vector.h>
+   #include <pstring.h>
+   
+5  main ()
+   {
+     pool pool = global_pool;
+     vector v = new_vector (pool, int);
+     int i, prod = 1;
+10 
+     for (i = 1; i <= 10; ++i)
+       vector_push_back (v, i);
+   
+     for (i = 0; i < vector_size (v); ++i)
+15     {
+         int elem;
+   
+         vector_get (v, i, elem);
+         prod *= elem;
+20     }
+   
+     printf ("product of integers: %s = %d\n",
+   	     pjoin (pool, pvitostr (pool, v), " * "),
+   	     prod);
+25 }
+
+ +

+ When run: +

+ +
+product of integers: 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 = 3628800
+
+ +

+ The call to new_vector(3) on line 8 creates a new + vector object (abstract data type). In this case the vector is + allocated in the global pool and you have told it that each + element of the vector will be of type int. Vectors + are arrays which automatically expand when you push elements + onto them. This vector behaves very much like a C++ STL + vector<int> or a Perl array. +

+ +

+ On lines 11-12, we push the numbers 1 through to 10 into + the vector. The vector_push_back(3) function + pushes an element onto the end of the vector. There are + also vector_pop_back(3) (removes and returns the + last element of a vector), vector_push_front(3) + and vector_pop_front(3) operations. +

+ +

+ Lines 14-20 show the general pattern for iterating over + the elements in a vector. The call to vector_get + (line 18) returns the ith element of vector v + into variable elem. +

+ +

+ Finally lines 22-24 print out the result. We use the + pjoin(3) function again to join the numbers + with the string " * " between each pair. + Also note the use of the strange pvitostr(3) + function. pjoin(3) is expecting a vector + of strings (ie. a vector of char *), but + we have a vector of int, which is + incompatible. The pvitostr(3) function + promotes a vector of integers into a vector of strings. +

+ +

+ The c2lib library stores vectors as arrays and + reallocates them using prealloc(3) whenever it + needs to expand them. This means that certain operations on + vectors are efficient, and some other operations are less + efficient. Getting an element of a vector or replacing an + element in the middle of a vector are both fast O(1) operations, + equivalent to the ordinary C index ([]) operator. + vector_push_back(3) and + vector_pop_back(3) are also fast. However + vector_push_front(3) and + vector_pop_front(3) are O(n) operations because + they require the library to shift up all the elements in the + array by one place. Normally however if your vectors are very + short (say, fewer than 100 elements), the speed difference will + not be noticable, whereas the productivity gains from using + vectors over hand-rolled linked lists or other structures will + be large. The vector type also allows you + to insert and remove elements in the middle of the array, + as shown in the next example below: +

+ +
+   #include <pool.h>
+   #include <vector.h>
+   #include <pstring.h>
+   
+5  main ()
+   {
+     pool pool = global_pool;
+     vector v = pvector (pool,
+   		         "a", "b", "c", "d", "e",
+10 		         "f", "g", "h", "i", "j", 0);
+     const char *X = "X";
+   
+     printf ("Original vector contains: %s\n",
+   	  pjoin (pool, v, ", "));
+15 
+     vector_erase_range (v, 3, 6);
+   
+     printf ("After erasing elements 3-5, vector contains: %s\n",
+   	     pjoin (pool, v, ", "));
+20 
+     vector_insert (v, 3, X);
+     vector_insert (v, 4, X);
+     vector_insert (v, 5, X);
+   
+25   printf ("After inserting 3 Xs, vector contains: %s\n",
+	     pjoin (pool, v, ", "));
+
+     vector_clear (v);
+     vector_fill (v, X, 10);
+30 
+     printf ("After clearing and inserting 10 Xs, vector contains: %s\n",
+   	     pjoin (pool, v, ", "));
+   }
+
+ +

+ When run: +

+ +
+Original vector contains: a, b, c, d, e, f, g, h, i, j
+After erasing elements 3-5, vector contains: a, b, c, g, h, i, j
+After inserting 3 Xs, vector contains: a, b, c, X, X, X, g, h, i, j
+After clearing and inserting 10 Xs, vector contains: X, X, X, X, X, X, X, X, X, X
+
+ +

+ This example demonstrates the following functions: +

+ +
    +
  • vector_erase_range(3) which is used + to erase a range of elements from the middle of + a vector. +
  • vector_insert(3) which is used to + insert single elements into a vector. +
  • vector_clear(3) which completely + clears the vector - removing all elements. +
  • vector_fill(3) which fills a vector + with identical elements. +
+ +

+ For more information, see the respective manual pages. +

+ +

+ You can store just about anything in a vector: strings, + pointers, wide integers, complex structures, etc. If you do + want to directly store large objects in a vector, you must + remember that the vector type actually copies those objects into + and out of the vector each time you insert, push, get, pop and + so on. For some large structures, you may want to store a + pointer instead (in fact with strings you have no choice: you + are always storing a pointer in the vector itself). +

+ +

Strings are just char *

+ +

+ c2lib doesn't have a fancy string type. + Instead we just use plain old char *. This + is possible because pools (see below) mean that we don't + need to worry about when to copy or deallocate specific + objects. +

+ +

+ The great benefit of using plain char * + for strings is that we can continue to use the + familiar libc functions such as strcmp(3), + strcpy(3), strlen(3), printf(3) + and so on, as in the next example. +

+ +
+   #include <assert.h>
+   #include <pstring.h>
+   
+   char *given_name = "Richard";
+5  char *family_name = "Jones";
+   char *email_address = "rich@annexia.org";
+   
+   main ()
+   {
+10   pool pool = global_pool;
+     char *email, *s;
+     vector v;
+   
+     email =
+15     psprintf (pool, "%s %s <%s>", given_name, family_name, email_address);
+   
+     printf ("full email address is: %s\n", email);
+   
+     v = pstrcsplit (pool, email, ' ');
+20 
+     printf ("split email into %d components\n", vector_size (v));
+   
+     vector_get (v, 0, s);
+     printf ("first component is: %s\n", s);
+25   assert (strcmp (s, given_name) == 0);
+   
+     vector_get (v, 1, s);
+     printf ("second component is: %s\n", s);
+     assert (strcmp (s, family_name) == 0);
+30 
+     vector_get (v, 2, s);
+     printf ("third component is: %s\n", s);
+     s = pstrdup (pool, s);
+     s++;
+35   s[strlen(s)-1] = '\0';
+     assert (strcmp (s, email_address) == 0);
+   }
+
+ +

+ When run: +

+ +
+full email address is: Richard Jones <rich@annexia.org>
+split email into 3 components
+first component is: Richard
+second component is: Jones
+third component is: <rich@annexia.org>
+
+ +

+ Line 15 demonstrates the psprintf(3) function + which is like the ordinary sprintf(3), + but is (a) safe, and (b) allocates the string in the + pool provided, ensuring that it will be safely deallocated + later. +

+ +

+ The pstrcsplit(3) function is similar to the + Perl split. It takes a string and splits it + into a vector of strings, in this case on the space + character. There are also other functions for splitting + on a string or on a regular expression. +

+ +

+ The final part of the code, lines 21-36, prints out + the components of the split string. The vector_get(3) + function is used to pull the strings out of the vector object. +

+ +

+ Notice on line 33 that before we remove the beginning + and end < ... > from around the email address, + we first duplicate the string using pstrdup(3). + In this case it is not strictly necessary to duplicate + the string s because we know that + pstrcsplit(3) actually allocates new + copies of the strings in the vector which it returns. + However in general this is good practice because + otherwise we would be modifying the contents of the + original vector v. +

+ +

Hashes

+ +

+ Hashes give you all the power of Perl's "%" hashes. In + fact the way they work is very similar (but more powerful: + unlike Perl's hashes the key does not need to be a string). +

+ +

+ In c2lib there are three flavors of hash. + However they all work in essentially the same way, and + all have exactly the same functionality. The reason for + having the three flavors is just to work around an obscure + problem with the ANSI C specification! +

+ +

+ The three flavors are: +

+ + + + + + + + + + + + + + +
hash A hash of any non-string type to any non-string type.
sash A hash of char * to char *.
shash A hash of char * to any non-string type.
+ +

+ As with vectors, the phrase "any non-string type" can + be simple integers or chars, pointers, or complex large + structures if you wish. +

+ +

+ Here is a short program showing you how to use a + sash (but note that the same functions are available + for all of the other flavors): +

+ +
+   #include <stdio.h>
+   #include <hash.h>
+   #include <pstring.h>
+   
+5  main ()
+   {
+     pool pool = global_pool;
+     sash h = new_sash (pool);
+     char *fruit;
+10   const char *color;
+   
+     sash_insert (h, "banana", "yellow");
+     sash_insert (h, "orange", "orange");
+     sash_insert (h, "apple", "red");
+15   sash_insert (h, "kiwi", "green");
+     sash_insert (h, "grapefruit", "yellow");
+     sash_insert (h, "pear", "green");
+     sash_insert (h, "tomato", "red");
+     sash_insert (h, "tangerine", "orange");
+20 
+     for (;;)
+       {
+         printf ("Please type in the name of a fruit: ");
+         fruit = pgetline (pool, stdin, 0);
+25 
+         if (sash_get (h, fruit, color))
+   	printf ("The color of that fruit is %s.\n", color);
+         else
+   	printf ("Sorry, I don't know anything about that fruit.\n");
+30     }
+   }
+
+ +

+ When run: +

+ +
+Please type in the name of a fruit: orange
+The color of that fruit is orange.
+Please type in the name of a fruit: apple
+The color of that fruit is red.
+Please type in the name of a fruit: dragon fruit
+Sorry, I don't know anything about that fruit.
+
+ +

+ The sash is allocated on line 8 using the new_sash(3) + function. +

+ +

+ We populate the sash using the simple sash_insert(3) + functions (lines 12-19). +

+ +

+ The sash_get(3) function retrieves a value + (color) from + the sash using the key given (fruit). It + returns true if a value was found, or false if there + was no matching key. +

+ +

+ There are many potentially powerful functions available + for manipulating hashes, sashes and shashes (below, + * stands for either "h", "s" or "sh"): +

+ +
    +
  • *ash_exists(3) tells you if a key + exists. It is equivalent to the Perl exists + function. +
  • *ash_erase(3) removes a key. It + is equivalent to the Perl delete function. +
  • *ash_keys(3) returns all of the + keys of a hash in a vector. It is equivalent to the + Perl keys function. +
  • *ash_values(3) returns all of the + values of a hash in a vector. It is equivalent to the + Perl values function. +
  • *ash_size(3) counts the number of keys. +
+ +

Advanced used of pools

+ +

+ So far we have only touched upon pools, and it may not + be clear in the examples above why they don't in fact + leak memory. There appears to be no deallocation being + done, which is quite counter-intuitive to most C programmers! +

+ +

+ Pools are collections of related objects (where an + "object" is some sort of memory allocation). +

+ +

+ In C you are normally responsible for allocating and + deallocating every single object, like so: +

+ +
+p = malloc (size);
+
+/* ... use p ... */
+
+free (p);
+
+ +

+ However in c2lib we first allocate a pool, + then use pmalloc(3) and prealloc(3) + to allocate lots of related objects in the pool. + At the end of the program, all of the objects can be + deleted in one go just by calling delete_pool(3). +

+ +

+ There is one special pool, called global_pool(3). + This pool is created for you before main is + called, and it is deleted for you after main + returns (or if exit(3) is called). You don't + ever need to worry about deallocating global_pool(3) + (in fact, if you try to, your program might core dump). +

+ +

+ Thus most short programs like the ones above should just + allocate all objects in global_pool(3), and + never need to worry about deallocating the objects or + the pool. +

+ +

+ For larger programs, and programs that are expected to run for a + long time like servers, you will need to learn about pools. +

+ +

+ Pools are organised in a hierarchy. This means that you often + allocate one pool inside another pool. Here is a + common pattern: +

+ +
+main ()
+{
+  /* ... use global_pool for allocations here ... */
+
+  for (;;) /* for each request: */
+    {
+      pool pool = new_subpool (global_pool);
+
+      /* ... process the request using pool ... */
+
+      delete_pool (pool);
+    }
+}
+
+ +

+ pool is created as a subpool of + global_pool(3) for the duration of + the request. At the end of the request the pool + (and therefore all objects inside it) is deallocated. +

+ +

+ The advantage of creating pool as a + subpool of global_pool(3) is that if + the request processing code calls exit(3) + in the middle of the request, then global_pool(3) + will be deallocated in the normal way and as a consequence + of this pool will also be properly deallocated. +

+ +

+ You can also use new_pool(3) to create a + completely new top-level pool. There are some rare + circumstances when you will need to do this, but + generally you should avoid creating pools which are + not subpools. If in doubt, always create subpools of + global_pool(3) or of the pool immediately + "above" you. +

+ +

+ Pools don't just store memory allocations. You can attach + other types of objects to pools, or trigger functions which + are run when the pool is deallocated. pool_register_fd(3) + attaches a file descriptor to a pool, meaning that the file + descriptor is closed when the pool is deleted (note + however that there is no way to unattach a file descriptor + from a pool, so don't go and call close(3) + on the file descriptor once you've attached it to + a pool. pool_register_cleanup_fn(3) + registers your own clean-up function which is called + when the pool is deleted. Although you should + normally use pmalloc(3) and/or + prealloc(3) to allocate objects directly + in pools, you can also allocate them normally using + malloc(3) and attach them to the pool + using pool_register_malloc(3). The object + will be freed up automatically when the pool is + deallocated. +

+ +

+ Pools become very important when writing multi-threaded + servers using the pthrlib library. Each + thread processes a single request or command. A pool + is created for every thread, and is automatically + deleted when the thread exits. This assumes of course + that threads (and hence requests) are short-lived, which + is a reasonable assumption for most HTTP-like services. +

+ +

Links to manual pages

+ +

+ (These manual pages are not always up to date. For the + latest documentation, always consult the manual pages + supplied with the latest c2lib package!) +

+ +

Pools

+ + + +

Vectors

+ + + +

Hashes

+ + + +

Strings and miscellaneous

+ + + +

Matrix and vector math

+ + + +
+
Richard Jones
+ + +Last modified: Fri May 2 19:42:09 BST 2002 + + + diff --git a/doc/make_identity_matrix.3.html b/doc/make_identity_matrix.3.html new file mode 100644 index 0000000..7c97df9 --- /dev/null +++ b/doc/make_identity_matrix.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/doc/make_zero_vec.3.html b/doc/make_zero_vec.3.html new file mode 100644 index 0000000..61aaead --- /dev/null +++ b/doc/make_zero_vec.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/doc/new_hash.3.html b/doc/new_hash.3.html new file mode 100644 index 0000000..e3239ea --- /dev/null +++ b/doc/new_hash.3.html @@ -0,0 +1,90 @@ + + + + +new_hash + + + +

new_hash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+new_hash, _hash_new - allocate a new hash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define new_hash(pool,key_type,value_type) _hash_new ((pool), sizeof (key_type), sizeof (value_type))
+hash _hash_new (pool, size_t key_size, size_t value_size);
+
+ +

DESCRIPTION

+ + + +
+Allocate a new hash in pool mapping key_type +to value_type. You can map both simple types like +int and also aggregate types like structures and +unions. However, beware of aggregate types that might +contain 'holes' because of alignment -- such types will +probably not work as you expect, particularly if used as +keys.
+ + + +
+If you wish to have a hash which maps strings to something, +then calling new_hash(pool, char *, char *) (for +example) will not do what you expect. You are better to use +either a sash (string to string hash) or a shash (string to +anything hash) instead (see new_sash(3) and +new_shash(3)).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_identity_matrix.3.html b/doc/new_identity_matrix.3.html new file mode 100644 index 0000000..6e20028 --- /dev/null +++ b/doc/new_identity_matrix.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/doc/new_matrix.3.html b/doc/new_matrix.3.html new file mode 100644 index 0000000..be87012 --- /dev/null +++ b/doc/new_matrix.3.html @@ -0,0 +1,109 @@ + + + + +new_matrix + + + +

new_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+new_matrix, new_vec - allocate a new matrix or vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+#define new_matrix(pool) ((float *) pmalloc ((pool), sizeof (float) * 16))
+#define new_vec(pool) ((float *) pmalloc ((pool), sizeof (float) * 4))
+
+ +

DESCRIPTION

+ + + +
+new_matrix allocates a new 4x4 matrix of floats in +pool.
+ + + +
+new_vec allocates a new 4-vector of floats in +pool.
+ + + +
+You may use these functions to allocate matrices and vectors +dynamically, or you may allocate them statically. The other +matrix and vector functions available do not distriguish +between dynamically and statically allocated +variables.
+ + + +
+Note: All matrices are stored in COLUMN-MAJOR ORDER! This is +for compatibility with OpenGL, but it is the OPPOSITE of the +natural C row-major ordering, so beware.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_identity_matrix(3), +new_zero_vec(3).
+
+ + diff --git a/doc/new_pool.3.html b/doc/new_pool.3.html new file mode 100644 index 0000000..6b1a962 --- /dev/null +++ b/doc/new_pool.3.html @@ -0,0 +1,105 @@ + + + + +new_pool + + + +

new_pool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+new_pool - allocate a new pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+pool new_pool (void);
+
+ +

DESCRIPTION

+ + + +
+Allocate a new pool. Pools must eventually be deleted +explicitly by calling delete_pool(3).
+ + + +
+Note that new_pool is now deprecated. It is almost +always better to create a subpool of the global pool, +ie:
+ + + +
+pool = new_subpool (global_pool);
+ + + +
+This has the distinct advantage that your new pool will be +cleaned up properly if the process calls +exit.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_subpool(3), global_pool(3), +delete_pool(3).
+
+ + diff --git a/doc/new_sash.3.html b/doc/new_sash.3.html new file mode 100644 index 0000000..6fdd32e --- /dev/null +++ b/doc/new_sash.3.html @@ -0,0 +1,81 @@ + + + + +new_sash + + + +

new_sash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+new_sash - allocate a new sash (string hash)
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+sash new_sash (pool);
+
+ +

DESCRIPTION

+ + + +
+Allocate a new sash in pool mapping strings to +strings.
+ + + +
+Use a string hash in preference to a hash of char * +-> char * which will probably not quite work as +you expect.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_shash.3.html b/doc/new_shash.3.html new file mode 100644 index 0000000..c29b092 --- /dev/null +++ b/doc/new_shash.3.html @@ -0,0 +1,81 @@ + + + + +new_shash + + + +

new_shash

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+new_shash - allocate a new shash (string -> something hash)
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define new_shash(pool,value_type) _shash_new ((pool), sizeof (value_type))
+
+ +

DESCRIPTION

+ + + +
+Allocate a new shash in pool mapping strings to +strings.
+ + + +
+Use a shash in preference to a hash of char * -> +something which will probably not quite work as you +expect.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_subpool.3.html b/doc/new_subpool.3.html new file mode 100644 index 0000000..ea49c94 --- /dev/null +++ b/doc/new_subpool.3.html @@ -0,0 +1,74 @@ + + + + +new_subpool + + + +

new_subpool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+new_subpool - allocate a subpool of an existing pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+pool new_subpool (pool);
+
+ +

DESCRIPTION

+ + + +
+Allocate a new subpool. The pool may either be deleted +explicitly, or else is deleted implicitly when the parent +pool is deleted.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_subvector.3.html b/doc/new_subvector.3.html new file mode 100644 index 0000000..9f945a2 --- /dev/null +++ b/doc/new_subvector.3.html @@ -0,0 +1,85 @@ + + + + +copy_vector + + + +

copy_vector

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+copy_vector, new_subvector - copy a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+vector copy_vector (pool, vector v);
+vector new_subvector (pool, vector v, int i, int j);
+
+ +

DESCRIPTION

+ + + +
+Copy a vector v into pool pool. If the vector +contains pointers, then this function will not copy the +pointed-to data as well: you will need to copy this yourself +if appropriate.
+ + + +
+new_subvector creates a copy of part of an existing +vector. The new vector contains the j-i elements of +the old vector starting at element number i and +finishing at element number j-1.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_vec.3.html b/doc/new_vec.3.html new file mode 100644 index 0000000..6f17d26 --- /dev/null +++ b/doc/new_vec.3.html @@ -0,0 +1,109 @@ + + + + +new_matrix + + + +

new_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+new_matrix, new_vec - allocate a new matrix or vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+#define new_matrix(pool) ((float *) pmalloc ((pool), sizeof (float) * 16))
+#define new_vec(pool) ((float *) pmalloc ((pool), sizeof (float) * 4))
+
+ +

DESCRIPTION

+ + + +
+new_matrix allocates a new 4x4 matrix of floats in +pool.
+ + + +
+new_vec allocates a new 4-vector of floats in +pool.
+ + + +
+You may use these functions to allocate matrices and vectors +dynamically, or you may allocate them statically. The other +matrix and vector functions available do not distriguish +between dynamically and statically allocated +variables.
+ + + +
+Note: All matrices are stored in COLUMN-MAJOR ORDER! This is +for compatibility with OpenGL, but it is the OPPOSITE of the +natural C row-major ordering, so beware.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_identity_matrix(3), +new_zero_vec(3).
+
+ + diff --git a/doc/new_vector.3.html b/doc/new_vector.3.html new file mode 100644 index 0000000..eaf1f48 --- /dev/null +++ b/doc/new_vector.3.html @@ -0,0 +1,76 @@ + + + + +new_vector + + + +

new_vector

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+new_vector, _vector_new - allocate a new vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define new_vector(pool,type) _vector_new ((pool), sizeof (type))
+vector _vector_new (pool, size_t size);
+
+ +

DESCRIPTION

+ + + +
+Allocate a new vector in pool of type type. +The first form is just a macro which evaluates the size of +type. The second form creates a vector with elements +of the given size directly.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/new_zero_vec.3.html b/doc/new_zero_vec.3.html new file mode 100644 index 0000000..a9c1912 --- /dev/null +++ b/doc/new_zero_vec.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/doc/pcalloc.3.html b/doc/pcalloc.3.html new file mode 100644 index 0000000..0a8a4c0 --- /dev/null +++ b/doc/pcalloc.3.html @@ -0,0 +1,116 @@ + + + + +pmalloc + + + +

pmalloc

+NAME
+SYNOPSIS
+DESCRIPTION
+BUGS
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pmalloc, pcalloc, prealloc - allocate memory in a pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void *pmalloc (pool, size_t n);
+void *pcalloc (pool, size_t nmemb, size_t size);
+void *prealloc (pool, void *ptr, size_t n);
+
+ +

DESCRIPTION

+ + + +
+Allocate memory in a pool or, if pool is null, on the main +heap (equivalent to plain malloc). If memory is +allocated in a real pool, then it is automatically freed +when the pool is deleted.
+ + + +
+Memory returned is word-aligned.
+ + + +
+If a memory allocation fails, the bad_malloc_handler +function is called (which defaults to just calling +abort(3)).
+ + + +
+pcalloc is identical to pmalloc but also sets +the memory to zero before returning it.
+ + + +
+prealloc increases the size of an existing memory +allocation. prealloc might move the memory in the +process of reallocating it.
+ +

BUGS

+ + + +
+prealloc cannot reduce the size of an existing memory +allocation.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pchomp.3.html b/doc/pchomp.3.html new file mode 100644 index 0000000..a8ec6e1 --- /dev/null +++ b/doc/pchomp.3.html @@ -0,0 +1,74 @@ + + + + +pchomp + + + +

pchomp

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pchomp - remove line endings from a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pchomp (char *line);
+
+ +

DESCRIPTION

+ + + +
+Remove line endings (either CR, CRLF or LF) from the string +argument. The string is modified in-place and a pointer to +the string is also returned.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pchrs.3.html b/doc/pchrs.3.html new file mode 100644 index 0000000..782cbe5 --- /dev/null +++ b/doc/pchrs.3.html @@ -0,0 +1,85 @@ + + + + +pchrs + + + +

pchrs

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pchrs, pstrs - generate a string of n repeated characters or strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pchrs (pool, char c, int n);
+char *pstrs (pool, const char *str, int n);
+
+ +

DESCRIPTION

+ + + +
+pchrs (pool, 'c', n) is similar to the Perl +expression 'c' x n. It generates a pool-allocated +string of n copies of character +'c'.
+ + + +
+pstrs (pool, str, n) is similar to the Perl +expression str x n. It generates a pool-allocated +string of n copies of the string +str.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pconcat.3.html b/doc/pconcat.3.html new file mode 100644 index 0000000..c11d119 --- /dev/null +++ b/doc/pconcat.3.html @@ -0,0 +1,88 @@ + + + + +pconcat + + + +

pconcat

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pconcat, pjoin - concatenate a vector of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pconcat (pool, vector);
+char *pjoin (pool, vector, const char *sep);
+
+ +

DESCRIPTION

+ + + +
+pconcat concatenates a vector of strings to form a +string.
+ + + +
+pjoin is similar except that sep is inserted +between each concatenated string in the output.
+ + + +
+pjoin is kind of the opposite of +pstrsplit(3).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pdtoa.3.html b/doc/pdtoa.3.html new file mode 100644 index 0000000..8380d84 --- /dev/null +++ b/doc/pdtoa.3.html @@ -0,0 +1,84 @@ + + + + +pitoa + + + +

pitoa

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pitoa, pdtoa, pxtoa - convert number types to strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pitoa (pool, int);
+char *pdtoa (pool, double);
+char *pxtoa (pool, unsigned);
+
+ +

DESCRIPTION

+ + + +
+These functions convert a decimal int, double +or hexadecimal unsigned into a string, which is +allocated in pool.
+ + + +
+pitoa is equivalent to psprintf (pool, +"%d", i), and the other functions have similar +equivalents.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pgetline.3.html b/doc/pgetline.3.html new file mode 100644 index 0000000..e8d01cd --- /dev/null +++ b/doc/pgetline.3.html @@ -0,0 +1,171 @@ + + + + +pgetline + + + +

pgetline

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+pgetline, pgetlinex, pgetlinec - read a line from a file, optionally removing comments
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pgetline (pool, FILE *fp, char *line);
+char *pgetlinex (pool, FILE *fp, char *line, const char *comment_set, int flags);
+#define pgetlinec(p,fp,line) pgetlinex ((p), (fp), (line), #",0)"
+
+ +

DESCRIPTION

+ + + +
+pgetline reads a single line from a file and returns +it. It allocates enough space to read lines of arbitrary' +and '0) are length. Line ending characters (' automatically +removed from the end of the line.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a pointer to a string allocated in +pool which will be reallocated and filled with the contents +of the line. You may pass line as NULL to get +a newly allocated buffer.
+ + + +
+Use pgetline in one of the following two +ways:
+ + + +
+line = pgetline (pool, fp, line);
+ + + +
+or
+ + + +
+line = pgetline (pool, fp, NULL);
+ + + +
+pgetlinex is a more advanced function which reads a +line from a file, optionally removing comments, +concatenating together lines which have been split with a +backslash, and ignoring blank lines. pgetlinex (and +the related macro pgetlinec) are very useful for +reading lines of input from a configuration +file.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a buffer allocated in pool which +will be reallocated and filled with the result. +comment_set is the set of possible comment characters +-- eg. "#!" to allow either # or +! to be used to introduce comments. flags is +zero or more of the following flags OR-ed +together:
+ + + +
+PGETL_NO_CONCAT: Don't concatenate lines which have +been split with trailing backslash characters.
+ + + +
+PGETL_INLINE_COMMENTS: Treat everything following a +comment character as a comment. The default is to only allow +comments which appear on a line on their own.
+ + + +
+pgetlinec is a helper macro which calls +pgetlinex with comment_set == "#" +and flags == 0.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+pmatch(3).
+
+ + diff --git a/doc/pgetlinec.3.html b/doc/pgetlinec.3.html new file mode 100644 index 0000000..a3557c0 --- /dev/null +++ b/doc/pgetlinec.3.html @@ -0,0 +1,171 @@ + + + + +pgetline + + + +

pgetline

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+pgetline, pgetlinex, pgetlinec - read a line from a file, optionally removing comments
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pgetline (pool, FILE *fp, char *line);
+char *pgetlinex (pool, FILE *fp, char *line, const char *comment_set, int flags);
+#define pgetlinec(p,fp,line) pgetlinex ((p), (fp), (line), #",0)"
+
+ +

DESCRIPTION

+ + + +
+pgetline reads a single line from a file and returns +it. It allocates enough space to read lines of arbitrary' +and '0) are length. Line ending characters (' automatically +removed from the end of the line.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a pointer to a string allocated in +pool which will be reallocated and filled with the contents +of the line. You may pass line as NULL to get +a newly allocated buffer.
+ + + +
+Use pgetline in one of the following two +ways:
+ + + +
+line = pgetline (pool, fp, line);
+ + + +
+or
+ + + +
+line = pgetline (pool, fp, NULL);
+ + + +
+pgetlinex is a more advanced function which reads a +line from a file, optionally removing comments, +concatenating together lines which have been split with a +backslash, and ignoring blank lines. pgetlinex (and +the related macro pgetlinec) are very useful for +reading lines of input from a configuration +file.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a buffer allocated in pool which +will be reallocated and filled with the result. +comment_set is the set of possible comment characters +-- eg. "#!" to allow either # or +! to be used to introduce comments. flags is +zero or more of the following flags OR-ed +together:
+ + + +
+PGETL_NO_CONCAT: Don't concatenate lines which have +been split with trailing backslash characters.
+ + + +
+PGETL_INLINE_COMMENTS: Treat everything following a +comment character as a comment. The default is to only allow +comments which appear on a line on their own.
+ + + +
+pgetlinec is a helper macro which calls +pgetlinex with comment_set == "#" +and flags == 0.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+pmatch(3).
+
+ + diff --git a/doc/pgetlinex.3.html b/doc/pgetlinex.3.html new file mode 100644 index 0000000..10cc5fd --- /dev/null +++ b/doc/pgetlinex.3.html @@ -0,0 +1,171 @@ + + + + +pgetline + + + +

pgetline

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+pgetline, pgetlinex, pgetlinec - read a line from a file, optionally removing comments
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pgetline (pool, FILE *fp, char *line);
+char *pgetlinex (pool, FILE *fp, char *line, const char *comment_set, int flags);
+#define pgetlinec(p,fp,line) pgetlinex ((p), (fp), (line), #",0)"
+
+ +

DESCRIPTION

+ + + +
+pgetline reads a single line from a file and returns +it. It allocates enough space to read lines of arbitrary' +and '0) are length. Line ending characters (' automatically +removed from the end of the line.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a pointer to a string allocated in +pool which will be reallocated and filled with the contents +of the line. You may pass line as NULL to get +a newly allocated buffer.
+ + + +
+Use pgetline in one of the following two +ways:
+ + + +
+line = pgetline (pool, fp, line);
+ + + +
+or
+ + + +
+line = pgetline (pool, fp, NULL);
+ + + +
+pgetlinex is a more advanced function which reads a +line from a file, optionally removing comments, +concatenating together lines which have been split with a +backslash, and ignoring blank lines. pgetlinex (and +the related macro pgetlinec) are very useful for +reading lines of input from a configuration +file.
+ + + +
+The pool argument is a pool for allocating the line. +The fp argument is the C FILE pointer. The +line argument is a buffer allocated in pool which +will be reallocated and filled with the result. +comment_set is the set of possible comment characters +-- eg. "#!" to allow either # or +! to be used to introduce comments. flags is +zero or more of the following flags OR-ed +together:
+ + + +
+PGETL_NO_CONCAT: Don't concatenate lines which have +been split with trailing backslash characters.
+ + + +
+PGETL_INLINE_COMMENTS: Treat everything following a +comment character as a comment. The default is to only allow +comments which appear on a line on their own.
+ + + +
+pgetlinec is a helper macro which calls +pgetlinex with comment_set == "#" +and flags == 0.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+pmatch(3).
+
+ + diff --git a/doc/pitoa.3.html b/doc/pitoa.3.html new file mode 100644 index 0000000..b403a7c --- /dev/null +++ b/doc/pitoa.3.html @@ -0,0 +1,84 @@ + + + + +pitoa + + + +

pitoa

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pitoa, pdtoa, pxtoa - convert number types to strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pitoa (pool, int);
+char *pdtoa (pool, double);
+char *pxtoa (pool, unsigned);
+
+ +

DESCRIPTION

+ + + +
+These functions convert a decimal int, double +or hexadecimal unsigned into a string, which is +allocated in pool.
+ + + +
+pitoa is equivalent to psprintf (pool, +"%d", i), and the other functions have similar +equivalents.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pjoin.3.html b/doc/pjoin.3.html new file mode 100644 index 0000000..969d1eb --- /dev/null +++ b/doc/pjoin.3.html @@ -0,0 +1,88 @@ + + + + +pconcat + + + +

pconcat

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pconcat, pjoin - concatenate a vector of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pconcat (pool, vector);
+char *pjoin (pool, vector, const char *sep);
+
+ +

DESCRIPTION

+ + + +
+pconcat concatenates a vector of strings to form a +string.
+ + + +
+pjoin is similar except that sep is inserted +between each concatenated string in the output.
+ + + +
+pjoin is kind of the opposite of +pstrsplit(3).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/plane_coefficients.3.html b/doc/plane_coefficients.3.html new file mode 100644 index 0000000..0663c20 --- /dev/null +++ b/doc/plane_coefficients.3.html @@ -0,0 +1,114 @@ + + + + +plane_coefficients + + + +

plane_coefficients

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+plane_coefficients - calculate the coefficient form for a plane
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+void plane_coefficients (const float *p, const float *q, const float *r, float *co);
+
+ +

DESCRIPTION

+ + + +
+Given three points, not colinear, which naturally form a +plane, calculate the 4-vector form for the plane +coefficients. The three points are passed as p, +q and r. The coefficients are returned in +vector co.
+ + + +
+The four coefficients returned are respectively a, +b, c and d in the standard plane +equation:
+ + + +
+a x + b y + c z + d = 0
+ + + +
+(Note that many texts use - d, so be +warned).
+ + + +
+The normal (perpendicular) vector to the plane may be +derived immediately: it is just (a, b, c). Note that +the normal vector is not normalized!
+ + + +
+Planes are unbounded: they stretch off to infinity in all +directions. If what you really want are bounded convex +polygons, then you need to use a c2lib +"face".
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/plane_translate_along_normal.3.html b/doc/plane_translate_along_normal.3.html new file mode 100644 index 0000000..3479b6c --- /dev/null +++ b/doc/plane_translate_along_normal.3.html @@ -0,0 +1,94 @@ + + + + +plane_translate_along_normal + + + +

plane_translate_along_normal

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+plane_translate_along_normal, face_translate_along_normal - translate a plane or face some distance in the direction of the normal
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+void plane_translate_along_normal (const float *plane, float distance, float *new_plane);
+void face_translate_along_normal (const float *points, int nr_points, const float *plane, float distance, float *new_points, float *new_plane);
+
+ +

DESCRIPTION

+ + + +
+Given an existing plane (expressed as plane +coefficients), produce a new plane new_plane which +has been translated by distance units along the +direction of the normal. The new plane is also returned as +plane coefficients.
+ + + +
+face_translate_along_normal is similar, except that +it also translates a list of points by the same +distance.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3).
+
+ + diff --git a/doc/pmalloc.3.html b/doc/pmalloc.3.html new file mode 100644 index 0000000..4ebdd5c --- /dev/null +++ b/doc/pmalloc.3.html @@ -0,0 +1,116 @@ + + + + +pmalloc + + + +

pmalloc

+NAME
+SYNOPSIS
+DESCRIPTION
+BUGS
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pmalloc, pcalloc, prealloc - allocate memory in a pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void *pmalloc (pool, size_t n);
+void *pcalloc (pool, size_t nmemb, size_t size);
+void *prealloc (pool, void *ptr, size_t n);
+
+ +

DESCRIPTION

+ + + +
+Allocate memory in a pool or, if pool is null, on the main +heap (equivalent to plain malloc). If memory is +allocated in a real pool, then it is automatically freed +when the pool is deleted.
+ + + +
+Memory returned is word-aligned.
+ + + +
+If a memory allocation fails, the bad_malloc_handler +function is called (which defaults to just calling +abort(3)).
+ + + +
+pcalloc is identical to pmalloc but also sets +the memory to zero before returning it.
+ + + +
+prealloc increases the size of an existing memory +allocation. prealloc might move the memory in the +process of reallocating it.
+ +

BUGS

+ + + +
+prealloc cannot reduce the size of an existing memory +allocation.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pmatch.3.html b/doc/pmatch.3.html new file mode 100644 index 0000000..8ab063d --- /dev/null +++ b/doc/pmatch.3.html @@ -0,0 +1,109 @@ + + + + +pmatch + + + +

pmatch

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pmatch, pmatchx - test if a string matches a regular expression
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+#define pmatch(p,str,re) pmatchx ((p), (str), (re), REG_EXTENDED, 0, 0)
+vector pmatchx (pool, const char *str, const char *re, int cflags, int eflags, int flags);
+
+ +

DESCRIPTION

+ + + +
+pmatch is used as a quick way to test if a string +str matches a POSIX regular expression re. The +function internally caches compiled regular expressions for +speed. The function returns a vector of char +*, containing the list of substrings which match. If the +regular expression does not match, then NULL is +returned.
+ + + +
+pmatchx is the same as pmatch except that it +allows greater control with flags. cflags and +eflags are passed directly to regcomp(3) and +regexec(3) respectively. flags may +contain:
+ + + +
+PMATCH_NO_CACHE: Compile the regular expression +regardless of whether the re is stored in the cache, +and do not store the compiled regular expression back into +the cache. This flag is useful to save memory if you know +that the particular re will only be used very +infrequently, and hence storing it in the cache would just +be a waste of space.
+ + + +
+Note that the state of cflags is not stored in the +cache. In rare circumstances this could cause +problems.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pmatchx.3.html b/doc/pmatchx.3.html new file mode 100644 index 0000000..10c9b3b --- /dev/null +++ b/doc/pmatchx.3.html @@ -0,0 +1,109 @@ + + + + +pmatch + + + +

pmatch

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pmatch, pmatchx - test if a string matches a regular expression
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+#define pmatch(p,str,re) pmatchx ((p), (str), (re), REG_EXTENDED, 0, 0)
+vector pmatchx (pool, const char *str, const char *re, int cflags, int eflags, int flags);
+
+ +

DESCRIPTION

+ + + +
+pmatch is used as a quick way to test if a string +str matches a POSIX regular expression re. The +function internally caches compiled regular expressions for +speed. The function returns a vector of char +*, containing the list of substrings which match. If the +regular expression does not match, then NULL is +returned.
+ + + +
+pmatchx is the same as pmatch except that it +allows greater control with flags. cflags and +eflags are passed directly to regcomp(3) and +regexec(3) respectively. flags may +contain:
+ + + +
+PMATCH_NO_CACHE: Compile the regular expression +regardless of whether the re is stored in the cache, +and do not store the compiled regular expression back into +the cache. This flag is useful to save memory if you know +that the particular re will only be used very +infrequently, and hence storing it in the cache would just +be a waste of space.
+ + + +
+Note that the state of cflags is not stored in the +cache. In rare circumstances this could cause +problems.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pmemdup.3.html b/doc/pmemdup.3.html new file mode 100644 index 0000000..83e7076 --- /dev/null +++ b/doc/pmemdup.3.html @@ -0,0 +1,90 @@ + + + + +pstrdup + + + +

pstrdup

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrdup, pstrndup, pmemdup - duplicate a string or area of memory
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrdup (pool, const char *s);
+char *pstrndup (pool, const char *s, int n);
+void *pmemdup (pool, const void *data, size_t size);
+
+ +

DESCRIPTION

+ + + +
+pstrdup duplicates string s, allocating new +memory for the string in pool pool.
+ + + +
+pstrndup duplicates just the first n +characters of the string.
+ + + +
+pmemdup duplicates an arbitrary area of memory of +size size bytes starting at address +data.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/point_distance_to_face.3.html b/doc/point_distance_to_face.3.html new file mode 100644 index 0000000..fdbf9d2 --- /dev/null +++ b/doc/point_distance_to_face.3.html @@ -0,0 +1,152 @@ + + + + +point_distance_to_face + + + +

point_distance_to_face

+NAME
+SYNOPSIS
+DESCRIPTION
+RETURNS
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_distance_to_face - distance from point to bounded convex polygon (face)
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float point_distance_to_face (const float *points, int nr_points, const float *plane, const float *point, int *edge);
+
+ +

DESCRIPTION

+ + + +
+Given a point and a bounded convex polygon (a +"face"), the function +point_distance_to_face calculates the distance from +the point to the face. There are two importance cases to +consider here:
+ + + +
+(a) The point is directly above or below the face. In other +words, a line dropped from the point perpendicular to the +face intersects the face within the boundary of the polygon. +In this case, the function returns the shortest distance +from the point to the intersection (and is essentially +equivalent to point_distance_to_plane).
+ + + +
+(b) The point is not directly above or below the face. In +this case the function works out the distance to the nearest +edge of the face.
+ + + +
+The face is specified as a list of points and a plane (ie. +plane coefficients). If plane is NULL, then +the function calls plane_coefficients(3) on your +behalf. If the face is fixed, and you will call this +function lots of times, then it is a good idea to calculate +the plane coefficients once only and cache +them.
+ +

RETURNS

+ + + +
+The distance of the point from the face. The distance will +be positive if the point is above the face (ie. inside the +plane: see point_distance_to_plane(3)), or negative +otherwise.
+ + + +
+If edge is not NULL, then it is set to one of +the following values:
+ + + +
+*edge == -1 if the point is directly above or below +the face, corresponding to case (a) above.
+ + + +
+*edge == 0 .. nr_points-1 if the point is closest to +that particular edge, corresponding to case (b) +above.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+point_distance_to_plane(3), +plane_coefficients(3), point_lies_in_face(3), +point_distance_to_line(3).
+
+ + diff --git a/doc/point_distance_to_line.3.html b/doc/point_distance_to_line.3.html new file mode 100644 index 0000000..4efceff --- /dev/null +++ b/doc/point_distance_to_line.3.html @@ -0,0 +1,86 @@ + + + + +point_distance_to_line + + + +

point_distance_to_line

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_distance_to_line - shortest distance from a point to a line
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float point_distance_to_line (const float *point, const float *line_point, const float *line_vector);
+
+ +

DESCRIPTION

+ + + +
+Given a point and a line, expressed as +line_point and parallel line_vector, compute +the shortest distance from the point to the +line.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+point_distance_to_plane(3), +point_distance_to_face(3), +point_distance_to_line_segment(3).
+
+ + diff --git a/doc/point_distance_to_line_segment.3.html b/doc/point_distance_to_line_segment.3.html new file mode 100644 index 0000000..8b807de --- /dev/null +++ b/doc/point_distance_to_line_segment.3.html @@ -0,0 +1,84 @@ + + + + +point_distance_to_line_segment + + + +

point_distance_to_line_segment

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_distance_to_line_segment - shortest distance from a point to a line segment
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float point_distance_to_line_segment (const float *point, const float *line_point0, const float *line_point1);
+
+ +

DESCRIPTION

+ + + +
+Given a point and a line segment from +line_point0 to line_point1, compute the +shortest distance from the point to the line +segment.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+point_distance_to_line(3).
+
+ + diff --git a/doc/point_distance_to_plane.3.html b/doc/point_distance_to_plane.3.html new file mode 100644 index 0000000..5b9bb03 --- /dev/null +++ b/doc/point_distance_to_plane.3.html @@ -0,0 +1,99 @@ + + + + +point_distance_to_plane + + + +

point_distance_to_plane

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_distance_to_plane, point_is_inside_plane - distance from point to plane
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float point_distance_to_plane (const float *plane, const float *point);
+int point_is_inside_plane (const float *plane, const float *point);
+
+ +

DESCRIPTION

+ + + +
+point_distance_to_plane calculates the (shortest) +distance from the point point to the plane +plane. This distance is positive if the point is +"inside" the plane -- that is, if the normal +vector drawn from the plane points towards the point. It is +negative if the point is "outside" the plane. It +is zero if the point lies on the plane.
+ + + +
+point_is_inside_plane returns true if the point is +strictly inside the plane, and false if the point lies on +the plane or is outside. It is much faster to compute this +than to use point_distance_to_plane and take the sign +of the result.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3), +point_distance_to_face(3).
+
+ + diff --git a/doc/point_face_angle_sum.3.html b/doc/point_face_angle_sum.3.html new file mode 100644 index 0000000..aee5d4e --- /dev/null +++ b/doc/point_face_angle_sum.3.html @@ -0,0 +1,103 @@ + + + + +point_lies_in_face + + + +

point_lies_in_face

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_lies_in_face, point_face_angle_sum - does a point lie on the interior of a bounded convex polygon
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+int point_lies_in_face (const float *points, int nr_points, const float *point);
+float point_face_angle_sum (const float *points, int nr_points, const float *point);
+
+ +

DESCRIPTION

+ + + +
+Take a bounded convex polygon (a "face") and a +point. The function point_lies_in_face returns true +iff the point is both (a) coplanar with the face, and (b) +lies inside the edges of the face.
+ + + +
+In order to do this, point_lies_in_face calls +point_face_angle_sum which works out the sum of the +interior angles. If conditions (a) and (b) are both +satisfied then the sum of the interior angles will be very +close to 2.PI.
+ + + +
+The face is expressed as a flat list of points +(3-vectors).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3), +point_distance_to_face(3).
+
+ + diff --git a/doc/point_is_inside_plane.3.html b/doc/point_is_inside_plane.3.html new file mode 100644 index 0000000..3767f12 --- /dev/null +++ b/doc/point_is_inside_plane.3.html @@ -0,0 +1,99 @@ + + + + +point_distance_to_plane + + + +

point_distance_to_plane

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_distance_to_plane, point_is_inside_plane - distance from point to plane
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float point_distance_to_plane (const float *plane, const float *point);
+int point_is_inside_plane (const float *plane, const float *point);
+
+ +

DESCRIPTION

+ + + +
+point_distance_to_plane calculates the (shortest) +distance from the point point to the plane +plane. This distance is positive if the point is +"inside" the plane -- that is, if the normal +vector drawn from the plane points towards the point. It is +negative if the point is "outside" the plane. It +is zero if the point lies on the plane.
+ + + +
+point_is_inside_plane returns true if the point is +strictly inside the plane, and false if the point lies on +the plane or is outside. It is much faster to compute this +than to use point_distance_to_plane and take the sign +of the result.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3), +point_distance_to_face(3).
+
+ + diff --git a/doc/point_lies_in_face.3.html b/doc/point_lies_in_face.3.html new file mode 100644 index 0000000..43abbd7 --- /dev/null +++ b/doc/point_lies_in_face.3.html @@ -0,0 +1,103 @@ + + + + +point_lies_in_face + + + +

point_lies_in_face

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+point_lies_in_face, point_face_angle_sum - does a point lie on the interior of a bounded convex polygon
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+int point_lies_in_face (const float *points, int nr_points, const float *point);
+float point_face_angle_sum (const float *points, int nr_points, const float *point);
+
+ +

DESCRIPTION

+ + + +
+Take a bounded convex polygon (a "face") and a +point. The function point_lies_in_face returns true +iff the point is both (a) coplanar with the face, and (b) +lies inside the edges of the face.
+ + + +
+In order to do this, point_lies_in_face calls +point_face_angle_sum which works out the sum of the +interior angles. If conditions (a) and (b) are both +satisfied then the sum of the interior angles will be very +close to 2.PI.
+ + + +
+The face is expressed as a flat list of points +(3-vectors).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+plane_coefficients(3), +point_distance_to_face(3).
+
+ + diff --git a/doc/pool_get_stats.3.html b/doc/pool_get_stats.3.html new file mode 100644 index 0000000..10189a9 --- /dev/null +++ b/doc/pool_get_stats.3.html @@ -0,0 +1,98 @@ + + + + +pool_get_stats + + + +

pool_get_stats

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pool_get_stats - get statistics from the pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void pool_get_stats (const pool, struct pool_stats *stats, size_t n);
+
+ +

DESCRIPTION

+ + + +
+Return various statistics collected for the pool. This +function fills in the stats argument which should +point to a structure of type struct pool_stats. +n should be set to the size of this +structure.
+ + + +
+struct pool_stats currently contains the following +fields:
+ + + +
+nr_subpools: The number of subpools (including the +current pool).
+ + + +
+struct_size: The memory overhead used by the pool +allocator itself to store structures. This includes +subpools.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pool_register_cleanup_fn.3.html b/doc/pool_register_cleanup_fn.3.html new file mode 100644 index 0000000..3cdae5e --- /dev/null +++ b/doc/pool_register_cleanup_fn.3.html @@ -0,0 +1,75 @@ + + + + +pool_register_cleanup_fn + + + +

pool_register_cleanup_fn

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pool_register_cleanup_fn - call function when pool is deleted
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void pool_register_cleanup_fn (pool, void (*fn) (void *), void *data);
+
+ +

DESCRIPTION

+ + + +
+Register a function to be called when the pool is deleted. +There is no way to unregister this function. If you wish to +do that, then you probably want to register it in a +subpool.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pool_register_fd.3.html b/doc/pool_register_fd.3.html new file mode 100644 index 0000000..af8d946 --- /dev/null +++ b/doc/pool_register_fd.3.html @@ -0,0 +1,75 @@ + + + + +pool_register_fd + + + +

pool_register_fd

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pool_register_fd - allow pool to own file descriptor
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void pool_register_fd (pool, int fd);
+
+ +

DESCRIPTION

+ + + +
+Register a file descriptor to be closed when the pool is +deleted. There is no way to unregister a file descriptor. If +you wish to do that, then you probably want to register the +fd in a subpool.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pool_register_malloc.3.html b/doc/pool_register_malloc.3.html new file mode 100644 index 0000000..9e28696 --- /dev/null +++ b/doc/pool_register_malloc.3.html @@ -0,0 +1,74 @@ + + + + +pool_register_malloc + + + +

pool_register_malloc

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pool_register_malloc - allow pool to own malloc'd memory
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void pool_register_malloc (pool, void *ptr);
+
+ +

DESCRIPTION

+ + + +
+Register an anonymous area of malloc-allocated memory which +will be freed (with free(3)) when the pool is +deleted.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pool_set_bad_malloc_handler.3.html b/doc/pool_set_bad_malloc_handler.3.html new file mode 100644 index 0000000..49131f9 --- /dev/null +++ b/doc/pool_set_bad_malloc_handler.3.html @@ -0,0 +1,74 @@ + + + + +pool_set_bad_malloc_handler + + + +

pool_set_bad_malloc_handler

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pool_set_bad_malloc_handler - set handler for when malloc fails
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void pool_set_bad_malloc_handler (void (*fn) (void));
+
+ +

DESCRIPTION

+ + + +
+Set the function which is called when an underlying malloc +or realloc operation fails. The default is that +abort(3) is called.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/prealloc.3.html b/doc/prealloc.3.html new file mode 100644 index 0000000..1c1bc86 --- /dev/null +++ b/doc/prealloc.3.html @@ -0,0 +1,116 @@ + + + + +pmalloc + + + +

pmalloc

+NAME
+SYNOPSIS
+DESCRIPTION
+BUGS
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pmalloc, pcalloc, prealloc - allocate memory in a pool
+ +

SYNOPSIS

+ + + +
+
#include <pool.h>
+
+void *pmalloc (pool, size_t n);
+void *pcalloc (pool, size_t nmemb, size_t size);
+void *prealloc (pool, void *ptr, size_t n);
+
+ +

DESCRIPTION

+ + + +
+Allocate memory in a pool or, if pool is null, on the main +heap (equivalent to plain malloc). If memory is +allocated in a real pool, then it is automatically freed +when the pool is deleted.
+ + + +
+Memory returned is word-aligned.
+ + + +
+If a memory allocation fails, the bad_malloc_handler +function is called (which defaults to just calling +abort(3)).
+ + + +
+pcalloc is identical to pmalloc but also sets +the memory to zero before returning it.
+ + + +
+prealloc increases the size of an existing memory +allocation. prealloc might move the memory in the +process of reallocating it.
+ +

BUGS

+ + + +
+prealloc cannot reduce the size of an existing memory +allocation.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/psort.3.html b/doc/psort.3.html new file mode 100644 index 0000000..d7cce33 --- /dev/null +++ b/doc/psort.3.html @@ -0,0 +1,82 @@ + + + + +psort + + + +

psort

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psort - sort a vector of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+void psort (vector, int (*compare_fn) (const char **, const char **));
+
+ +

DESCRIPTION

+ + + +
+Sort a vector of strings, using compare_fn to compare +strings. The vector is sorted in-place.
+ + + +
+It is a common mistake to try to use strcmp directly +as your comparison function. This will not work. See the C +FAQ, section 12, question 12.2 +(http://www.lysator.liu.se/c/c-faq/c-12.html).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/psprintf.3.html b/doc/psprintf.3.html new file mode 100644 index 0000000..a627176 --- /dev/null +++ b/doc/psprintf.3.html @@ -0,0 +1,82 @@ + + + + +psprintf + + + +

psprintf

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psprintf, pvsprintf - sprintf which allocates the result in a pool
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *psprintf (pool, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+char *pvsprintf (pool, const char *format, va_list ap);
+
+ +

DESCRIPTION

+ + + +
+The psprintf function is equivalent to sprintf +but it allocates the result string in +pool.
+ + + +
+pvsprintf works similarly to +vsprintf.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrcat.3.html b/doc/pstrcat.3.html new file mode 100644 index 0000000..e59238e --- /dev/null +++ b/doc/pstrcat.3.html @@ -0,0 +1,96 @@ + + + + +pstrcat + + + +

pstrcat

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrcat, pstrncat - extend a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrcat (pool, char *str, const char *ending);
+char *pstrncat (pool, char *str, const char *ending, size_t n);
+
+ +

DESCRIPTION

+ + + +
+str is a string allocated in pool. Append +ending to str, reallocating str if +necessary.
+ + + +
+Because str may be reallocated (ie. moved) you must +invoke this function as follows:
+ + + +
+str = pstrcat (pool, str, ending);
+ + + +
+pstrncat is similar to pstrcat except that +only the first n characters of ending are +appended to str.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrcsplit.3.html b/doc/pstrcsplit.3.html new file mode 100644 index 0000000..30538d2 --- /dev/null +++ b/doc/pstrcsplit.3.html @@ -0,0 +1,95 @@ + + + + +pstrsplit + + + +

pstrsplit

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrsplit, pstrcsplit, pstrresplit - split a string on a character, string or regexp.
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pstrsplit (pool, const char *str, const char *sep);
+vector pstrcsplit (pool, const char *str, char c);
+vector pstrresplit (pool, const char *str, const regex_t *re);
+
+ +

DESCRIPTION

+ + + +
+These functions split string str on either a string +sep, a character c or a regular expression +re.
+ + + +
+The result is a vector of newly created +substrings.
+ + + +
+Perl's split function treats zero-length strings +differently from other strings -- returning an empty vector +(rather than returning a vector containing a single +zero-length string which is what you might expect, and is +slightly more orthogonal). The author has not decided what +the correct behaviour should be, so treat this case as +undefined in the current release.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrdup.3.html b/doc/pstrdup.3.html new file mode 100644 index 0000000..9abadeb --- /dev/null +++ b/doc/pstrdup.3.html @@ -0,0 +1,90 @@ + + + + +pstrdup + + + +

pstrdup

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrdup, pstrndup, pmemdup - duplicate a string or area of memory
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrdup (pool, const char *s);
+char *pstrndup (pool, const char *s, int n);
+void *pmemdup (pool, const void *data, size_t size);
+
+ +

DESCRIPTION

+ + + +
+pstrdup duplicates string s, allocating new +memory for the string in pool pool.
+ + + +
+pstrndup duplicates just the first n +characters of the string.
+ + + +
+pmemdup duplicates an arbitrary area of memory of +size size bytes starting at address +data.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrlwr.3.html b/doc/pstrlwr.3.html new file mode 100644 index 0000000..95f0831 --- /dev/null +++ b/doc/pstrlwr.3.html @@ -0,0 +1,75 @@ + + + + +pstrupr + + + +

pstrupr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrupr, pstrlwr - convert a string to upper- or lowercase
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrupr (char *str);
+char *pstrlwr (char *str);
+
+ +

DESCRIPTION

+ + + +
+Convert a string, in-place, to upper or lowercase by +applying toupper or tolower to each character +in turn.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrncat.3.html b/doc/pstrncat.3.html new file mode 100644 index 0000000..9a15169 --- /dev/null +++ b/doc/pstrncat.3.html @@ -0,0 +1,96 @@ + + + + +pstrcat + + + +

pstrcat

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrcat, pstrncat - extend a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrcat (pool, char *str, const char *ending);
+char *pstrncat (pool, char *str, const char *ending, size_t n);
+
+ +

DESCRIPTION

+ + + +
+str is a string allocated in pool. Append +ending to str, reallocating str if +necessary.
+ + + +
+Because str may be reallocated (ie. moved) you must +invoke this function as follows:
+ + + +
+str = pstrcat (pool, str, ending);
+ + + +
+pstrncat is similar to pstrcat except that +only the first n characters of ending are +appended to str.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrndup.3.html b/doc/pstrndup.3.html new file mode 100644 index 0000000..9d59434 --- /dev/null +++ b/doc/pstrndup.3.html @@ -0,0 +1,90 @@ + + + + +pstrdup + + + +

pstrdup

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrdup, pstrndup, pmemdup - duplicate a string or area of memory
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrdup (pool, const char *s);
+char *pstrndup (pool, const char *s, int n);
+void *pmemdup (pool, const void *data, size_t size);
+
+ +

DESCRIPTION

+ + + +
+pstrdup duplicates string s, allocating new +memory for the string in pool pool.
+ + + +
+pstrndup duplicates just the first n +characters of the string.
+ + + +
+pmemdup duplicates an arbitrary area of memory of +size size bytes starting at address +data.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrresplit.3.html b/doc/pstrresplit.3.html new file mode 100644 index 0000000..3809815 --- /dev/null +++ b/doc/pstrresplit.3.html @@ -0,0 +1,95 @@ + + + + +pstrsplit + + + +

pstrsplit

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrsplit, pstrcsplit, pstrresplit - split a string on a character, string or regexp.
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pstrsplit (pool, const char *str, const char *sep);
+vector pstrcsplit (pool, const char *str, char c);
+vector pstrresplit (pool, const char *str, const regex_t *re);
+
+ +

DESCRIPTION

+ + + +
+These functions split string str on either a string +sep, a character c or a regular expression +re.
+ + + +
+The result is a vector of newly created +substrings.
+ + + +
+Perl's split function treats zero-length strings +differently from other strings -- returning an empty vector +(rather than returning a vector containing a single +zero-length string which is what you might expect, and is +slightly more orthogonal). The author has not decided what +the correct behaviour should be, so treat this case as +undefined in the current release.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrs.3.html b/doc/pstrs.3.html new file mode 100644 index 0000000..0c4ac35 --- /dev/null +++ b/doc/pstrs.3.html @@ -0,0 +1,85 @@ + + + + +pchrs + + + +

pchrs

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pchrs, pstrs - generate a string of n repeated characters or strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pchrs (pool, char c, int n);
+char *pstrs (pool, const char *str, int n);
+
+ +

DESCRIPTION

+ + + +
+pchrs (pool, 'c', n) is similar to the Perl +expression 'c' x n. It generates a pool-allocated +string of n copies of character +'c'.
+ + + +
+pstrs (pool, str, n) is similar to the Perl +expression str x n. It generates a pool-allocated +string of n copies of the string +str.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrsplit.3.html b/doc/pstrsplit.3.html new file mode 100644 index 0000000..2bd717f --- /dev/null +++ b/doc/pstrsplit.3.html @@ -0,0 +1,95 @@ + + + + +pstrsplit + + + +

pstrsplit

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrsplit, pstrcsplit, pstrresplit - split a string on a character, string or regexp.
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pstrsplit (pool, const char *str, const char *sep);
+vector pstrcsplit (pool, const char *str, char c);
+vector pstrresplit (pool, const char *str, const regex_t *re);
+
+ +

DESCRIPTION

+ + + +
+These functions split string str on either a string +sep, a character c or a regular expression +re.
+ + + +
+The result is a vector of newly created +substrings.
+ + + +
+Perl's split function treats zero-length strings +differently from other strings -- returning an empty vector +(rather than returning a vector containing a single +zero-length string which is what you might expect, and is +slightly more orthogonal). The author has not decided what +the correct behaviour should be, so treat this case as +undefined in the current release.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pstrupr.3.html b/doc/pstrupr.3.html new file mode 100644 index 0000000..3721a82 --- /dev/null +++ b/doc/pstrupr.3.html @@ -0,0 +1,75 @@ + + + + +pstrupr + + + +

pstrupr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pstrupr, pstrlwr - convert a string to upper- or lowercase
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pstrupr (char *str);
+char *pstrlwr (char *str);
+
+ +

DESCRIPTION

+ + + +
+Convert a string, in-place, to upper or lowercase by +applying toupper or tolower to each character +in turn.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/psubst.3.html b/doc/psubst.3.html new file mode 100644 index 0000000..c69d8b4 --- /dev/null +++ b/doc/psubst.3.html @@ -0,0 +1,117 @@ + + + + +psubst + + + +

psubst

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psubst, psubstx - substitute string matching regular expression
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+#define psubst(p,str,pat,sub) psubstx ((p), (str), (pat), (sub), REG_EXTENDED, 0, 0)
+const char *psubstx (pool, const char *str, const char *pat, const char *sub, int cflags, int eflags, int flags);
+
+ +

DESCRIPTION

+ + + +
+psubst is used as a quick way to substitute strings +which match a regular expression with other strings. It is +the equivalent of the s/// operator in Perl. The +function internally caches compiled regular expressions for +speed. The function returns a new string which is formed +from str by substituting string sub for the +first regular expression which matches +pat.
+ + + +
+psubstx is the same as psubst except that it +allows greater control with flags. cflags and +eflags are passed directly to regcomp(3) and +regexec(3) respectively. flags may +contain:
+ + + +
+PSUBST_GLOBAL: Match and replace every instance of +pat in the string, not just the first.
+ + + +
+PSUBST_NO_CACHE: Compile the regular expression +regardless of whether the re is stored in the cache, +and do not store the compiled regular expression back into +the cache. This flag is useful to save memory if you know +that the particular re will only be used very +infrequently, and hence storing it in the cache would just +be a waste of space.
+ + + +
+Note that the state of cflags is not stored in the +cache. In rare circumstances this could cause +problems.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/psubstr.3.html b/doc/psubstr.3.html new file mode 100644 index 0000000..87b6940 --- /dev/null +++ b/doc/psubstr.3.html @@ -0,0 +1,75 @@ + + + + +psubstr + + + +

psubstr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psubstr - return a substring of a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *psubstr (pool, const char *str, int offset, int len);
+
+ +

DESCRIPTION

+ + + +
+Return the substring starting at offset and of length +len of str, allocated as a new string. If +len is negative, everything up to the end of +str is returned.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/psubstx.3.html b/doc/psubstx.3.html new file mode 100644 index 0000000..40cd5ff --- /dev/null +++ b/doc/psubstx.3.html @@ -0,0 +1,117 @@ + + + + +psubst + + + +

psubst

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psubst, psubstx - substitute string matching regular expression
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+#define psubst(p,str,pat,sub) psubstx ((p), (str), (pat), (sub), REG_EXTENDED, 0, 0)
+const char *psubstx (pool, const char *str, const char *pat, const char *sub, int cflags, int eflags, int flags);
+
+ +

DESCRIPTION

+ + + +
+psubst is used as a quick way to substitute strings +which match a regular expression with other strings. It is +the equivalent of the s/// operator in Perl. The +function internally caches compiled regular expressions for +speed. The function returns a new string which is formed +from str by substituting string sub for the +first regular expression which matches +pat.
+ + + +
+psubstx is the same as psubst except that it +allows greater control with flags. cflags and +eflags are passed directly to regcomp(3) and +regexec(3) respectively. flags may +contain:
+ + + +
+PSUBST_GLOBAL: Match and replace every instance of +pat in the string, not just the first.
+ + + +
+PSUBST_NO_CACHE: Compile the regular expression +regardless of whether the re is stored in the cache, +and do not store the compiled regular expression back into +the cache. This flag is useful to save memory if you know +that the particular re will only be used very +infrequently, and hence storing it in the cache would just +be a waste of space.
+ + + +
+Note that the state of cflags is not stored in the +cache. In rare circumstances this could cause +problems.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/ptrim.3.html b/doc/ptrim.3.html new file mode 100644 index 0000000..833c0d6 --- /dev/null +++ b/doc/ptrim.3.html @@ -0,0 +1,91 @@ + + + + +ptrim + + + +

ptrim

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+ptrim, ptrimfront, ptrimback - remove whitespace from the ends of a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *ptrim (char *str);
+char *ptrimfront (char *str);
+char *ptrimback (char *str);
+
+ +

DESCRIPTION

+ + + +
+ptrim modifies a string of text in place, removing +any whitespace characters from the beginning and end of the +line.
+ + + +
+ptrimfront is the same as ptrim but only +removes whitespace from the beginning of a +string.
+ + + +
+ptrimback is the same as ptrim but only +removes whitespace from the end of a string.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/ptrimback.3.html b/doc/ptrimback.3.html new file mode 100644 index 0000000..875b8c7 --- /dev/null +++ b/doc/ptrimback.3.html @@ -0,0 +1,91 @@ + + + + +ptrim + + + +

ptrim

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+ptrim, ptrimfront, ptrimback - remove whitespace from the ends of a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *ptrim (char *str);
+char *ptrimfront (char *str);
+char *ptrimback (char *str);
+
+ +

DESCRIPTION

+ + + +
+ptrim modifies a string of text in place, removing +any whitespace characters from the beginning and end of the +line.
+ + + +
+ptrimfront is the same as ptrim but only +removes whitespace from the beginning of a +string.
+ + + +
+ptrimback is the same as ptrim but only +removes whitespace from the end of a string.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/ptrimfront.3.html b/doc/ptrimfront.3.html new file mode 100644 index 0000000..ae21b10 --- /dev/null +++ b/doc/ptrimfront.3.html @@ -0,0 +1,91 @@ + + + + +ptrim + + + +

ptrim

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+ptrim, ptrimfront, ptrimback - remove whitespace from the ends of a string
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *ptrim (char *str);
+char *ptrimfront (char *str);
+char *ptrimback (char *str);
+
+ +

DESCRIPTION

+ + + +
+ptrim modifies a string of text in place, removing +any whitespace characters from the beginning and end of the +line.
+ + + +
+ptrimfront is the same as ptrim but only +removes whitespace from the beginning of a +string.
+ + + +
+ptrimback is the same as ptrim but only +removes whitespace from the end of a string.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pvdtostr.3.html b/doc/pvdtostr.3.html new file mode 100644 index 0000000..7dac52d --- /dev/null +++ b/doc/pvdtostr.3.html @@ -0,0 +1,100 @@ + + + + +pvitostr + + + +

pvitostr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pvitostr, pvdtostr, pvxtostr - convert vectors of numbers to vectors of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pvitostr (pool, vector);
+vector pvdtostr (pool, vector);
+vector pvxtostr (pool, vector);
+
+ +

DESCRIPTION

+ + + +
+Promote vector of numbers to vector of strings.
+ + + +
+pvitostr expects a vector of int.
+ + + +
+pvdtostr expects a vector of +double.
+ + + +
+pvxtostr expects a vector of hexadecimal +unsigned.
+ + + +
+All functions return a vector of char *.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pvector.3.html b/doc/pvector.3.html new file mode 100644 index 0000000..1a58092 --- /dev/null +++ b/doc/pvector.3.html @@ -0,0 +1,112 @@ + + + + +pvector + + + +

pvector

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+pvector, pvectora - generate a vector from a list or array of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pvector (pool, ...);
+vector pvectora (pool, const char *array[], int n);
+
+ +

DESCRIPTION

+ + + +
+pvector takes a NULL-terminated list of strings as +arguments and returns a vector of strings. pvectora +takes a pointer to an array of strings and the number of +strings and returns a vector of strings.
+ + + +
+A typical use of this is to quickly concatenate +strings:
+ + + +
+s = pconcat (pool, pvector (pool, s1, s2, s3, +NULL));
+ + + +
+which is roughly equivalent to:
+ + + +
+s = psprintf (pool, "%s%s%s", s1, s2, +s3);
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+pconcat(3), psprintf(3).
+
+ + diff --git a/doc/pvectora.3.html b/doc/pvectora.3.html new file mode 100644 index 0000000..8bbf934 --- /dev/null +++ b/doc/pvectora.3.html @@ -0,0 +1,112 @@ + + + + +pvector + + + +

pvector

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+pvector, pvectora - generate a vector from a list or array of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pvector (pool, ...);
+vector pvectora (pool, const char *array[], int n);
+
+ +

DESCRIPTION

+ + + +
+pvector takes a NULL-terminated list of strings as +arguments and returns a vector of strings. pvectora +takes a pointer to an array of strings and the number of +strings and returns a vector of strings.
+ + + +
+A typical use of this is to quickly concatenate +strings:
+ + + +
+s = pconcat (pool, pvector (pool, s1, s2, s3, +NULL));
+ + + +
+which is roughly equivalent to:
+ + + +
+s = psprintf (pool, "%s%s%s", s1, s2, +s3);
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+pconcat(3), psprintf(3).
+
+ + diff --git a/doc/pvitostr.3.html b/doc/pvitostr.3.html new file mode 100644 index 0000000..e1ddcd4 --- /dev/null +++ b/doc/pvitostr.3.html @@ -0,0 +1,100 @@ + + + + +pvitostr + + + +

pvitostr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pvitostr, pvdtostr, pvxtostr - convert vectors of numbers to vectors of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pvitostr (pool, vector);
+vector pvdtostr (pool, vector);
+vector pvxtostr (pool, vector);
+
+ +

DESCRIPTION

+ + + +
+Promote vector of numbers to vector of strings.
+ + + +
+pvitostr expects a vector of int.
+ + + +
+pvdtostr expects a vector of +double.
+ + + +
+pvxtostr expects a vector of hexadecimal +unsigned.
+ + + +
+All functions return a vector of char *.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pvsprintf.3.html b/doc/pvsprintf.3.html new file mode 100644 index 0000000..4f80550 --- /dev/null +++ b/doc/pvsprintf.3.html @@ -0,0 +1,82 @@ + + + + +psprintf + + + +

psprintf

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+psprintf, pvsprintf - sprintf which allocates the result in a pool
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *psprintf (pool, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+char *pvsprintf (pool, const char *format, va_list ap);
+
+ +

DESCRIPTION

+ + + +
+The psprintf function is equivalent to sprintf +but it allocates the result string in +pool.
+ + + +
+pvsprintf works similarly to +vsprintf.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pvxtostr.3.html b/doc/pvxtostr.3.html new file mode 100644 index 0000000..43dc480 --- /dev/null +++ b/doc/pvxtostr.3.html @@ -0,0 +1,100 @@ + + + + +pvitostr + + + +

pvitostr

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pvitostr, pvdtostr, pvxtostr - convert vectors of numbers to vectors of strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+vector pvitostr (pool, vector);
+vector pvdtostr (pool, vector);
+vector pvxtostr (pool, vector);
+
+ +

DESCRIPTION

+ + + +
+Promote vector of numbers to vector of strings.
+ + + +
+pvitostr expects a vector of int.
+ + + +
+pvdtostr expects a vector of +double.
+ + + +
+pvxtostr expects a vector of hexadecimal +unsigned.
+ + + +
+All functions return a vector of char *.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/pxtoa.3.html b/doc/pxtoa.3.html new file mode 100644 index 0000000..087331e --- /dev/null +++ b/doc/pxtoa.3.html @@ -0,0 +1,84 @@ + + + + +pitoa + + + +

pitoa

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+pitoa, pdtoa, pxtoa - convert number types to strings
+ +

SYNOPSIS

+ + + +
+
#include <pstring.h>
+
+char *pitoa (pool, int);
+char *pdtoa (pool, double);
+char *pxtoa (pool, unsigned);
+
+ +

DESCRIPTION

+ + + +
+These functions convert a decimal int, double +or hexadecimal unsigned into a string, which is +allocated in pool.
+ + + +
+pitoa is equivalent to psprintf (pool, +"%d", i), and the other functions have similar +equivalents.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_erase.3.html b/doc/sash_erase.3.html new file mode 100644 index 0000000..ac8135e --- /dev/null +++ b/doc/sash_erase.3.html @@ -0,0 +1,73 @@ + + + + +sash_erase + + + +

sash_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_erase - erase a key from a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int sash_erase (sash, const char *key);
+
+ +

DESCRIPTION

+ + + +
+Erase key from the sash. If an element was erased, +this returns true, else this returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_exists.3.html b/doc/sash_exists.3.html new file mode 100644 index 0000000..37f3bde --- /dev/null +++ b/doc/sash_exists.3.html @@ -0,0 +1,85 @@ + + + + +sash_get + + + +

sash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_get, _sash_get, sash_exists - look up in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define sash_get(sash,key,value) _sash_get((sash),(key),&(value))
+int _sash_get (sash, const char *key, const char **ptr);
+#define sash_exists(sash,key) _sash_get ((sash), (key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+sash_exists simply tests whether or not key +exists in the sash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_get.3.html b/doc/sash_get.3.html new file mode 100644 index 0000000..cfc2971 --- /dev/null +++ b/doc/sash_get.3.html @@ -0,0 +1,85 @@ + + + + +sash_get + + + +

sash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_get, _sash_get, sash_exists - look up in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define sash_get(sash,key,value) _sash_get((sash),(key),&(value))
+int _sash_get (sash, const char *key, const char **ptr);
+#define sash_exists(sash,key) _sash_get ((sash), (key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+sash_exists simply tests whether or not key +exists in the sash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_get_buckets_allocated.3.html b/doc/sash_get_buckets_allocated.3.html new file mode 100644 index 0000000..da6fbec --- /dev/null +++ b/doc/sash_get_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +sash_get_buckets_used + + + +

sash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_get_buckets_used, sash_get_buckets_allocated - return the number of buckets in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int sash_get_buckets_used (sash);
+int sash_get_buckets_allocated (sash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of sash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +sash_set_buckets_allocated to change the number used +in the sash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_get_buckets_used.3.html b/doc/sash_get_buckets_used.3.html new file mode 100644 index 0000000..2fb774e --- /dev/null +++ b/doc/sash_get_buckets_used.3.html @@ -0,0 +1,76 @@ + + + + +sash_get_buckets_used + + + +

sash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_get_buckets_used, sash_get_buckets_allocated - return the number of buckets in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int sash_get_buckets_used (sash);
+int sash_get_buckets_allocated (sash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of sash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +sash_set_buckets_allocated to change the number used +in the sash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_insert.3.html b/doc/sash_insert.3.html new file mode 100644 index 0000000..b057363 --- /dev/null +++ b/doc/sash_insert.3.html @@ -0,0 +1,76 @@ + + + + +sash_insert + + + +

sash_insert

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_insert - insert a (key, value) pair into a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int sash_insert (sash, const char *key, const char *value);
+
+ +

DESCRIPTION

+ + + +
+Insert an element (key, value) into the sash. +If key already exists in the sash, then the existing +value is replaced by value and the function returns +true. If there was no previous key in the sash then +this function returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_keys.3.html b/doc/sash_keys.3.html new file mode 100644 index 0000000..e1861fd --- /dev/null +++ b/doc/sash_keys.3.html @@ -0,0 +1,78 @@ + + + + +sash_keys + + + +

sash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_keys, sash_keys_in_pool, sash_values, sash_values_in_pool - return a vector of the keys or values in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector sash_keys (sash);
+vector sash_keys_in_pool (sash, pool);
+vector sash_values (sash);
+vector sash_values_in_pool (sash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of sash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the sash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_keys_in_pool.3.html b/doc/sash_keys_in_pool.3.html new file mode 100644 index 0000000..59228b5 --- /dev/null +++ b/doc/sash_keys_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +sash_keys + + + +

sash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_keys, sash_keys_in_pool, sash_values, sash_values_in_pool - return a vector of the keys or values in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector sash_keys (sash);
+vector sash_keys_in_pool (sash, pool);
+vector sash_values (sash);
+vector sash_values_in_pool (sash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of sash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the sash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_set_buckets_allocated.3.html b/doc/sash_set_buckets_allocated.3.html new file mode 100644 index 0000000..b61bfbd --- /dev/null +++ b/doc/sash_set_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +sash_set_buckets_allocated + + + +

sash_set_buckets_allocated

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_set_buckets_allocated - set the number of buckets
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+void sash_set_buckets_allocated (sash, int);
+
+ +

DESCRIPTION

+ + + +
+Set the number of buckets allocated. You may ONLY do this +when you have just created the sash and before you have +inserted any elements. Otherwise the results are undefined +(and probably bad). The number of buckets MUST be a power of +2.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_size.3.html b/doc/sash_size.3.html new file mode 100644 index 0000000..4075ff9 --- /dev/null +++ b/doc/sash_size.3.html @@ -0,0 +1,73 @@ + + + + +sash_size + + + +

sash_size

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_size - return the number of (key, value) pairs in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int sash_size (sash);
+
+ +

DESCRIPTION

+ + + +
+Count the number of (key, value) pairs in the +sash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_values.3.html b/doc/sash_values.3.html new file mode 100644 index 0000000..756b32d --- /dev/null +++ b/doc/sash_values.3.html @@ -0,0 +1,78 @@ + + + + +sash_keys + + + +

sash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_keys, sash_keys_in_pool, sash_values, sash_values_in_pool - return a vector of the keys or values in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector sash_keys (sash);
+vector sash_keys_in_pool (sash, pool);
+vector sash_values (sash);
+vector sash_values_in_pool (sash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of sash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the sash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/sash_values_in_pool.3.html b/doc/sash_values_in_pool.3.html new file mode 100644 index 0000000..2f011d3 --- /dev/null +++ b/doc/sash_values_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +sash_keys + + + +

sash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+sash_keys, sash_keys_in_pool, sash_values, sash_values_in_pool - return a vector of the keys or values in a sash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector sash_keys (sash);
+vector sash_keys_in_pool (sash, pool);
+vector sash_values (sash);
+vector sash_values_in_pool (sash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of sash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the sash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_erase.3.html b/doc/shash_erase.3.html new file mode 100644 index 0000000..126234e --- /dev/null +++ b/doc/shash_erase.3.html @@ -0,0 +1,73 @@ + + + + +shash_erase + + + +

shash_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_erase - erase a key from a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int shash_erase (shash, const char *key);
+
+ +

DESCRIPTION

+ + + +
+Erase key from the shash. If an element was erased, +this returns true, else this returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_exists.3.html b/doc/shash_exists.3.html new file mode 100644 index 0000000..6afab4d --- /dev/null +++ b/doc/shash_exists.3.html @@ -0,0 +1,97 @@ + + + + +shash_get + + + +

shash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_get, _shash_get, shash_get_ptr, _shash_get_ptr, shash_exists - look up in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define shash_get(shash,key,value) _shash_get((shash),(key),&(value))
+int _shash_get (shash, const char *key, void *value);
+#define shash_get_ptr(h,key,ptr) _shash_get_ptr ((h),(key),&(ptr))
+int _shash_get_ptr (shash, const char *key, void **ptr);
+#define shash_exists(shash,key) _shash_get_ptr ((shash), (key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the +shash, this pointer may become invalid.
+ + + +
+shash_exists simply tests whether or not key +exists in the shash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_get.3.html b/doc/shash_get.3.html new file mode 100644 index 0000000..09e8da8 --- /dev/null +++ b/doc/shash_get.3.html @@ -0,0 +1,97 @@ + + + + +shash_get + + + +

shash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_get, _shash_get, shash_get_ptr, _shash_get_ptr, shash_exists - look up in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define shash_get(shash,key,value) _shash_get((shash),(key),&(value))
+int _shash_get (shash, const char *key, void *value);
+#define shash_get_ptr(h,key,ptr) _shash_get_ptr ((h),(key),&(ptr))
+int _shash_get_ptr (shash, const char *key, void **ptr);
+#define shash_exists(shash,key) _shash_get_ptr ((shash), (key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the +shash, this pointer may become invalid.
+ + + +
+shash_exists simply tests whether or not key +exists in the shash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_get_buckets_allocated.3.html b/doc/shash_get_buckets_allocated.3.html new file mode 100644 index 0000000..3af2c8c --- /dev/null +++ b/doc/shash_get_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +shash_get_buckets_used + + + +

shash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_get_buckets_used, shash_get_buckets_allocated - return the number of buckets in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int shash_get_buckets_used (shash);
+int shash_get_buckets_allocated (shash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of shash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +shash_set_buckets_allocated to change the number used +in the shash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_get_buckets_used.3.html b/doc/shash_get_buckets_used.3.html new file mode 100644 index 0000000..f550064 --- /dev/null +++ b/doc/shash_get_buckets_used.3.html @@ -0,0 +1,76 @@ + + + + +shash_get_buckets_used + + + +

shash_get_buckets_used

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_get_buckets_used, shash_get_buckets_allocated - return the number of buckets in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int shash_get_buckets_used (shash);
+int shash_get_buckets_allocated (shash);
+
+ +

DESCRIPTION

+ + + +
+Return the number of shash buckets used and allocated. The +number of buckets allocated is always a power of 2. See also +shash_set_buckets_allocated to change the number used +in the shash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_get_ptr.3.html b/doc/shash_get_ptr.3.html new file mode 100644 index 0000000..dd261d8 --- /dev/null +++ b/doc/shash_get_ptr.3.html @@ -0,0 +1,97 @@ + + + + +shash_get + + + +

shash_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_get, _shash_get, shash_get_ptr, _shash_get_ptr, shash_exists - look up in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define shash_get(shash,key,value) _shash_get((shash),(key),&(value))
+int _shash_get (shash, const char *key, void *value);
+#define shash_get_ptr(h,key,ptr) _shash_get_ptr ((h),(key),&(ptr))
+int _shash_get_ptr (shash, const char *key, void **ptr);
+#define shash_exists(shash,key) _shash_get_ptr ((shash), (key), 0)
+
+ +

DESCRIPTION

+ + + +
+Get the value associated with key key and +return true. If there is no value associated with +key, this returns false and value is left +unchanged.
+ + + +
+The *_ptr variants return a pointer rather than +copying out the entire value object. The pointer is +typically only valid for a short period of time. +Particularly if you insert or remove elements from the +shash, this pointer may become invalid.
+ + + +
+shash_exists simply tests whether or not key +exists in the shash. If so, it returns true, otherwise +false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_insert.3.html b/doc/shash_insert.3.html new file mode 100644 index 0000000..248e2ac --- /dev/null +++ b/doc/shash_insert.3.html @@ -0,0 +1,77 @@ + + + + +shash_insert + + + +

shash_insert

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_insert, _shash_insert - insert a (key, value) pair into a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+#define shash_insert(h,key,value) _shash_insert((h),(key),&(value))
+int _shash_insert (shash, const char *key, const void *value);
+
+ +

DESCRIPTION

+ + + +
+Insert an element (key, value) into the shash. +If key already exists in the shash, then the existing +value is replaced by value and the function returns +true. If there was no previous key in the shash then +this function returns false.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_keys.3.html b/doc/shash_keys.3.html new file mode 100644 index 0000000..441836c --- /dev/null +++ b/doc/shash_keys.3.html @@ -0,0 +1,78 @@ + + + + +shash_keys + + + +

shash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_keys, shash_keys_in_pool, shash_values, shash_values_in_pool - return a vector of the keys or values in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector shash_keys (shash);
+vector shash_keys_in_pool (shash, pool);
+vector shash_values (shash);
+vector shash_values_in_pool (shash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of shash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the shash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_keys_in_pool.3.html b/doc/shash_keys_in_pool.3.html new file mode 100644 index 0000000..5d58e3d --- /dev/null +++ b/doc/shash_keys_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +shash_keys + + + +

shash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_keys, shash_keys_in_pool, shash_values, shash_values_in_pool - return a vector of the keys or values in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector shash_keys (shash);
+vector shash_keys_in_pool (shash, pool);
+vector shash_values (shash);
+vector shash_values_in_pool (shash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of shash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the shash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_set_buckets_allocated.3.html b/doc/shash_set_buckets_allocated.3.html new file mode 100644 index 0000000..d0626bb --- /dev/null +++ b/doc/shash_set_buckets_allocated.3.html @@ -0,0 +1,76 @@ + + + + +shash_set_buckets_allocated + + + +

shash_set_buckets_allocated

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_set_buckets_allocated - set the number of buckets
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+void shash_set_buckets_allocated (shash, int);
+
+ +

DESCRIPTION

+ + + +
+Set the number of buckets allocated. You may ONLY do this +when you have just created the shash and before you have +inserted any elements. Otherwise the results are undefined +(and probably bad). The number of buckets MUST be a power of +2.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_size.3.html b/doc/shash_size.3.html new file mode 100644 index 0000000..030b624 --- /dev/null +++ b/doc/shash_size.3.html @@ -0,0 +1,73 @@ + + + + +shash_size + + + +

shash_size

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_size - return the number of (key, value) pairs in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+int shash_size (shash);
+
+ +

DESCRIPTION

+ + + +
+Count the number of (key, value) pairs in the +shash.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_values.3.html b/doc/shash_values.3.html new file mode 100644 index 0000000..8838388 --- /dev/null +++ b/doc/shash_values.3.html @@ -0,0 +1,78 @@ + + + + +shash_keys + + + +

shash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_keys, shash_keys_in_pool, shash_values, shash_values_in_pool - return a vector of the keys or values in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector shash_keys (shash);
+vector shash_keys_in_pool (shash, pool);
+vector shash_values (shash);
+vector shash_values_in_pool (shash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of shash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the shash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/shash_values_in_pool.3.html b/doc/shash_values_in_pool.3.html new file mode 100644 index 0000000..8747de2 --- /dev/null +++ b/doc/shash_values_in_pool.3.html @@ -0,0 +1,78 @@ + + + + +shash_keys + + + +

shash_keys

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+shash_keys, shash_keys_in_pool, shash_values, shash_values_in_pool - return a vector of the keys or values in a shash
+ +

SYNOPSIS

+ + + +
+
#include <hash.h>
+
+vector shash_keys (shash);
+vector shash_keys_in_pool (shash, pool);
+vector shash_values (shash);
+vector shash_values_in_pool (shash, pool);
+
+ +

DESCRIPTION

+ + + +
+Return a vector containing all the keys or values of shash. +The *_in_pool variants allow you to allocate the +vector in another pool (the default is to allocate the +vector in the same pool as the shash).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vec_angle_between.3.html b/doc/vec_angle_between.3.html new file mode 100644 index 0000000..32dd6fe --- /dev/null +++ b/doc/vec_angle_between.3.html @@ -0,0 +1,83 @@ + + + + +vec_angle_between + + + +

vec_angle_between

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_angle_between - calculate the angle between two vectors
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float vec_angle_between (const float *v1, const float *v2);
+
+ +

DESCRIPTION

+ + + +
+This function returns the angle between two vectors +v1 and v2.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_dot_product(3), +vec_magnitude_in_direction(3)
+
+ + diff --git a/doc/vec_dot_product.3.html b/doc/vec_dot_product.3.html new file mode 100644 index 0000000..ed8934c --- /dev/null +++ b/doc/vec_dot_product.3.html @@ -0,0 +1,107 @@ + + + + +vec_dot_product + + + +

vec_dot_product

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_dot_product - calculate the dot product of two vectors
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float vec_dot_product (const float *v1, const float *v2);
+
+ +

DESCRIPTION

+ + + +
+vec_dot_product calculates the dot product of two +vectors v1 and v2 and returns it. The dot +product is formally defined as:
+ + + +
+|v1| |v2| cos theta
+ + + +
+where theta is the angle between the two +vectors.
+ + + +
+One interesting consequence of this is that if both +v1 and v2 are already normalized, then the dot +product is 1 if the vectors are parallel and running in the +same direction, and 0 if the vectors are +perpendicular.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_magnitude_in_direction(3), +vec_angle_between(3)
+
+ + diff --git a/doc/vec_magnitude.3.html b/doc/vec_magnitude.3.html new file mode 100644 index 0000000..e7b91ab --- /dev/null +++ b/doc/vec_magnitude.3.html @@ -0,0 +1,85 @@ + + + + +vec_magnitude + + + +

vec_magnitude

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_magnitude, vec_magnitude2d - calculate magnitude (length) of a vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float vec_magnitude (const float *v);
+float vec_magnitude2d (const float *v);
+
+ +

DESCRIPTION

+ + + +
+vec_magnitude calculates the magnitude (length) of a +3D vector. vec_magnitude2d calculates the magnitude +of a 2D vector.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_normalize(3), +vec_normalize2d(3).
+
+ + diff --git a/doc/vec_magnitude2d.3.html b/doc/vec_magnitude2d.3.html new file mode 100644 index 0000000..e018a80 --- /dev/null +++ b/doc/vec_magnitude2d.3.html @@ -0,0 +1,85 @@ + + + + +vec_magnitude + + + +

vec_magnitude

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_magnitude, vec_magnitude2d - calculate magnitude (length) of a vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float vec_magnitude (const float *v);
+float vec_magnitude2d (const float *v);
+
+ +

DESCRIPTION

+ + + +
+vec_magnitude calculates the magnitude (length) of a +3D vector. vec_magnitude2d calculates the magnitude +of a 2D vector.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_normalize(3), +vec_normalize2d(3).
+
+ + diff --git a/doc/vec_magnitude_in_direction.3.html b/doc/vec_magnitude_in_direction.3.html new file mode 100644 index 0000000..64562c9 --- /dev/null +++ b/doc/vec_magnitude_in_direction.3.html @@ -0,0 +1,88 @@ + + + + +vec_magnitude_in_direction + + + +

vec_magnitude_in_direction

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_magnitude_in_direction - calculate relative direction of two vectors
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float vec_magnitude_in_direction (const float *v1, const float *v2);
+
+ +

DESCRIPTION

+ + + +
+If v1 and v2 are parallel and point in the +same direction, then vec_magnitude_in_direction +returns +1. If v1 and v2 are perpendicular, +this returns 0. If v1 and v2 are parallel and +point in opposite directions to each other, this returns -1. +For other vectors, this function returns the cosine of the +angle between the vectors.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_dot_product(3), +vec_angle_between(3)
+
+ + diff --git a/doc/vec_normalize.3.html b/doc/vec_normalize.3.html new file mode 100644 index 0000000..434d866 --- /dev/null +++ b/doc/vec_normalize.3.html @@ -0,0 +1,98 @@ + + + + +vec_normalize + + + +

vec_normalize

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_normalize, vec_normalize2d - normalize a vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+void vec_normalize (const float *v, float *r);
+void vec_normalize2d (const float *v, float *r);
+
+ +

DESCRIPTION

+ + + +
+These two functions normalize respectively a 3D or 2D vector +v. The original vector v is not touched, and +the result is placed in vector r.
+ + + +
+To normalize a vector in-place (ie. modifying the original +vector), do:
+ + + +
+vec_normalize (v, v);
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_magnitude(3), +vec_magnitude2d(3).
+
+ + diff --git a/doc/vec_normalize2d.3.html b/doc/vec_normalize2d.3.html new file mode 100644 index 0000000..6f0d535 --- /dev/null +++ b/doc/vec_normalize2d.3.html @@ -0,0 +1,98 @@ + + + + +vec_normalize + + + +

vec_normalize

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+vec_normalize, vec_normalize2d - normalize a vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+void vec_normalize (const float *v, float *r);
+void vec_normalize2d (const float *v, float *r);
+
+ +

DESCRIPTION

+ + + +
+These two functions normalize respectively a 3D or 2D vector +v. The original vector v is not touched, and +the result is placed in vector r.
+ + + +
+To normalize a vector in-place (ie. modifying the original +vector), do:
+ + + +
+vec_normalize (v, v);
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+vec_magnitude(3), +vec_magnitude2d(3).
+
+ + diff --git a/doc/vector_allocated.3.html b/doc/vector_allocated.3.html new file mode 100644 index 0000000..12a525b --- /dev/null +++ b/doc/vector_allocated.3.html @@ -0,0 +1,77 @@ + + + + +vector_allocated + + + +

vector_allocated

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_allocated - return the space allocated to a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_allocated(v) ((v)->allocated)
+
+ +

DESCRIPTION

+ + + +
+Return the amount of space which has been allocated for +storing elements of the vector. This is different from the +number of elements actually stored by the vector (see +vector_size(3)) and also different from the size of +each element in bytes (see +vector_element_size(3)).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_clear.3.html b/doc/vector_clear.3.html new file mode 100644 index 0000000..70f8f60 --- /dev/null +++ b/doc/vector_clear.3.html @@ -0,0 +1,97 @@ + + + + +vector_erase + + + +

vector_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_erase, vector_erase_range, vector_clear - erase elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_erase (vector v, int i);
+void vector_erase_range (vector v, int i, int j);
+void vector_clear (vector v);
+
+ +

DESCRIPTION

+ + + +
+vector_erase removes the element v[i], +shuffling the later elements down by one place to fill the +space.
+ + + +
+vector_erase_range removes a range of elements +v[i] to v[j-1] (i <= j), shuffling +later elements down to fill the space.
+ + + +
+vector_clear removes all elements from the vector, +setting its size to 0.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_compare.3.html b/doc/vector_compare.3.html new file mode 100644 index 0000000..4cc298e --- /dev/null +++ b/doc/vector_compare.3.html @@ -0,0 +1,76 @@ + + + + +vector_compare + + + +

vector_compare

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_compare, _vector_compare - compare two vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_compare(v1,v2,compare_fn) _vector_compare ((v1), (v2), (int (*)(const void *,const void *)) (compare_fn))
+int _vector_compare (vector, vector, int (*compare_fn) (const void *, const void *));
+
+ +

DESCRIPTION

+ + + +
+Compare two vectors. This returns 0 if the two vectors are +identical. It returns > 0 if v1 > v2. +This returns < 0 if v1 < +v2.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_element_size.3.html b/doc/vector_element_size.3.html new file mode 100644 index 0000000..b147491 --- /dev/null +++ b/doc/vector_element_size.3.html @@ -0,0 +1,73 @@ + + + + +vector_element_size + + + +

vector_element_size

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_element_size - return the size of each element of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_element_size(v) ((v)->size)
+
+ +

DESCRIPTION

+ + + +
+Return the size in bytes of each element in +vector.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_erase.3.html b/doc/vector_erase.3.html new file mode 100644 index 0000000..a1c1ce8 --- /dev/null +++ b/doc/vector_erase.3.html @@ -0,0 +1,97 @@ + + + + +vector_erase + + + +

vector_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_erase, vector_erase_range, vector_clear - erase elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_erase (vector v, int i);
+void vector_erase_range (vector v, int i, int j);
+void vector_clear (vector v);
+
+ +

DESCRIPTION

+ + + +
+vector_erase removes the element v[i], +shuffling the later elements down by one place to fill the +space.
+ + + +
+vector_erase_range removes a range of elements +v[i] to v[j-1] (i <= j), shuffling +later elements down to fill the space.
+ + + +
+vector_clear removes all elements from the vector, +setting its size to 0.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_erase_range.3.html b/doc/vector_erase_range.3.html new file mode 100644 index 0000000..9bec9fb --- /dev/null +++ b/doc/vector_erase_range.3.html @@ -0,0 +1,97 @@ + + + + +vector_erase + + + +

vector_erase

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_erase, vector_erase_range, vector_clear - erase elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_erase (vector v, int i);
+void vector_erase_range (vector v, int i, int j);
+void vector_clear (vector v);
+
+ +

DESCRIPTION

+ + + +
+vector_erase removes the element v[i], +shuffling the later elements down by one place to fill the +space.
+ + + +
+vector_erase_range removes a range of elements +v[i] to v[j-1] (i <= j), shuffling +later elements down to fill the space.
+ + + +
+vector_clear removes all elements from the vector, +setting its size to 0.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_fill.3.html b/doc/vector_fill.3.html new file mode 100644 index 0000000..57f7be5 --- /dev/null +++ b/doc/vector_fill.3.html @@ -0,0 +1,76 @@ + + + + +vector_fill + + + +

vector_fill

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_fill, _vector_fill - fill a vector with identical elements
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_fill(v,obj,n) _vector_fill((v),&(obj),(n))
+void _vector_fill (vector, const void *ptr, int n);
+
+ +

DESCRIPTION

+ + + +
+vector_fill appends n identical copies of +obj to the vector. It is equivalent to calling +vector_push_back(3) in a loop n +times.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_get.3.html b/doc/vector_get.3.html new file mode 100644 index 0000000..38d7b29 --- /dev/null +++ b/doc/vector_get.3.html @@ -0,0 +1,106 @@ + + + + +vector_get + + + +

vector_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_get, _vector_get, vector_get_ptr, _vector_get_ptr - array-style indexing for vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_get(v,i,obj) _vector_get((v),(i),&(obj))
+void _vector_get (vector, int i, void *ptr);
+#define vector_get_ptr(v,i,ptr) (ptr) =((typeof (ptr))_vector_get_ptr((v),(i)))
+const void *_vector_get_ptr (vector, int i);
+
+ +

DESCRIPTION

+ + + +
+vector_get copies the element at index v[i] +into local variable obj. The vector is +unaffected.
+ + + +
+_vector_get copies the element into the memory +pointed to by ptr. If ptr is NULL then +the effect is simply to check that element v[i] +exists.
+ + + +
+vector_get_ptr and _vector_get_ptr are used to +get a pointer to an element in the vector. This pointer +actually points to the vector's internal data array. It is +only valid as long as the user does not cause the internal +data array to be reallocated or moved - typically this can +happen when the user performs some operation which inserts +more elements into the array.
+ + + +
+Array indexes are checked. An attempt to access an +out-of-bounds element will result in a call to +abort(3).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_get_ptr.3.html b/doc/vector_get_ptr.3.html new file mode 100644 index 0000000..4599344 --- /dev/null +++ b/doc/vector_get_ptr.3.html @@ -0,0 +1,106 @@ + + + + +vector_get + + + +

vector_get

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_get, _vector_get, vector_get_ptr, _vector_get_ptr - array-style indexing for vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_get(v,i,obj) _vector_get((v),(i),&(obj))
+void _vector_get (vector, int i, void *ptr);
+#define vector_get_ptr(v,i,ptr) (ptr) =((typeof (ptr))_vector_get_ptr((v),(i)))
+const void *_vector_get_ptr (vector, int i);
+
+ +

DESCRIPTION

+ + + +
+vector_get copies the element at index v[i] +into local variable obj. The vector is +unaffected.
+ + + +
+_vector_get copies the element into the memory +pointed to by ptr. If ptr is NULL then +the effect is simply to check that element v[i] +exists.
+ + + +
+vector_get_ptr and _vector_get_ptr are used to +get a pointer to an element in the vector. This pointer +actually points to the vector's internal data array. It is +only valid as long as the user does not cause the internal +data array to be reallocated or moved - typically this can +happen when the user performs some operation which inserts +more elements into the array.
+ + + +
+Array indexes are checked. An attempt to access an +out-of-bounds element will result in a call to +abort(3).
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_grep.3.html b/doc/vector_grep.3.html new file mode 100644 index 0000000..b1300cc --- /dev/null +++ b/doc/vector_grep.3.html @@ -0,0 +1,75 @@ + + + + +vector_grep + + + +

vector_grep

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_grep - produce a new vector containing elements of the old vector which match a boolean function
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+vector vector_grep (pool, vector v, int (*match_fn) (const void *));
+
+ +

DESCRIPTION

+ + + +
+This macro calls match_fn(&t) for each element +t of vector v. It constructs and returns a new +vector containing all those elements where the function +returns true.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_grep_pool.3.html b/doc/vector_grep_pool.3.html new file mode 100644 index 0000000..fdf5c10 --- /dev/null +++ b/doc/vector_grep_pool.3.html @@ -0,0 +1,75 @@ + + + + +vector_grep_pool + + + +

vector_grep_pool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_grep_pool - produce a new vector containing elements of the old vector which match a boolean function
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+vector vector_grep_pool (pool, vector v, int (*match_fn) (pool, const void *));
+
+ +

DESCRIPTION

+ + + +
+This macro calls match_fn(pool, &t) for each +element t of vector v. It constructs and +returns a new vector containing all those elements where the +function returns true.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_insert.3.html b/doc/vector_insert.3.html new file mode 100644 index 0000000..4351667 --- /dev/null +++ b/doc/vector_insert.3.html @@ -0,0 +1,90 @@ + + + + +vector_insert + + + +

vector_insert

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_insert, _vector_insert, vector_insert_array - insert elements into a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_insert(v,i,obj) _vector_insert((v),(i),&(obj))
+void _vector_insert (vector, int i, const void *ptr);
+void vector_insert_array (vector v, int i, const void *ptr, int n);
+
+ +

DESCRIPTION

+ + + +
+vector_insert inserts a single object obj +before element i. All other elements are moved up to +make space.
+ + + +
+vector_insert_array inserts an array of n +objects starting at address ptr into the vector +before index i.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_insert_array.3.html b/doc/vector_insert_array.3.html new file mode 100644 index 0000000..e5b2565 --- /dev/null +++ b/doc/vector_insert_array.3.html @@ -0,0 +1,90 @@ + + + + +vector_insert + + + +

vector_insert

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_insert, _vector_insert, vector_insert_array - insert elements into a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_insert(v,i,obj) _vector_insert((v),(i),&(obj))
+void _vector_insert (vector, int i, const void *ptr);
+void vector_insert_array (vector v, int i, const void *ptr, int n);
+
+ +

DESCRIPTION

+ + + +
+vector_insert inserts a single object obj +before element i. All other elements are moved up to +make space.
+ + + +
+vector_insert_array inserts an array of n +objects starting at address ptr into the vector +before index i.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_map.3.html b/doc/vector_map.3.html new file mode 100644 index 0000000..6bd53a8 --- /dev/null +++ b/doc/vector_map.3.html @@ -0,0 +1,76 @@ + + + + +vector_map + + + +

vector_map

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_map, _vector_map - apply function to each element of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_map(pool,v,map_fn,result_type) _vector_map ((pool), (v), (map_fn), sizeof (result_type))
+vector _vector_map (pool, vector v, void (*map_fn) (const void *, void *), size_t result_size);
+
+ +

DESCRIPTION

+ + + +
+Call map_fn(&t, &r) for each element t +of vector v. The result (r) should have type +result_type and these are concatenated to form a new +vector which is returned.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_map_pool.3.html b/doc/vector_map_pool.3.html new file mode 100644 index 0000000..e039a83 --- /dev/null +++ b/doc/vector_map_pool.3.html @@ -0,0 +1,76 @@ + + + + +vector_map_pool + + + +

vector_map_pool

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_map_pool, _vector_map_pool - apply function to each element of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_map_pool(pool,v,map_fn,result_type) _vector_map_pool ((pool), (v), (map_fn), sizeof (result_type))
+vector _vector_map_pool (pool, vector v, void (*map_fn_pool) (pool, const void *, void *), size_t result_size);
+
+ +

DESCRIPTION

+ + + +
+Call map_fn(pool, &t, &r) for each element +t of vector v. The result (r) should +have type result_type and these are concatenated to +form a new vector which is returned.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_pop_back.3.html b/doc/vector_pop_back.3.html new file mode 100644 index 0000000..16bb0cd --- /dev/null +++ b/doc/vector_pop_back.3.html @@ -0,0 +1,118 @@ + + + + +vector_push_back + + + +

vector_push_back

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_push_back, _vector_push_back, vector_pop_back, _vector_pop_back, vector_push_front, _vector_push_front, vector_pop_front, _vector_pop_front - push and pop objects into and out of vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_push_back(v,obj) _vector_push_back((v),&(obj))
+void _vector_push_back (vector, const void *ptr);
+#define vector_pop_back(v,obj) _vector_pop_back((v),&(obj))
+void _vector_pop_back (vector, void *ptr);
+#define vector_push_front(v,obj) _vector_push_front((v),&(obj))
+void _vector_push_front (vector, const void *ptr);
+#define vector_pop_front(v,obj) _vector_pop_front((v),&(obj))
+void _vector_pop_front (vector, void *ptr);
+
+ +

DESCRIPTION

+ + + +
+The *_push_* functions push objects onto +vectors.
+ + + +
+The *_pop_* functions pop objects off vectors into +local variables.
+ + + +
+The *_front functions push and pop objects off the +front of a vector. This type of operation is not very +efficient, because it involves moving all other elements of +the vector up or down by one place.
+ + + +
+The *_back functions push and pop elements off the +end of the vector, which is efficient.
+ + + +
+Each function has two forms: a macro version and an +underlying function.
+ + + +
+Array indexes are checked. You cannot pop an empty vector. +If ptr is NULL then the popped object is +discarded.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_pop_front.3.html b/doc/vector_pop_front.3.html new file mode 100644 index 0000000..288a2f2 --- /dev/null +++ b/doc/vector_pop_front.3.html @@ -0,0 +1,118 @@ + + + + +vector_push_back + + + +

vector_push_back

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_push_back, _vector_push_back, vector_pop_back, _vector_pop_back, vector_push_front, _vector_push_front, vector_pop_front, _vector_pop_front - push and pop objects into and out of vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_push_back(v,obj) _vector_push_back((v),&(obj))
+void _vector_push_back (vector, const void *ptr);
+#define vector_pop_back(v,obj) _vector_pop_back((v),&(obj))
+void _vector_pop_back (vector, void *ptr);
+#define vector_push_front(v,obj) _vector_push_front((v),&(obj))
+void _vector_push_front (vector, const void *ptr);
+#define vector_pop_front(v,obj) _vector_pop_front((v),&(obj))
+void _vector_pop_front (vector, void *ptr);
+
+ +

DESCRIPTION

+ + + +
+The *_push_* functions push objects onto +vectors.
+ + + +
+The *_pop_* functions pop objects off vectors into +local variables.
+ + + +
+The *_front functions push and pop objects off the +front of a vector. This type of operation is not very +efficient, because it involves moving all other elements of +the vector up or down by one place.
+ + + +
+The *_back functions push and pop elements off the +end of the vector, which is efficient.
+ + + +
+Each function has two forms: a macro version and an +underlying function.
+ + + +
+Array indexes are checked. You cannot pop an empty vector. +If ptr is NULL then the popped object is +discarded.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_push_back.3.html b/doc/vector_push_back.3.html new file mode 100644 index 0000000..6cb511f --- /dev/null +++ b/doc/vector_push_back.3.html @@ -0,0 +1,118 @@ + + + + +vector_push_back + + + +

vector_push_back

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_push_back, _vector_push_back, vector_pop_back, _vector_pop_back, vector_push_front, _vector_push_front, vector_pop_front, _vector_pop_front - push and pop objects into and out of vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_push_back(v,obj) _vector_push_back((v),&(obj))
+void _vector_push_back (vector, const void *ptr);
+#define vector_pop_back(v,obj) _vector_pop_back((v),&(obj))
+void _vector_pop_back (vector, void *ptr);
+#define vector_push_front(v,obj) _vector_push_front((v),&(obj))
+void _vector_push_front (vector, const void *ptr);
+#define vector_pop_front(v,obj) _vector_pop_front((v),&(obj))
+void _vector_pop_front (vector, void *ptr);
+
+ +

DESCRIPTION

+ + + +
+The *_push_* functions push objects onto +vectors.
+ + + +
+The *_pop_* functions pop objects off vectors into +local variables.
+ + + +
+The *_front functions push and pop objects off the +front of a vector. This type of operation is not very +efficient, because it involves moving all other elements of +the vector up or down by one place.
+ + + +
+The *_back functions push and pop elements off the +end of the vector, which is efficient.
+ + + +
+Each function has two forms: a macro version and an +underlying function.
+ + + +
+Array indexes are checked. You cannot pop an empty vector. +If ptr is NULL then the popped object is +discarded.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_push_front.3.html b/doc/vector_push_front.3.html new file mode 100644 index 0000000..f493bf4 --- /dev/null +++ b/doc/vector_push_front.3.html @@ -0,0 +1,118 @@ + + + + +vector_push_back + + + +

vector_push_back

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_push_back, _vector_push_back, vector_pop_back, _vector_pop_back, vector_push_front, _vector_push_front, vector_pop_front, _vector_pop_front - push and pop objects into and out of vectors
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_push_back(v,obj) _vector_push_back((v),&(obj))
+void _vector_push_back (vector, const void *ptr);
+#define vector_pop_back(v,obj) _vector_pop_back((v),&(obj))
+void _vector_pop_back (vector, void *ptr);
+#define vector_push_front(v,obj) _vector_push_front((v),&(obj))
+void _vector_push_front (vector, const void *ptr);
+#define vector_pop_front(v,obj) _vector_pop_front((v),&(obj))
+void _vector_pop_front (vector, void *ptr);
+
+ +

DESCRIPTION

+ + + +
+The *_push_* functions push objects onto +vectors.
+ + + +
+The *_pop_* functions pop objects off vectors into +local variables.
+ + + +
+The *_front functions push and pop objects off the +front of a vector. This type of operation is not very +efficient, because it involves moving all other elements of +the vector up or down by one place.
+ + + +
+The *_back functions push and pop elements off the +end of the vector, which is efficient.
+ + + +
+Each function has two forms: a macro version and an +underlying function.
+ + + +
+Array indexes are checked. You cannot pop an empty vector. +If ptr is NULL then the popped object is +discarded.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_reallocate.3.html b/doc/vector_reallocate.3.html new file mode 100644 index 0000000..6443663 --- /dev/null +++ b/doc/vector_reallocate.3.html @@ -0,0 +1,77 @@ + + + + +vector_reallocate + + + +

vector_reallocate

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_reallocate - change allocation for a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_reallocate (vector v, int n);
+
+ +

DESCRIPTION

+ + + +
+Increase the amount of space allocated to a vector. See also +vector_allocated(3). This function can be used to +avoid the vector itself making too many calls to the +underlying prealloc(3), particularly if you know in +advance exactly how many elements the vector will +contain.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_replace.3.html b/doc/vector_replace.3.html new file mode 100644 index 0000000..092cb5b --- /dev/null +++ b/doc/vector_replace.3.html @@ -0,0 +1,89 @@ + + + + +vector_replace + + + +

vector_replace

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_replace, _vector_replace, vector_replace_array - replace elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_replace(v,i,obj) _vector_replace((v),(i),&(obj))
+void _vector_replace (vector, int i, const void *ptr);
+void vector_replace_array (vector v, int i, const void *ptr, int n);
+
+ +

DESCRIPTION

+ + + +
+vector_replace replaces the single element at +v[i] with object obj.
+ + + +
+vector_replace_array replaces the n elements +in the vector starting at index i with the n +elements from the array ptr.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_replace_array.3.html b/doc/vector_replace_array.3.html new file mode 100644 index 0000000..f52126d --- /dev/null +++ b/doc/vector_replace_array.3.html @@ -0,0 +1,89 @@ + + + + +vector_replace + + + +

vector_replace

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_replace, _vector_replace, vector_replace_array - replace elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_replace(v,i,obj) _vector_replace((v),(i),&(obj))
+void _vector_replace (vector, int i, const void *ptr);
+void vector_replace_array (vector v, int i, const void *ptr, int n);
+
+ +

DESCRIPTION

+ + + +
+vector_replace replaces the single element at +v[i] with object obj.
+ + + +
+vector_replace_array replaces the n elements +in the vector starting at index i with the n +elements from the array ptr.
+ + + +
+Array indexes are checked.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_reverse.3.html b/doc/vector_reverse.3.html new file mode 100644 index 0000000..f0b6139 --- /dev/null +++ b/doc/vector_reverse.3.html @@ -0,0 +1,72 @@ + + + + +vector_reverse + + + +

vector_reverse

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_reverse - reverse the elements of a vector in-place
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_reverse (vector v);
+
+ +

DESCRIPTION

+ + + +
+Reverse the elements of a vector in-place.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_size.3.html b/doc/vector_size.3.html new file mode 100644 index 0000000..1ede40a --- /dev/null +++ b/doc/vector_size.3.html @@ -0,0 +1,73 @@ + + + + +vector_size + + + +

vector_size

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_size - return the size of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_size(v) ((v)->used)
+
+ +

DESCRIPTION

+ + + +
+Return the size (ie. number of elements) in the +vector.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_sort.3.html b/doc/vector_sort.3.html new file mode 100644 index 0000000..a58d601 --- /dev/null +++ b/doc/vector_sort.3.html @@ -0,0 +1,74 @@ + + + + +vector_sort + + + +

vector_sort

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_sort, _vector_sort - sort a vector in-place
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+#define vector_sort(v,compare_fn) _vector_sort ((v), (int (*)(const void *,const void *)) (compare_fn))
+void _vector_sort (vector v, int (*compare_fn) (const void *, const void *));
+
+ +

DESCRIPTION

+ + + +
+Sort a vector in-place, comparing elements using +compare_fn.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/vector_swap.3.html b/doc/vector_swap.3.html new file mode 100644 index 0000000..4544dd0 --- /dev/null +++ b/doc/vector_swap.3.html @@ -0,0 +1,73 @@ + + + + +vector_swap + + + +

vector_swap

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+ +
+ + + +

NAME

+ + +
+vector_swap - swap two elements of a vector
+ +

SYNOPSIS

+ + + +
+
#include <vector.h>
+
+void vector_swap (vector v, int i, int j);
+
+ +

DESCRIPTION

+ + + +
+Swap elements i and j of vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+
+ + diff --git a/doc/zero_vec.3.html b/doc/zero_vec.3.html new file mode 100644 index 0000000..1f8dc0f --- /dev/null +++ b/doc/zero_vec.3.html @@ -0,0 +1,105 @@ + + + + +identity_matrix + + + +

identity_matrix

+NAME
+SYNOPSIS
+DESCRIPTION
+AUTHOR
+LICENSE
+VERSION
+SEE ALSO
+ +
+ + + +

NAME

+ + +
+identity_matrix, zero_vec, new_identity_matrix, new_zero_vec, make_identity_matrix, make_zero_vec - identity matrix and zero vector
+ +

SYNOPSIS

+ + + +
+
#include <matvec.h>
+
+float identity_matrix[16];
+float zero_vec[4];
+float *new_identity_matrix (pool);
+float *new_zero_vec (pool);
+#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16);
+#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4);
+
+ +

DESCRIPTION

+ + + +
+The identity_matrix variable contains a read-only +copy of the identity matrix. The zero_vec variable +contains a read-only copy of the zero vector.
+ + + +
+Use new_identity_matrix to allocate a new identity +matrix variable in pool. Use new_zero_vec to +similarly allocate a new zero vector.
+ + + +
+Use make_identity_matrix to copy the identity matrix +over an existing matrix m. Use make_zero_vec +to similarly copy the zero vector over an existing vector +v.
+ +

AUTHOR

+ + + +
+Richard Jones <rich@annexia.org>
+ +

LICENSE

+ + + +
+GNU LGPL (see http://www.gnu.org/)
+ +

VERSION

+ + + +
+c2lib-1.2.13
+ +

SEE ALSO

+ + + +
+new_matrix(3), new_vec(3).
+
+ + diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..b88c9e8 --- /dev/null +++ b/hash.c @@ -0,0 +1,936 @@ +/* A hash class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: hash.c,v 1.4 2002/11/26 19:47:29 rich Exp $ + */ + +#include "config.h" + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include + +struct hash +{ + pool pool; + size_t key_size; + size_t value_size; + vector buckets; +}; + +struct sash +{ + pool pool; + vector buckets; +}; + +struct shash +{ + pool pool; + size_t value_size; + vector buckets; +}; + +#define HASH_NR_BUCKETS 32 + +/* This is the hashing function -- the same one as used by Perl. */ +static inline unsigned +HASH (const void *key, size_t key_size, int nr_buckets) +{ + unsigned h = 0; + const char *s = (const char *) key; + + while (key_size--) + h = h * 33 + *s++; + + return h & (nr_buckets - 1); +} + +/*----- HASHes -----*/ + +struct hash_bucket_entry +{ + void *key; + void *value; +}; + +hash +_hash_new (pool pool, size_t key_size, size_t value_size) +{ + hash h; + vector null = 0; + + h = pmalloc (pool, sizeof *h); + h->pool = pool; + h->key_size = key_size; + h->value_size = value_size; + h->buckets = new_vector (pool, sizeof (vector)); + vector_fill (h->buckets, null, HASH_NR_BUCKETS); + + return h; +} + +/* NB. This only copies the hash, NOT the structures or whatever + * which might be pointed to by keys/values in the hash. Beware. + */ +hash +copy_hash (pool pool, hash h) +{ + hash new_h; + int b, i; + + new_h = pmalloc (pool, sizeof *new_h); + new_h->pool = pool; + new_h->key_size = h->key_size; + new_h->value_size = h->value_size; + new_h->buckets = copy_vector (pool, h->buckets); + + /* Copy the buckets. */ + for (b = 0; b < vector_size (new_h->buckets); ++b) + { + vector v; + + vector_get (new_h->buckets, b, v); + + if (v) + { + v = copy_vector (pool, v); + vector_replace (new_h->buckets, b, v); + + /* Copy the keys/values in this vector. */ + for (i = 0; i < vector_size (v); ++i) + { + struct hash_bucket_entry entry; + + vector_get (v, i, entry); + entry.key = pmemdup (pool, entry.key, h->key_size); + entry.value = pmemdup (pool, entry.value, h->value_size); + vector_replace (v, i, entry); + } + } + } + + return new_h; +} + +int +_hash_get (hash h, const void *key, void *value) +{ + const void *ptr; + + ptr = _hash_get_ptr (h, key); + if (ptr == 0) return 0; + + if (value) memcpy (value, ptr, h->value_size); + return 1; +} + +const void * +_hash_get_ptr (hash h, const void *key) +{ + int b, i; + vector bucket; + + /* Find the appropriate bucket. */ + b = HASH (key, h->key_size, vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) + return 0; + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + struct hash_bucket_entry entry; + + vector_get (bucket, i, entry); + if (memcmp (entry.key, key, h->key_size) == 0) + return entry.value; + } + + return 0; +} + +int +_hash_insert (hash h, const void *key, const void *value) +{ + int b, i; + vector bucket; + struct hash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, h->key_size, vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + /* If there is no bucket there, we have to allocate a fresh vector. */ + if (bucket == 0) + { + bucket = new_vector (h->pool, struct hash_bucket_entry); + vector_replace (h->buckets, b, bucket); + } + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (memcmp (entry.key, key, h->key_size) == 0) + { + memcpy (entry.value, value, h->value_size); + /*entry.value = pmemdup (h->pool, value, h->value_size);*/ + + /* Replace this entry. */ + vector_replace (bucket, i, entry); + + return 1; + } + } + + /* Append to this bucket. */ + entry.key = pmemdup (h->pool, key, h->key_size); + entry.value = pmemdup (h->pool, value, h->value_size); + + vector_push_back (bucket, entry); + return 0; +} + +int +_hash_erase (hash h, const void *key) +{ + int b, i; + vector bucket; + struct hash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, h->key_size, vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) return 0; + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (memcmp (entry.key, key, h->key_size) == 0) + { + /* Remove this entry. */ + vector_erase (bucket, i); + + return 1; + } + } + + return 0; +} + +inline vector +hash_keys_in_pool (hash h, pool p) +{ + int i, j; + vector bucket, keys; + struct hash_bucket_entry entry; + + keys = _vector_new (p, h->key_size); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + vector_get (bucket, j, entry); + _vector_push_back (keys, entry.key); + } + } + + return keys; +} + +vector +hash_keys (hash h) +{ + return hash_keys_in_pool (h, h->pool); +} + +inline vector +hash_values_in_pool (hash h, pool p) +{ + int i, j; + vector bucket, values; + struct hash_bucket_entry entry; + + values = _vector_new (p, h->value_size); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + vector_get (bucket, j, entry); + _vector_push_back (values, entry.value); + } + } + + return values; +} + +vector +hash_values (hash h) +{ + return hash_values_in_pool (h, h->pool); +} + +int +hash_size (hash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? vector_size (bucket) : 0; + } + + return n; +} + +int +hash_get_buckets_used (hash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? 1 : 0; + } + + return n; +} + +int +hash_get_buckets_allocated (hash h) +{ + return vector_size (h->buckets); +} + +void +hash_set_buckets_allocated (hash h, int new_size) +{ + vector null = 0; + + /* The user has been warned not to call this after elements have been + * inserted into the hash, and to make NEW_SIZE a power of 2. + */ + if (vector_size (h->buckets) > new_size) + vector_erase_range (h->buckets, new_size, vector_size (h->buckets)); + else if (vector_size (h->buckets) < new_size) + vector_fill (h->buckets, null, new_size - vector_size (h->buckets)); +} + +/*----- SASHes -----*/ + +struct sash_bucket_entry +{ + char *key; + char *value; + int value_allocated; +}; + +sash +new_sash (pool pool) +{ + sash h; + vector null = 0; + + h = pmalloc (pool, sizeof *h); + h->pool = pool; + h->buckets = new_vector (pool, sizeof (vector)); + vector_fill (h->buckets, null, HASH_NR_BUCKETS); + + return h; +} + +/* NB. Unlike copy_hash, this does copy the strings into the new + * pool. So a copy_sash is really a deep copy of the string hash and the + * strings. + */ +sash +copy_sash (pool pool, sash h) +{ + sash new_h; + int b, i; + + new_h = pmalloc (pool, sizeof *new_h); + new_h->pool = pool; + new_h->buckets = copy_vector (pool, h->buckets); + + /* Copy the buckets. */ + for (b = 0; b < vector_size (new_h->buckets); ++b) + { + vector v; + + vector_get (new_h->buckets, b, v); + + if (v) + { + v = copy_vector (pool, v); + vector_replace (new_h->buckets, b, v); + + /* Copy the string keys/values in this vector. */ + for (i = 0; i < vector_size (v); ++i) + { + struct sash_bucket_entry entry; + + vector_get (v, i, entry); + entry.key = pstrdup (pool, entry.key); + entry.value = pstrdup (pool, entry.value); + vector_replace (v, i, entry); + } + } + } + + return new_h; +} + +int +_sash_get (sash h, const char *key, const char **ptr) +{ + int b, i; + vector bucket; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) + { + if (ptr) *ptr = 0; + return 0; + } + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + struct sash_bucket_entry entry; + + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + { + if (ptr) *ptr = entry.value; + return 1; + } + } + + if (ptr) *ptr = 0; + return 0; +} + +int +sash_insert (sash h, const char *key, const char *value) +{ + int b, i, len = strlen (value); + vector bucket; + struct sash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + /* If there is no bucket there, we have to allocate a fresh vector. */ + if (bucket == 0) + { + bucket = new_vector (h->pool, struct sash_bucket_entry); + vector_replace (h->buckets, b, bucket); + } + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + { + /* To avoid unnecessarily allocating more memory, we try to + * be clever here. If the existing allocation is large enough + * to store the new string, use it. Otherwise reallocate it + * to make it bigger. + */ + if (len < entry.value_allocated) + memcpy (entry.value, value, len + 1); + else + { + entry.value = prealloc (h->pool, entry.value, len + 1); + memcpy (entry.value, value, len + 1); + entry.value_allocated = len + 1; + } + + /* Replace this entry. */ + vector_replace (bucket, i, entry); + + return 1; + } + } + + /* Append to this bucket. */ + entry.key = pstrdup (h->pool, key); + entry.value = pstrdup (h->pool, value); + entry.value_allocated = len + 1; + + vector_push_back (bucket, entry); + return 0; +} + +int +sash_erase (sash h, const char *key) +{ + int b, i; + vector bucket; + struct sash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) return 0; + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + { + /* Remove this entry. */ + vector_erase (bucket, i); + + return 1; + } + } + + return 0; +} + +inline vector +sash_keys_in_pool (sash h, pool p) +{ + int i, j; + vector bucket, keys; + struct sash_bucket_entry entry; + + keys = new_vector (p, char *); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + char *key; + + vector_get (bucket, j, entry); + key = pstrdup (p, entry.key); + vector_push_back (keys, key); + } + } + + return keys; +} + +vector +sash_keys (sash h) +{ + return sash_keys_in_pool (h, h->pool); +} + +inline vector +sash_values_in_pool (sash h, pool p) +{ + int i, j; + vector bucket, values; + struct sash_bucket_entry entry; + + values = new_vector (p, char *); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + char *value; + + vector_get (bucket, j, entry); + value = pstrdup (p, entry.value); + vector_push_back (values, value); + } + } + + return values; +} + +vector +sash_values (sash h) +{ + return sash_values_in_pool (h, h->pool); +} + +int +sash_size (sash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? vector_size (bucket) : 0; + } + + return n; +} + +int +sash_get_buckets_used (sash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? 1 : 0; + } + + return n; +} + +int +sash_get_buckets_allocated (sash h) +{ + return vector_size (h->buckets); +} + +void +sash_set_buckets_allocated (sash h, int new_size) +{ + vector null = 0; + + /* The user has been warned not to call this after elements have been + * inserted into the sash, and to make NEW_SIZE a power of 2. + */ + if (vector_size (h->buckets) > new_size) + vector_erase_range (h->buckets, new_size, vector_size (h->buckets)); + else if (vector_size (h->buckets) < new_size) + vector_fill (h->buckets, null, new_size - vector_size (h->buckets)); +} + +/*----- SHASHes -----*/ + +struct shash_bucket_entry +{ + char *key; + void *value; +}; + +shash +_shash_new (pool pool, size_t value_size) +{ + shash h; + vector null = 0; + + h = pmalloc (pool, sizeof *h); + h->pool = pool; + h->value_size = value_size; + h->buckets = new_vector (pool, sizeof (vector)); + vector_fill (h->buckets, null, HASH_NR_BUCKETS); + + return h; +} + +/* NB. Unlike copy_hash, this does copy the strings into the new + * pool. So a copy_shash is really a deep copy of the shash and the + * strings. + */ +shash +copy_shash (pool pool, shash h) +{ + shash new_h; + int b, i; + + new_h = pmalloc (pool, sizeof *new_h); + new_h->pool = pool; + new_h->value_size = h->value_size; + new_h->buckets = copy_vector (pool, h->buckets); + + /* Copy the buckets. */ + for (b = 0; b < vector_size (new_h->buckets); ++b) + { + vector v; + + vector_get (new_h->buckets, b, v); + + if (v) + { + v = copy_vector (pool, v); + vector_replace (new_h->buckets, b, v); + + /* Copy the string keys in this vector. */ + for (i = 0; i < vector_size (v); ++i) + { + struct shash_bucket_entry entry; + + vector_get (v, i, entry); + entry.key = pstrdup (pool, entry.key); + entry.value = pmemdup (pool, entry.value, h->value_size); + vector_replace (v, i, entry); + } + } + } + + return new_h; +} + +int +_shash_get (shash h, const char *key, void *value) +{ + const void *ptr; + + ptr = _shash_get_ptr (h, key); + if (ptr == 0) return 0; + + if (value) memcpy (value, ptr, h->value_size); + return 1; +} + +const void * +_shash_get_ptr (shash h, const char *key) +{ + int b, i; + vector bucket; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) + return 0; + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + struct shash_bucket_entry entry; + + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + return entry.value; + } + + return 0; +} + +int +_shash_insert (shash h, const char *key, const void *value) +{ + int b, i; + vector bucket; + struct shash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + /* If there is no bucket there, we have to allocate a fresh vector. */ + if (bucket == 0) + { + bucket = new_vector (h->pool, struct shash_bucket_entry); + vector_replace (h->buckets, b, bucket); + } + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + { + memcpy (entry.value, value, h->value_size); + /*entry.value = pmemdup (h->pool, value, h->value_size);*/ + + /* Replace this entry. */ + vector_replace (bucket, i, entry); + + return 1; + } + } + + /* Append to this bucket. */ + entry.key = pstrdup (h->pool, key); + entry.value = pmemdup (h->pool, value, h->value_size); + + vector_push_back (bucket, entry); + return 0; +} + +int +shash_erase (shash h, const char *key) +{ + int b, i; + vector bucket; + struct shash_bucket_entry entry; + + /* Find the appropriate bucket. */ + b = HASH (key, strlen (key), vector_size (h->buckets)); + vector_get (h->buckets, b, bucket); + + if (bucket == 0) return 0; + + /* Search this bucket linearly. */ + for (i = 0; i < vector_size (bucket); ++i) + { + vector_get (bucket, i, entry); + if (strcmp (entry.key, key) == 0) + { + /* Remove this entry. */ + vector_erase (bucket, i); + + return 1; + } + } + + return 0; +} + +inline vector +shash_keys_in_pool (shash h, pool p) +{ + int i, j; + vector bucket, keys; + struct shash_bucket_entry entry; + + keys = new_vector (p, char *); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + char *key; + + vector_get (bucket, j, entry); + key = pstrdup (p, entry.key); + vector_push_back (keys, key); + } + } + + return keys; +} + +vector +shash_keys (shash h) +{ + return shash_keys_in_pool (h, h->pool); +} + +inline vector +shash_values_in_pool (shash h, pool p) +{ + int i, j; + vector bucket, values; + struct shash_bucket_entry entry; + + values = _vector_new (p, h->value_size); + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + + if (bucket) + for (j = 0; j < vector_size (bucket); ++j) + { + vector_get (bucket, j, entry); + _vector_push_back (values, entry.value); + } + } + + return values; +} + +vector +shash_values (shash h) +{ + return shash_values_in_pool (h, h->pool); +} + +int +shash_size (shash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? vector_size (bucket) : 0; + } + + return n; +} + +int +shash_get_buckets_used (shash h) +{ + vector bucket; + int n = 0, i; + + for (i = 0; i < vector_size (h->buckets); ++i) + { + vector_get (h->buckets, i, bucket); + n += bucket ? 1 : 0; + } + + return n; +} + +int +shash_get_buckets_allocated (shash h) +{ + return vector_size (h->buckets); +} + +void +shash_set_buckets_allocated (shash h, int new_size) +{ + vector null = 0; + + /* The user has been warned not to call this after elements have been + * inserted into the shash, and to make NEW_SIZE a power of 2. + */ + if (vector_size (h->buckets) > new_size) + vector_erase_range (h->buckets, new_size, vector_size (h->buckets)); + else if (vector_size (h->buckets) < new_size) + vector_fill (h->buckets, null, new_size - vector_size (h->buckets)); +} diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..161d6c6 --- /dev/null +++ b/hash.h @@ -0,0 +1,358 @@ +/* Generalized hash and string hash (sash) classes. + * By Richard W.M. Jones + * + * 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. + * + * $Id: hash.h,v 1.6 2002/11/26 19:47:30 rich Exp $ + */ + +#ifndef HASH_H +#define HASH_H + +#include + +/* Note, hash and sash are identical but for the fact that + * hash maps fixed sized keys to values (eg. int -> int or + * int -> struct) and sash maps nul-terminated ASCII strings + * to nul-terminated ASCII strings (ie. string -> string ONLY). + * shash maps nul-terminated ASCII strings to anything else. + */ + +struct hash; +typedef struct hash *hash; + +struct sash; +typedef struct sash *sash; + +struct shash; +typedef struct shash *shash; + +/* Function: new_hash - allocate a new hash + * Function: _hash_new + * + * Allocate a new hash in @code{pool} mapping + * @code{key_type} to @code{value_type}. You can map both + * simple types like @code{int} and also aggregate types + * like structures and unions. However, beware of aggregate + * types that might contain 'holes' because of alignment -- + * such types will probably not work as you expect, particularly + * if used as keys. + * + * If you wish to have + * a hash which maps strings to something, then calling + * @code{new_hash(pool, char *, char *)} (for example) will not do what + * you expect. You are better to use either a sash (string to string hash) + * or a shash (string to anything hash) instead (see + * @ref{new_sash(3)} and @ref{new_shash(3)}). + */ +#define new_hash(pool,key_type,value_type) _hash_new ((pool), sizeof (key_type), sizeof (value_type)) +extern hash _hash_new (pool, size_t key_size, size_t value_size); + +/* Function: copy_hash - copy a hash + * + * Copy a hash into a new pool. This function copies the keys + * and values, but if keys and values are pointers, then it does + * not perform a 'deep' copy. + */ +extern hash copy_hash (pool, hash); + +/* Function: hash_get - look up in a hash + * Function: _hash_get + * Function: hash_get_ptr + * Function: _hash_get_ptr + * Function: hash_exists + * + * Get the @code{value} associated with key @code{key} and return true. + * If there is no @code{value} associated with @code{key}, this returns + * false and @code{value} is left unchanged. + * + * The @code{*_ptr} variants return a pointer rather than copying + * out the entire value object. The pointer is typically only + * valid for a short period of time. Particularly if you insert + * or remove elements from the hash, this pointer may become + * invalid. + * + * @code{hash_exists} simply tests whether or not @code{key} exists + * in the hash. If so, it returns true, otherwise false. + */ +#define hash_get(h,key,value) _hash_get ((h), &(key), &(value)) +extern int _hash_get (hash, const void *key, void *value); +#define hash_get_ptr(h,key,ptr) ((ptr) = ((typeof (ptr))_hash_get_ptr ((h), &(key)))) +extern const void *_hash_get_ptr (hash, const void *key); +#define hash_exists(h,key) (_hash_get_ptr ((h), &(key)) ? 1 : 0) + +/* Function: hash_insert - insert a (key, value) pair into a hash + * Function: _hash_insert + * + * Insert an element (@code{key}, @code{value}) into the hash. + * If @code{key} already + * exists in the hash, then the existing value is replaced by + * @code{value} + * and the function returns true. If there was no previous @code{key} + * in the hash then this function returns false. + */ +#define hash_insert(h,key,value) _hash_insert((h),&(key),&(value)) +extern int _hash_insert (hash, const void *key, const void *value); + +/* Function: hash_erase - erase a key from a hash + * Function: _hash_erase + * + * Erase @code{key} from the hash. If an element was erased, + * this returns true, else this returns false. + */ +#define hash_erase(h,key) _hash_erase((h),&(key)) +extern int _hash_erase (hash, const void *key); + +/* Function: hash_keys - return a vector of the keys or values in a hash + * Function: hash_keys_in_pool + * Function: hash_values + * Function: hash_values_in_pool + * + * Return a vector containing all the keys or values of hash. The + * @code{*_in_pool} variants allow you to allocate the vector in + * another pool (the default is to allocate the vector in the same + * pool as the hash). + */ +extern vector hash_keys (hash); +extern vector hash_keys_in_pool (hash, pool); +extern vector hash_values (hash); +extern vector hash_values_in_pool (hash, pool); + +/* Function: hash_size - return the number of (key, value) pairs in a hash + * + * Count the number of (key, value) pairs in the hash. + */ +extern int hash_size (hash); + +/* Function: hash_get_buckets_used - return the number of buckets in a hash + * Function: hash_get_buckets_allocated + * + * Return the number of hash buckets used and allocated. The number of + * buckets allocated is always a power of 2. See also + * @ref{hash_set_buckets_allocated} to change the number used + * in the hash. + */ +extern int hash_get_buckets_used (hash); +extern int hash_get_buckets_allocated (hash); + +/* Function: hash_set_buckets_allocated - set the number of buckets + * + * Set the number of buckets allocated. You may ONLY do this when you + * have just created the hash and before you have inserted any elements. + * Otherwise the results are undefined (and probably bad). The number + * of buckets MUST be a power of 2. + */ +extern void hash_set_buckets_allocated (hash, int); + +/* Function: new_sash - allocate a new sash (string hash) + * + * Allocate a new sash in @code{pool} mapping + * strings to strings. + * + * Use a string hash in preference to a hash of + * @code{char *} -> @code{char *} which will probably not + * quite work as you expect. + */ +extern sash new_sash (pool); + +/* Function: copy_sash - copy a sash + * + * Copy a sash into a new pool. This function copies the keys + * and values, but if keys and values are pointers, then it does + * not perform a 'deep' copy. + */ +extern sash copy_sash (pool, sash); + +/* Function: sash_get - look up in a sash + * Function: _sash_get + * Function: sash_exists + * + * Get the @code{value} associated with key @code{key} and return true. + * If there is no @code{value} associated with @code{key}, this returns + * false and @code{value} is left unchanged. + * + * @code{sash_exists} simply tests whether or not @code{key} exists + * in the sash. If so, it returns true, otherwise false. + */ +#define sash_get(sash,key,value) _sash_get((sash),(key),&(value)) +extern int _sash_get (sash, const char *key, const char **ptr); +#define sash_exists(sash,key) _sash_get ((sash), (key), 0) + +/* Function: sash_insert - insert a (key, value) pair into a sash + * + * Insert an element (@code{key}, @code{value}) into the sash. + * If @code{key} already + * exists in the sash, then the existing value is replaced by + * @code{value} + * and the function returns true. If there was no previous @code{key} + * in the sash then this function returns false. + */ +extern int sash_insert (sash, const char *key, const char *value); + +/* Function: sash_erase - erase a key from a sash + * + * Erase @code{key} from the sash. If an element was erased, + * this returns true, else this returns false. + */ +extern int sash_erase (sash, const char *key); + +/* Function: sash_keys - return a vector of the keys or values in a sash + * Function: sash_keys_in_pool + * Function: sash_values + * Function: sash_values_in_pool + * + * Return a vector containing all the keys or values of sash. The + * @code{*_in_pool} variants allow you to allocate the vector in + * another pool (the default is to allocate the vector in the same + * pool as the sash). + */ +extern vector sash_keys (sash); +extern vector sash_keys_in_pool (sash, pool); +extern vector sash_values (sash); +extern vector sash_values_in_pool (sash, pool); + +/* Function: sash_size - return the number of (key, value) pairs in a sash + * + * Count the number of (key, value) pairs in the sash. + */ +extern int sash_size (sash); + +/* Function: sash_get_buckets_used - return the number of buckets in a sash + * Function: sash_get_buckets_allocated + * + * Return the number of sash buckets used and allocated. The number of + * buckets allocated is always a power of 2. See also + * @ref{sash_set_buckets_allocated} to change the number used + * in the sash. + */ +extern int sash_get_buckets_used (sash); +extern int sash_get_buckets_allocated (sash); + +/* Function: sash_set_buckets_allocated - set the number of buckets + * + * Set the number of buckets allocated. You may ONLY do this when you + * have just created the sash and before you have inserted any elements. + * Otherwise the results are undefined (and probably bad). The number + * of buckets MUST be a power of 2. + */ +extern void sash_set_buckets_allocated (sash, int); + +/* Function: new_shash - allocate a new shash (string -> something hash) + * + * Allocate a new shash in @code{pool} mapping + * strings to strings. + * + * Use a shash in preference to a hash of + * @code{char *} -> something which will probably not + * quite work as you expect. + */ +#define new_shash(pool,value_type) _shash_new ((pool), sizeof (value_type)) +extern shash _shash_new (pool, size_t value_size); + +/* Function: copy_shash - copy a shash + * + * Copy a shash into a new pool. This function copies the keys + * and values, but if keys and values are pointers, then it does + * not perform a 'deep' copy. + */ +extern shash copy_shash (pool, shash); + +/* Function: shash_get - look up in a shash + * Function: _shash_get + * Function: shash_get_ptr + * Function: _shash_get_ptr + * Function: shash_exists + * + * Get the @code{value} associated with key @code{key} and return true. + * If there is no @code{value} associated with @code{key}, this returns + * false and @code{value} is left unchanged. + * + * The @code{*_ptr} variants return a pointer rather than copying + * out the entire value object. The pointer is typically only + * valid for a short period of time. Particularly if you insert + * or remove elements from the shash, this pointer may become + * invalid. + * + * @code{shash_exists} simply tests whether or not @code{key} exists + * in the shash. If so, it returns true, otherwise false. + */ +#define shash_get(shash,key,value) _shash_get((shash),(key),&(value)) +extern int _shash_get (shash, const char *key, void *value); +#define shash_get_ptr(h,key,ptr) ((ptr) = ((typeof (ptr))_shash_get_ptr ((h),(key)))) +extern const void *_shash_get_ptr (shash, const char *key); +#define shash_exists(shash,key) (_shash_get_ptr ((shash), (key)) ? 1 : 0) + +/* Function: shash_insert - insert a (key, value) pair into a shash + * Function: _shash_insert + * + * Insert an element (@code{key}, @code{value}) into the shash. + * If @code{key} already + * exists in the shash, then the existing value is replaced by + * @code{value} + * and the function returns true. If there was no previous @code{key} + * in the shash then this function returns false. + */ +#define shash_insert(h,key,value) _shash_insert((h),(key),&(value)) +extern int _shash_insert (shash, const char *key, const void *value); + +/* Function: shash_erase - erase a key from a shash + * + * Erase @code{key} from the shash. If an element was erased, + * this returns true, else this returns false. + */ +extern int shash_erase (shash, const char *key); + +/* Function: shash_keys - return a vector of the keys or values in a shash + * Function: shash_keys_in_pool + * Function: shash_values + * Function: shash_values_in_pool + * + * Return a vector containing all the keys or values of shash. The + * @code{*_in_pool} variants allow you to allocate the vector in + * another pool (the default is to allocate the vector in the same + * pool as the shash). + */ +extern vector shash_keys (shash); +extern vector shash_keys_in_pool (shash, pool); +extern vector shash_values (shash); +extern vector shash_values_in_pool (shash, pool); + +/* Function: shash_size - return the number of (key, value) pairs in a shash + * + * Count the number of (key, value) pairs in the shash. + */ +extern int shash_size (shash); + +/* Function: shash_get_buckets_used - return the number of buckets in a shash + * Function: shash_get_buckets_allocated + * + * Return the number of shash buckets used and allocated. The number of + * buckets allocated is always a power of 2. See also + * @ref{shash_set_buckets_allocated} to change the number used + * in the shash. + */ +extern int shash_get_buckets_used (shash); +extern int shash_get_buckets_allocated (shash); + +/* Function: shash_set_buckets_allocated - set the number of buckets + * + * Set the number of buckets allocated. You may ONLY do this when you + * have just created the shash and before you have inserted any elements. + * Otherwise the results are undefined (and probably bad). The number + * of buckets MUST be a power of 2. + */ +extern void shash_set_buckets_allocated (shash, int); + +#endif /* HASH_H */ diff --git a/matvec.c b/matvec.c new file mode 100644 index 0000000..f8c033e --- /dev/null +++ b/matvec.c @@ -0,0 +1,909 @@ +/* Matrix and vector arithmetic. + * By Richard W.M. Jones + * + * 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. + * + * $Id: matvec.c,v 1.5 2002/05/04 11:54:23 rich Exp $ + */ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include "matvec.h" + +float identity_matrix[16] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; + +float zero_vec[4] = { 0, 0, 0, 1 }; + +float * +new_identity_matrix (pool pool) +{ + float *m = new_matrix (pool); + make_identity_matrix (m); + return m; +} + +float * +new_zero_vec (pool pool) +{ + float *v = new_vec (pool); + make_zero_vec (v); + return v; +} + +/* This code is taken from Mesa 3.0. I have exchanged degrees for radians. */ +void +make_rotation_matrix (float angle, + float x, float y, float z, + float *m) +{ + /* This function contributed by Erich Boleyn (erich@uruk.org) */ + float mag, s, c; + float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; + + s = sin(angle); + c = cos(angle); + + mag = sqrt ( x*x + y*y + z*z ); + + if (mag == 0.0) { + /* generate an identity matrix and return */ + make_identity_matrix (m); + return; + } + + x /= mag; + y /= mag; + z /= mag; + +#define M(row,col) m[col*4+row] + + /* + * Arbitrary axis rotation matrix. + * + * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied + * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation + * (which is about the X-axis), and the two composite transforms + * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary + * from the arbitrary axis to the X-axis then back. They are + * all elementary rotations. + * + * Rz' is a rotation about the Z-axis, to bring the axis vector + * into the x-z plane. Then Ry' is applied, rotating about the + * Y-axis to bring the axis vector parallel with the X-axis. The + * rotation about the X-axis is then performed. Ry and Rz are + * simply the respective inverse transforms to bring the arbitrary + * axis back to it's original orientation. The first transforms + * Rz' and Ry' are considered inverses, since the data from the + * arbitrary axis gives you info on how to get to it, not how + * to get away from it, and an inverse must be applied. + * + * The basic calculation used is to recognize that the arbitrary + * axis vector (x, y, z), since it is of unit length, actually + * represents the sines and cosines of the angles to rotate the + * X-axis to the same orientation, with theta being the angle about + * Z and phi the angle about Y (in the order described above) + * as follows: + * + * cos ( theta ) = x / sqrt ( 1 - z^2 ) + * sin ( theta ) = y / sqrt ( 1 - z^2 ) + * + * cos ( phi ) = sqrt ( 1 - z^2 ) + * sin ( phi ) = z + * + * Note that cos ( phi ) can further be inserted to the above + * formulas: + * + * cos ( theta ) = x / cos ( phi ) + * sin ( theta ) = y / sin ( phi ) + * + * ...etc. Because of those relations and the standard trigonometric + * relations, it is pssible to reduce the transforms down to what + * is used below. It may be that any primary axis chosen will give the + * same results (modulo a sign convention) using thie method. + * + * Particularly nice is to notice that all divisions that might + * have caused trouble when parallel to certain planes or + * axis go away with care paid to reducing the expressions. + * After checking, it does perform correctly under all cases, since + * in all the cases of division where the denominator would have + * been zero, the numerator would have been zero as well, giving + * the expected result. + */ + + xx = x * x; + yy = y * y; + zz = z * z; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + one_c = 1.0F - c; + + M(0,0) = (one_c * xx) + c; + M(0,1) = (one_c * xy) - zs; + M(0,2) = (one_c * zx) + ys; + M(0,3) = 0.0F; + + M(1,0) = (one_c * xy) + zs; + M(1,1) = (one_c * yy) + c; + M(1,2) = (one_c * yz) - xs; + M(1,3) = 0.0F; + + M(2,0) = (one_c * zx) - ys; + M(2,1) = (one_c * yz) + xs; + M(2,2) = (one_c * zz) + c; + M(2,3) = 0.0F; + + M(3,0) = 0.0F; + M(3,1) = 0.0F; + M(3,2) = 0.0F; + M(3,3) = 1.0F; + +#undef M +} + +void +make_translation_matrix (float x, float y, float z, float *m) +{ + make_identity_matrix (m); + m[12] = x; + m[13] = y; + m[14] = z; +} + +void +make_scaling_matrix (float x, float y, float z, float *m) +{ + make_identity_matrix (m); + m[0] = x; + m[5] = y; + m[10] = z; +} + +/* The next two functions are from the matrix FAQ by , see: + * http://www.flipcode.com/documents/matrfaq.html + */ + +/* Quickly convert 3 Euler angles to a rotation matrix. */ +void +matrix_euler_to_rotation (float angle_x, float angle_y, float angle_z, + float *mat) +{ + float A = cos(angle_x); + float B = sin(angle_x); + float C = cos(angle_y); + float D = sin(angle_y); + float E = cos(angle_z); + float F = sin(angle_z); + + float AD = A * D; + float BD = B * D; + + mat[0] = C * E; + mat[4] = -C * F; + mat[8] = -D; + mat[1] = -BD * E + A * F; + mat[5] = BD * F + A * E; + mat[9] = -B * C; + mat[2] = AD * E + B * F; + mat[6] = -AD * F + B * E; + mat[10] = A * C; + + mat[12] = mat[13] = mat[14] = mat[3] = mat[7] = mat[11] = 0; + mat[15] = 1; +} + +static inline float +clamp (float v, float low, float high) +{ + /* This is not very efficient ... */ + v -= low; + while (v > high - low) v -= high - low; + while (v < 0) v += high - low; + v += low; + return v; +} + +/* Convert a rotation matrix to 3 Euler angles. */ +void +matrix_rotation_to_euler (const float *mat, + float *angle_x, float *angle_y, float *angle_z) +{ + float C, trx, try; + + *angle_y = -asin( mat[8]); /* Calculate Y-axis angle */ + C = cos( *angle_y ); + + if ( fabs( C ) > 0.005 ) /* Gimball lock? */ + { + trx = mat[10] / C; /* No, so get X-axis angle */ + try = -mat[9] / C; + + *angle_x = atan2( try, trx ); + + trx = mat[0] / C; /* Get Z-axis angle */ + try = -mat[4] / C; + + *angle_z = atan2( try, trx ); + } + else /* Gimball lock has occurred */ + { + trx = mat[5]; /* And calculate Z-axis angle */ + try = mat[1]; + + *angle_z = atan2( try, trx ); + } + + /* Clamp all angles to range */ + *angle_x = clamp (*angle_x, 0, 2 * M_PI); + *angle_y = clamp (*angle_y, 0, 2 * M_PI); + *angle_z = clamp (*angle_z, 0, 2 * M_PI); +} + +/* This code is taken from Mesa 3.0. + */ +void +matrix_multiply (const float *a, const float *b, + float *product) +{ + /* This matmul was contributed by Thomas Malik */ + int i; + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define P(row,col) product[(col<<2)+row] + + /* i-te Zeile */ + for (i = 0; i < 4; i++) { + float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); + P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); + P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); + P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); + P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); + } + +#undef A +#undef B +#undef P +} + +/* Multiply matrix by vector. */ +void +matrix_vec_multiply (const float *m, const float *v, + float *result) +{ + result[0] = m[0]*v[0] + m[1]*v[1] + m[2]*v[2] + m[3]*v[3]; + result[1] = m[4]*v[0] + m[5]*v[1] + m[6]*v[2] + m[7]*v[3]; + result[2] = m[8]*v[0] + m[9]*v[1] + m[10]*v[2] + m[11]*v[3]; + result[3] = m[12]*v[0] + m[13]*v[1] + m[14]*v[2] + m[15]*v[3]; +} + +/* Compute the magnitude of a vector. */ +float +vec_magnitude (const float *v) +{ + return sqrt (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); +} + +/* Compute the magnitude of a 2D vector. */ +float +vec_magnitude2d (const float *v) +{ + return sqrt (v[0]*v[0] + v[1]*v[1]); +} + +/* Normalize a vector. */ +void +vec_normalize (const float *v, float *r) +{ + float w = vec_magnitude (v); + r[0] = v[0] / w; + r[1] = v[1] / w; + r[2] = v[2] / w; +} + +/* Normalize a 2D vector. */ +void +vec_normalize2d (const float *v, float *r) +{ + float w = vec_magnitude2d (v); + r[0] = v[0] / w; + r[1] = v[1] / w; +} + +void +vec_unit_normal_to_side (float *side, float *normal) +{ + float n[3] = { side[0], side[1], side[2] }; + vec_normalize (n, normal); +} + +/* Compute the dot product of two vectors. */ +float +vec_dot_product (const float *v1, const float *v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +/* Compute the magnitude of vector v1 in direction vector v2. + * If v1 == v2, this returns 1. If v1 = -v2, this returns -1. + * If v1 is perpendicular to v2 this returns 0. + */ +float +vec_magnitude_in_direction (const float *v1, const float *v2) +{ + static float v1n[3], v2n[3]; + + /* Normalize both vectors. */ + vec_normalize (v1, v1n); + vec_normalize (v2, v2n); + + /* Return their dot product. */ + return vec_dot_product (v1n, v2n); +} + +/* Compute angle between two vectors. */ +float +vec_angle_between (const float *v1, const float *v2) +{ + return acos (vec_magnitude_in_direction (v1, v2)); +} + +/* Scale a vector. */ +void +vec_scale (const float *a, float n, float *r) +{ + r[0] = a[0] * n; + r[1] = a[1] * n; + r[2] = a[2] * n; +} + +/* Add two vectors. */ +void +vec_add (const float *a, const float *b, float *r) +{ + r[0] = a[0] + b[0]; + r[1] = a[1] + b[1]; + r[2] = a[2] + b[2]; +} + +/* Subtract two vectors. */ +void +vec_subtract (const float *a, const float *b, float *r) +{ + r[0] = a[0] - b[0]; + r[1] = a[1] - b[1]; + r[2] = a[2] - b[2]; +} + +/* Calculate midpoint. */ +void +point_midpoint (const float *p1, const float *p2, float *mp) +{ + mp[0] = (p1[0] + p2[0]) / 2; + mp[1] = (p1[1] + p2[1]) / 2; + mp[2] = (p1[2] + p2[2]) / 2; +} + +/* Calculate midpoint (in 2D). */ +void +point_midpoint2d (const float *p1, const float *p2, float *mp) +{ + mp[0] = (p1[0] + p2[0]) / 2; + mp[1] = (p1[1] + p2[1]) / 2; +} + +/* Distance between two points. */ +float +point_distance_to_point (const float *p1, const float *p2) +{ + float v[3]; + + vec_subtract (p1, p2, v); + return vec_magnitude (v); +} + +/* Cross product of vectors v and w. + * The cross product is a vector: + * + * v x w = |v| |w| sin t n^ + * + * where t is the angle between a and + * b, and n^ is a normal vector perpendicular + * to a and b such that a,b,n^ form a + * right-handed set. + */ +void +vec_cross_product (const float *v, const float *w, float *r) +{ + r[0] = v[1]*w[2] - v[2]*w[1]; + r[1] = v[2]*w[0] - v[0]*w[2]; + r[2] = v[0]*w[1] - v[1]*w[0]; +} + +/* Distance between two points. */ +float +point_distance (const float *p, const float *q) +{ + double x = p[0] - q[0]; + double y = p[1] - q[1]; + double z = p[2] - q[2]; + return sqrt (x*x + y*y + z*z); +} + +/* Distance from a point to a plane. */ +float +point_distance_to_plane (const float *plane, const float *point) +{ + float a = plane[0]; + float b = plane[1]; + float c = plane[2]; + float d = plane[3]; + float x = point[0]; + float y = point[1]; + float z = point[2]; + float t = (a*x + b*y + c*z + d) / - (a*a + b*b + c*c); + float t2 = t*t; + float dist = sqrt (t2*a*a + t2*b*b + t2*c*c); + /* Don't lose the sign of t. */ + if (t < 0) return dist; else return -dist; +} + +/* Return true if point_distance_to_plane > 0. */ +int +point_is_inside_plane (const float *plane, const float *point) +{ + float a = plane[0]; + float b = plane[1]; + float c = plane[2]; + float d = plane[3]; + float x = point[0]; + float y = point[1]; + float z = point[2]; + float t = (a*x + b*y + c*z + d) / - (a*a + b*b + c*c); + + return t < 0; + +#if 0 + float t2 = t*t; + float dist = sqrt (t2*a*a + t2*b*b + t2*c*c); + /* Don't lose the sign of t. */ + if (t < 0) return dist; else return -dist; +#endif +} + +/* See: http://www.greuer.de/efaq.html */ +void +point_footprint_on_line (const float *point, + const float *line_point, const float *line_vector, + float *footprint) +{ + float t; + float s[3]; + + vec_subtract (point, line_point, s); + t = vec_dot_product (s, line_vector) / + vec_dot_product (line_vector, line_vector); + + vec_scale (line_vector, t, s); + vec_add (line_point, s, footprint); +} + +float +point_distance_to_line (const float *point, + const float *line_point, const float *line_vector) +{ +#if 0 + float footprint[3]; + + point_footprint_on_line (point, line_point, line_vector, footprint); + return point_distance_to_point (point, footprint); +#else + float u[3], p[3], prod[3], dist; + + /* Normalize vector u along the line. */ + vec_normalize (line_vector, u); + + /* The distance is given by | (p-a) x u | where p is the + * point, a is a point on the line and x is the cross product. + */ + vec_subtract (point, line_point, p); + vec_cross_product (p, u, prod); + dist = vec_magnitude (prod); + + return dist; +#endif +} + +float +point_distance_to_line_segment (const float *point, + const float *line_point0, + const float *line_point1) +{ + float t; + float s[3], v[3]; + + vec_subtract (line_point1, line_point0, v); + vec_subtract (point, line_point0, s); + t = vec_dot_product (s, v) / + vec_dot_product (v, v); + + if (t >= 0 && t <= 1) + { + float footprint[3]; + + vec_scale (v, t, s); + vec_add (line_point0, s, footprint); + return point_distance_to_point (point, footprint); + } + else if (t < 0) + return point_distance_to_point (point, line_point0); + /* else t > 1 */ + return point_distance_to_point (point, line_point1); +} + +int +point_lies_in_face (const float *points, int nr_points, const float *point) +{ + float sum = point_face_angle_sum (points, nr_points, point); + return fabs (sum - 2*M_PI) < 1e-5; +} + +/* See: http://astronomy.swin.edu.au/pbourke/geometry/insidepoly/ */ +float +point_face_angle_sum (const float *points, int nr_points, const float *point) +{ + float sum = 0; + int i, next; + + for (i = 0, next = 1; i < nr_points; ++i, ++next) + { + float p1[3], p2[3], m1, m2, costheta; + + if (next == nr_points) next = 0; + + p1[0] = points[i*3] - point[0]; + p1[1] = points[i*3+1] - point[1]; + p1[2] = points[i*3+2] - point[2]; + p2[0] = points[next*3] - point[0]; + p2[1] = points[next*3+1] - point[1]; + p2[2] = points[next*3+2] - point[2]; + + m1 = vec_magnitude (p1); + m2 = vec_magnitude (p2); + + if (m1 * m2 < 1e-5) + return 2 * M_PI; + else + costheta = (p1[0]*p2[0] + p1[1]*p2[1] + p1[2]*p2[2]) / (m1*m2); + + sum += acos (costheta); + } + + return sum; +} + +float +point_distance_to_face (const float *points, int nr_points, + const float *plane, const float *point, int *edge) +{ + float my_plane_coeffs[4]; + float a, b, c, d, tq, q[3], dist; + int e, i, next; + + /* Calculate plane coefficients, if necessary. */ + if (plane == 0) + { + plane = my_plane_coeffs; + plane_coefficients (&points[0], &points[3], &points[6], (float *) plane); + } + + a = plane[0]; + b = plane[1]; + c = plane[2]; + d = plane[3]; + + /* q is the coordinate of the point of intersection of a + * normal line from the point to the plane. It may or may + * not be on the bounded face (we'll work that out in the + * moment). tq is the parameter of point q. + */ + tq = - (a*point[0] + b*point[1] + c*point[2] + d) / (a*a + b*b + c*c); + q[0] = point[0] + tq*a; + q[1] = point[1] + tq*b; + q[2] = point[2] + tq*c; + + /* Is q on the bounded face? */ + if (point_lies_in_face (points, nr_points, q)) + { + /* Compute the distance from the point to the plane. */ + float t2 = tq*tq; + + dist = sqrt (t2*a*a + t2*b*b + t2*c*c); + + if (edge) *edge = -1; + + return tq < 0 ? dist : -dist; + } + + /* Find the closest edge. */ + e = -1; + dist = 0; + + for (i = 0, next = 1; i < nr_points; ++i, ++next) + { + float d; + + if (next == nr_points) next = 0; + + d = point_distance_to_line_segment (point, + &points[i*3], &points[next*3]); + + if (e == -1 || d < dist) + { + dist = d; + e = i; + } + } + + if (edge) *edge = e; + + return tq < 0 ? dist : -dist; +} + +/* Compute the four coefficients of a plane which + * uniquely specify that plane, given three points + * (not colinear) on the plane. Most of the variables + * in this function are redundant (optimized out?), + * but they get it into the same form as in + * Lansdown, p. 178. + */ +void +plane_coefficients (const float *p, const float *q, const float *r, + float *co) +{ + float x2 = p[0]; + float y2 = p[1]; + float z2 = p[2]; + float x1 = q[0]; + float y1 = q[1]; + float z1 = q[2]; + float x3 = r[0]; + float y3 = r[1]; + float z3 = r[2]; + float xa = x1 + x2; + float xb = x2 + x3; + float xc = x3 + x1; + float ya = y1 + y2; + float yb = y2 + y3; + float yc = y3 + y1; + float za = z1 + z2; + float zb = z2 + z3; + float zc = z3 + z1; + + co[0] = (y1-y2) * za + (y2-y3) * zb + (y3-y1) * zc; + co[1] = (z1-z2) * xa + (z2-z3) * xb + (z3-z1) * xc; + co[2] = (x1-x2) * ya + (x2-x3) * yb + (x3-x1) * yc; + co[3] = - (co[0]*x1 + co[1]*y1 + co[2]*z1); +} + +void +plane_translate_along_normal (const float *plane, float distance, + float *new_plane) +{ + float w = vec_magnitude (plane); + + new_plane[0] = plane[0]; + new_plane[1] = plane[1]; + new_plane[2] = plane[2]; + new_plane[3] = plane[3] - w * distance; +} + +void +face_translate_along_normal (const float *points, int nr_points, + const float *plane, float distance, + float *new_points, float *new_plane) +{ + float w = vec_magnitude (plane), nv[3]; + int i; + + new_plane[0] = plane[0]; + new_plane[1] = plane[1]; + new_plane[2] = plane[2]; + new_plane[3] = plane[3] - w * distance; + + vec_scale (plane, distance / w, nv); + for (i = 0; i < nr_points; ++i) + { + new_points[i*3] = points[i*3] + nv[0]; + new_points[i*3+1] = points[i*3+1] + nv[1]; + new_points[i*3+2] = points[i*3+2] + nv[2]; + } +} + +/* All these quaternion functions are modified from the matrix FAQ again. */ +void +quaternion_normalize (const float *a, float *r) +{ + float w = vec_magnitude (a); + r[0] = a[0] / w; + r[1] = a[1] / w; + r[2] = a[2] / w; + r[3] = a[3] / w; +} + +void +quaternion_conjugate (const float *a, float *r) +{ + r[0] = -a[0]; + r[1] = -a[1]; + r[2] = -a[2]; + r[3] = a[3]; +} + +float +quaternion_magnitude (const float *a) +{ + return sqrt (a[3]*a[3] + a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); +} + +void +quaternion_multiply (const float *a, const float *b, float *r) +{ + float va[3], vb[3], vc[3]; + + r[3] = vec_dot_product (a, b); + + vec_cross_product (a, b, va); + vec_scale (a, b[3], vb); + vec_scale (b, a[3], vc); + vec_add (va, vb, va); + vec_add (va, vc, r); + + quaternion_normalize (r, r); +} + +void +quaternion_to_rotation_matrix (const float *q, float *mat) +{ + float X = q[0]; + float Y = q[1]; + float Z = q[2]; + float W = q[3]; + + float xx = X * X; + float xy = X * Y; + float xz = X * Z; + float xw = X * W; + + float yy = Y * Y; + float yz = Y * Z; + float yw = Y * W; + + float zz = Z * Z; + float zw = Z * W; + + mat[0] = 1 - 2 * ( yy + zz ); + mat[4] = 2 * ( xy - zw ); + mat[8] = 2 * ( xz + yw ); + + mat[1] = 2 * ( xy + zw ); + mat[5] = 1 - 2 * ( xx + zz ); + mat[9] = 2 * ( yz - xw ); + + mat[2] = 2 * ( xz - yw ); + mat[6] = 2 * ( yz + xw ); + mat[10] = 1 - 2 * ( xx + yy ); + + mat[3] = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0; + mat[15] = 1; +} + +void +make_quaternion_from_axis_angle (const float *axis, float angle, + float *q) +{ + double sin_a = sin (angle / 2); + double cos_a = cos (angle / 2); + + q[0] = axis[0] * sin_a; + q[1] = axis[1] * sin_a; + q[2] = axis[2] * sin_a; + q[3] = cos_a; + + quaternion_normalize (q, q); +} + +int +collision_moving_sphere_and_face (const float *p0, const float *p1, + float radius, + const float *points, int nr_points, + const float *plane, + float *collision_point) +{ + float my_plane_coeffs[4], raised_plane[4], t, v[3], quot; + float raised_points[3 * nr_points]; + + /* Get the plane coefficients. */ + if (plane == 0) + { + plane = my_plane_coeffs; + plane_coefficients (&points[0], &points[3], &points[6], (float *) plane); + } + + /* Raise the plane up by the distance of one radius. Then we can + * just test for the intersection of the ray and the face.This is + * something of an approximation, but hopefully will give us good + * results in practice. If not, then we may need to rework this + * code. (XXX) + */ + face_translate_along_normal (points, nr_points, plane, radius, + raised_points, raised_plane); + + /* Get the intersection point of the ray and the plane, as a + * parameter, t. + */ + vec_subtract (p1, p0, v); + quot = raised_plane[0]*v[0] + raised_plane[1]*v[1] + raised_plane[2]*v[2]; + if (fabs (quot) +#if 0 + < 1e-5 +#else + == 0 +#endif + ) + { + /* The path of the sphere is nearly parallel to the plane. Don't + * count this as a collision at all. + */ + return 0; + } + + t = - (raised_plane[0]*p0[0] + raised_plane[1]*p0[1] + raised_plane[2]*p0[2] + + raised_plane[3]) / quot; + if (t < 0 || t > 1) + { + /* There is no collision. */ + return 0; + } + + /* Calculate the actual point of collision. NOTE: This is the centre + * of the sphere, NOT the point where the sphere and plane touch. + */ + vec_scale (v, t, v); + vec_add (p0, v, collision_point); + + /* Is the collision point actually within the bounded convex polygon + * which defines the face? If not, then no collision actually + * occurred. Note that we have to translate (ie. raise) the points + * list too. + */ + return point_lies_in_face (raised_points, nr_points, collision_point); +} diff --git a/matvec.h b/matvec.h new file mode 100644 index 0000000..240317b --- /dev/null +++ b/matvec.h @@ -0,0 +1,392 @@ +/* Matrix and vector arithmetic. + * By Richard W.M. Jones + * + * 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. + * + * $Id: matvec.h,v 1.3 2001/11/19 17:10:54 rich Exp $ + */ + +#ifndef MATVEC_H +#define MATVEC_H + +#include +#include + +/* Notes: + * + * This library only handles 4x4 matrices and 4-vectors, for + * basic 3D graphics use. A matrix is just an array float[16] + * and a vector is just an array float[4]. You can either allocate + * these in a pool using ``new_matrix'' and ``new_vec'', or + * else you can allocate them statically. + * + * All matrices are stored in COLUMN-MAJOR ORDER! This is for + * compatibility with OpenGL, but it is the OPPOSITE of the + * normal C row-major ordering, so beware. Matrix elements in + * column-major order are as follows: + * + * M = | m0 m4 m8 m12 | + * | m1 m5 m9 m13 | + * | m2 m6 m10 m14 | + * | m3 m7 m11 m15 | + * + * Some of these functions have been inlined. I only inline + * functions based on evidence from profiling the code as a + * whole or where the function is so simple that the overhead + * of calling it is larger than the inlined code. Excessive + * inlining can itself cause performance problems, particularly + * on modern processors which are very good at making jumps + * and function calls. + * + */ + +/* Function: new_matrix - allocate a new matrix or vector + * Function: new_vec + * + * @code{new_matrix} allocates a new 4x4 matrix of floats + * in @code{pool}. + * + * @code{new_vec} allocates a new 4-vector of floats in + * @code{pool}. + * + * You may use these functions to allocate matrices and + * vectors dynamically, or you may allocate them statically. + * The other matrix and vector functions available do not + * distriguish between dynamically and statically allocated + * variables. + * + * Note: All matrices are stored in COLUMN-MAJOR ORDER! + * This is for compatibility with OpenGL, but it is the + * OPPOSITE of the natural C row-major ordering, so beware. + * + * See also: @ref{new_identity_matrix(3)}, @ref{new_zero_vec(3)}. + */ +#define new_matrix(pool) ((float *) pmalloc ((pool), sizeof (float) * 16)) +#define new_vec(pool) ((float *) pmalloc ((pool), sizeof (float) * 4)) + +/* Variable: identity_matrix - identity matrix and zero vector + * Variable: zero_vec + * Function: new_identity_matrix + * Function: new_zero_vec + * Function: make_identity_matrix + * Function: make_zero_vec + * + * The @code{identity_matrix} variable contains a read-only + * copy of the identity matrix. The @code{zero_vec} variable + * contains a read-only copy of the zero vector. + * + * Use @code{new_identity_matrix} to allocate a new + * identity matrix variable in @code{pool}. Use @code{new_zero_vec} + * to similarly allocate a new zero vector. + * + * Use @code{make_identity_matrix} to copy the identity + * matrix over an existing matrix @code{m}. Use @code{make_zero_vec} + * to similarly copy the zero vector over an existing vector @code{v}. + * + * See also: @ref{new_matrix(3)}, @ref{new_vec(3)}. + */ +extern float identity_matrix[16]; +extern float zero_vec[4]; +extern float *new_identity_matrix (pool); +extern float *new_zero_vec (pool); +#define make_identity_matrix(m) memcpy (m, identity_matrix, sizeof(float)*16); +#define make_zero_vec(v) memcpy (v, zero_vec, sizeof (float) * 4); + +extern void make_rotation_matrix (float angle, + float x, float y, float z, + float *m); + +extern void make_translation_matrix (float x, float y, float z, float *m); + +extern void make_scaling_matrix (float x, float y, float z, float *m); + +extern void matrix_euler_to_rotation (float angle_x, float angle_y, + float angle_z, + float *mat); +extern void matrix_rotation_to_euler (const float *mat, + float *angle_x, float *angle_y, + float *angle_z); + +extern void matrix_multiply (const float *a, const float *b, + float *product); + +extern void matrix_vec_multiply (const float *m, const float *v, + float *result); + +/* Function: vec_magnitude - calculate magnitude (length) of a vector + * Function: vec_magnitude2d + * + * @code{vec_magnitude} calculates the magnitude (length) of a + * 3D vector. @code{vec_magnitude2d} calculates the magnitude + * of a 2D vector. + * + * See also: @ref{vec_normalize(3)}, @ref{vec_normalize2d(3)}. + */ +extern float vec_magnitude (const float *v); +extern float vec_magnitude2d (const float *v); + +/* Function: vec_normalize - normalize a vector + * Function: vec_normalize2d + * + * These two functions normalize respectively a 3D or 2D + * vector @code{v}. The original vector @code{v} is not touched, + * and the result is placed in vector @code{r}. + * + * To normalize a vector in-place (ie. modifying the original + * vector), do: + * + * @code{vec_normalize (v, v);} + * + * See also: @ref{vec_magnitude(3)}, @ref{vec_magnitude2d(3)}. + */ +extern void vec_normalize (const float *v, float *r); +extern void vec_normalize2d (const float *v, float *r); + +extern void vec_unit_normal_to_side (float *side, float *normal); + +/* Function: vec_dot_product - calculate the dot product of two vectors + * + * @code{vec_dot_product} calculates the dot product of two + * vectors @code{v1} and @code{v2} and returns it. The dot + * product is formally defined as: + * + * @code{|v1| |v2| cos theta} + * + * where @code{theta} is the angle between the two vectors. + * + * One interesting consequence of this is that if both @code{v1} + * and @code{v2} are already normalized, then the dot product + * is 1 if the vectors are parallel and running in the same + * direction, and 0 if the vectors are + * perpendicular. + * + * See also: @ref{vec_magnitude_in_direction(3)}, @ref{vec_angle_between(3)} + */ +extern float vec_dot_product (const float *v1, const float *v2); + +/* Function: vec_magnitude_in_direction - calculate relative direction of two vectors + * + * If @code{v1} and @code{v2} are parallel and point in the + * same direction, then @code{vec_magnitude_in_direction} returns +1. + * If @code{v1} and @code{v2} are perpendicular, this returns + * 0. If @code{v1} and @code{v2} are parallel and point in + * opposite directions to each other, this returns -1. + * For other vectors, this function returns the cosine of + * the angle between the vectors. + * + * See also: @ref{vec_dot_product(3)}, @ref{vec_angle_between(3)} + */ +extern float vec_magnitude_in_direction (const float *v1, const float *v2); + +/* Function: vec_angle_between - calculate the angle between two vectors + * + * This function returns the angle between two vectors + * @code{v1} and @code{v2}. + * + * See also: @ref{vec_dot_product(3)}, @ref{vec_magnitude_in_direction(3)} + */ +extern float vec_angle_between (const float *v1, const float *v2); + +extern void vec_cross_product (const float *v, const float *w, float *r); + +extern void vec_scale (const float *a, float n, float *r); +extern void vec_add (const float *a, const float *b, float *r); +extern void vec_subtract (const float *a, const float *b, float *r); + +float point_distance_to_point (const float *p1, const float *p2); + +extern void point_midpoint (const float *p1, const float *p2, float *mp); +extern void point_midpoint2d (const float *p1, const float *p2, float *mp); +extern float point_distance (const float *p, const float *q); + +/* Function: point_distance_to_plane - distance from point to plane + * Function: point_is_inside_plane + * + * @code{point_distance_to_plane} calculates the (shortest) distance from + * the point @code{point} to the plane @code{plane}. This distance is + * positive if the point is "inside" the plane -- that is, if the + * normal vector drawn from the plane points towards the point. It + * is negative if the point is "outside" the plane. It is zero if the + * point lies on the plane. + * + * @code{point_is_inside_plane} returns true if the point is strictly + * inside the plane, and false if the point lies on the plane or is + * outside. It is much faster to compute this than to use + * @code{point_distance_to_plane} and take the sign of the result. + * + * See also: @ref{plane_coefficients(3)}, @ref{point_distance_to_face(3)}. + */ +extern float point_distance_to_plane (const float *plane, const float *point); +extern int point_is_inside_plane (const float *plane, const float *point); + +extern void point_footprint_on_line (const float *point, const float *line_point, const float *line_vector, float *footprint); + +/* Function: point_distance_to_line - shortest distance from a point to a line + * + * Given a @code{point} and a line, expressed as @code{line_point} + * and parallel @code{line_vector}, compute the shortest distance + * from the point to the line. + * + * See also: @ref{point_distance_to_plane(3)}, @ref{point_distance_to_face(3)}, + * @ref{point_distance_to_line_segment(3)}. + */ +extern float point_distance_to_line (const float *point, const float *line_point, const float *line_vector); + +/* Function: point_distance_to_line_segment - shortest distance from a point to a line segment + * + * Given a @code{point} and a line segment from @code{line_point0} to + * @code{line_point1}, compute the shortest distance from the + * point to the line segment. + * + * See also: @ref{point_distance_to_line(3)}. + */ +extern float point_distance_to_line_segment (const float *point, const float *line_point0, const float *line_point1); + +/* Function: point_lies_in_face - does a point lie on the interior of a bounded convex polygon + * Function: point_face_angle_sum + * + * Take a bounded convex polygon (a "face") and a point. The function + * @code{point_lies_in_face} returns true iff the point is both + * (a) coplanar with the face, and + * (b) lies inside the edges of the face. + * + * In order to do this, @code{point_lies_in_face} calls + * @code{point_face_angle_sum} which works out the sum of + * the interior angles. If conditions (a) and (b) are both + * satisfied then the sum of the interior angles will be + * very close to 2.PI. + * + * The face is expressed as a flat list of points (3-vectors). + * + * See also: @ref{plane_coefficients(3)}, @ref{point_distance_to_face(3)}. + */ +extern int point_lies_in_face (const float *points, int nr_points, const float *point); +extern float point_face_angle_sum (const float *points, int nr_points, const float *point); + +/* Function: point_distance_to_face - distance from point to bounded convex polygon (face) + * + * Given a point and a bounded convex polygon (a "face"), the + * function @code{point_distance_to_face} calculates the distance + * from the point to the face. There are two importance cases to + * consider here: + * + * (a) The point is directly above or below the face. In other words, + * a line dropped from the point perpendicular to the face intersects + * the face within the boundary of the polygon. In this case, the + * function returns the shortest distance from the point to the + * intersection (and is essentially equivalent to + * @code{point_distance_to_plane}). + * + * (b) The point is not directly above or below the face. In this case + * the function works out the distance to the nearest edge of the face. + * + * The face is specified as a list of points and a plane (ie. + * plane coefficients). If @code{plane} is @code{NULL}, then the + * function calls @ref{plane_coefficients(3)} on your behalf. If + * the face is fixed, and you will call this function lots of + * times, then it is a good idea to calculate the plane coefficients + * once only and cache them. + * + * Returns: The distance of the point from the face. The distance + * will be positive if the point is above the face (ie. inside + * the plane: see @ref{point_distance_to_plane(3)}), or negative + * otherwise. + * + * If @code{edge} is not @code{NULL}, then it is set to one of + * the following values: + * + * @code{*edge == -1} if the point is directly above or below + * the face, corresponding to case (a) above. + * + * @code{*edge == 0 .. nr_points-1} if the point is closest to + * that particular edge, corresponding to case (b) above. + * + * See also: @ref{point_distance_to_plane(3)}, + * @ref{plane_coefficients(3)}, @ref{point_lies_in_face(3)}, + * @ref{point_distance_to_line(3)}. + */ +extern float point_distance_to_face (const float *points, int nr_points, const float *plane, const float *point, int *edge); + +/* Function: plane_coefficients - calculate the coefficient form for a plane + * + * Given three points, not colinear, which naturally form a plane, calculate + * the 4-vector form for the plane coefficients. The three points + * are passed as @code{p}, @code{q} and @code{r}. The coefficients + * are returned in vector @code{co}. + * + * The four coefficients returned are respectively @code{a}, @code{b}, + * @code{c} and @code{d} in the standard plane equation: + * + * @code{a x + b y + c z + d = 0} + * + * (Note that many texts use @code{- d}, so be warned). + * + * The normal (perpendicular) vector to the plane may be derived + * immediately: it is just @code{(a, b, c)}. Note that the normal + * vector is not normalized! + * + * Planes are unbounded: they stretch off to infinity in all directions. + * If what you really want are bounded convex polygons, then you + * need to use a c2lib "face". + */ +extern void plane_coefficients (const float *p, const float *q, const float *r, float *co); + +/* Function: plane_translate_along_normal - translate a plane or face some distance in the direction of the normal + * Function: face_translate_along_normal + * + * Given an existing @code{plane} (expressed as plane coefficients), + * produce a new plane @code{new_plane} which has been translated + * by @code{distance} units along the direction of the normal. The + * new plane is also returned as plane coefficients. + * + * @code{face_translate_along_normal} is similar, except that it also + * translates a list of points by the same distance. + * + * See also: @ref{plane_coefficients(3)}. + */ +extern void plane_translate_along_normal (const float *plane, float distance, float *new_plane); +extern void face_translate_along_normal (const float *points, int nr_points, const float *plane, float distance, float *new_points, float *new_plane); + +extern void quaternion_normalize (const float *a, float *r); +extern void quaternion_conjugate (const float *a, float *r); +extern float quaternion_magnitude (const float *a); +extern void quaternion_multiply (const float *a, const float *b, float *r); +extern void quaternion_to_rotation_matrix (const float *q, float *mat); +extern void make_quaternion_from_axis_angle (const float *axis, float angle, + float *q); + +/* Function: collision_moving_sphere_and_face - detect collision between a moving sphere and a fixed face + * + * This function detects collisions between a sphere which is moving + * at constant speed along a linear path and a fixed bounded + * convex polygon ("face"). + * + * The centre of the sphere moves from point @code{p0} to point @code{p1}. + * The sphere has radius @code{radius}. + * + * The face is described by the list of bounding points, and the plane + * coefficients of the plane of the face (you may pass @code{plane} + * as @code{NULL} in which case the function works out the plane + * coefficients for you, although this is generally less efficient). + * + * Returns: If there was a collision, this function returns true and + * sets the collision point in @code{collision_point}. Note that the + * collision point is the position of the centre of the sphere at + * the point of collision, NOT the place where the sphere touches + * the face. If there was no collision, this function returns false. + */ +extern int collision_moving_sphere_and_face (const float *p0, const float *p1, float radius, const float *points, int nr_points, const float *plane, float *collision_point); + +#endif /* MATVEC_H */ diff --git a/pool.c b/pool.c new file mode 100644 index 0000000..2155c62 --- /dev/null +++ b/pool.c @@ -0,0 +1,488 @@ +/* An Apache-like pool allocator. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pool.c,v 1.8 2002/10/13 12:25:42 rich Exp $ + */ + +#include "config.h" + +#if SIZEOF_VOID_P != SIZEOF_LONG +#error "This library currently assumes that sizeof (void *) == sizeof (long), which is not the case on your platform. This may cause the library to crash at runtime." +#endif + +/* If set, then calls to pmalloc will initialise the memory to 0xefefef..., + * helping to catch uninitialised memory problems. This is very useful for + * debugging new code, but should be turned off on production systems. + */ +#define DEBUG_UNINITIALISED_MEMORY 1 + +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include + +struct _pool_allocs +{ + struct _pool_allocs *next; + + /* The flags field contains: + * bit 31 == if set, this structure shouldn't be freed + * bits 30-16 == number of slots in the structure + * bits 15- 0 == number of slots used in the structure. + */ + unsigned flags; + +#define _PA_NO_FREE(pa) ((pa)->flags & 0x80000000U) +#define _PA_SLOTS(pa) (((pa)->flags & 0x7fff0000U) >> 16) +#define _PA_SLOTS_USED(pa) ((pa)->flags & 0xffffU) + + void *slot[0]; +} __attribute__((packed)); + +struct _pool_cleanup_slot +{ + void (*fn) (void *); + void *data; +}; + +struct _pool_cleanups +{ + struct _pool_cleanups *next; + + /* The flags field contains: + * bit 31 == if set, this structure shouldn't be freed + * bits 30-16 == number of slots in the structure + * bits 15- 0 == number of slots used in the structure. + */ + unsigned flags; + +#define _PC_NO_FREE(pc) ((pc)->flags & 0x80000000U) +#define _PC_SLOTS(pc) (((pc)->flags & 0x7fff0000U) >> 16) +#define _PC_SLOTS_USED(pc) ((pc)->flags & 0xffffU) + + struct _pool_cleanup_slot slot[0]; +} __attribute__((packed)); + +#define INITIAL_PA_SLOTS 16U +#define MAX_PA_SLOTS 16384U /* Must be <= 16384 */ +#define INITIAL_PC_SLOTS 2U +#define MAX_PC_SLOTS 16384U /* Must be <= 16384 */ + +struct pool +{ + /* If this is a subpool, then this points to the parent. */ + struct pool *parent_pool; + + /* When subpools are stored on a list, this is used to link the list. */ + struct pool *next; + + /* Sub-pools. */ + struct pool *subpool_list; + + /* Pointer to head block of memory allocations. */ + struct _pool_allocs *allocs; + + /* Pointer to head block of clean-up functions. */ + struct _pool_cleanups *cleanups; +}; + +#ifndef NO_GLOBAL_POOL +pool global_pool; +#endif + +static int trace_fd = -1; +static const char *trace_filename = 0; + +static void (*bad_malloc_handler) (void) = abort; +#ifndef NO_GLOBAL_POOL +static void alloc_global_pool (void) __attribute__((constructor)); +static void free_global_pool (void) __attribute__((destructor)); +#endif +static void open_trace_file (void) __attribute__((constructor)); +static void trace (const char *fn, void *caller, struct pool *ptr1, void *ptr2, void *ptr3, int i1); + +#define TRACE(ptr1, ptr2, ptr3, i1) do { if (trace_filename) trace (__PRETTY_FUNCTION__, __builtin_return_address (0), (ptr1), (ptr2), (ptr3), (i1)); } while (0) + +pool +new_pool () +{ + /* The amount of space required for pool + allocs + cleanups. */ + const int size + = sizeof (struct pool) + + sizeof (struct _pool_allocs) + + INITIAL_PA_SLOTS * sizeof (void *) + + sizeof (struct _pool_cleanups) + + INITIAL_PC_SLOTS * sizeof (struct _pool_cleanup_slot); + + pool p = malloc (size); + if (p == 0) bad_malloc_handler (); + + memset (p, 0, size); + + p->allocs = (struct _pool_allocs *) ((void *)p + sizeof (struct pool)); + p->cleanups = (struct _pool_cleanups *) + ((void *)p + sizeof (struct pool) + sizeof (struct _pool_allocs) + + INITIAL_PA_SLOTS * sizeof (void *)); + + p->allocs->flags = 0x80000000U | INITIAL_PA_SLOTS << 16; + p->cleanups->flags = 0x80000000U | INITIAL_PC_SLOTS << 16; + + TRACE (p, 0, 0, 0); + + return p; +} + +pool +new_subpool (pool parent) +{ + pool p = new_pool (); + p->parent_pool = parent; + + p->next = parent->subpool_list; + parent->subpool_list = p; + + TRACE (p, parent, 0, 0); + + return p; +} + +static inline void +_do_cleanups (pool p) +{ + struct _pool_cleanups *pc, *pc_next; + int i; + + for (pc = p->cleanups; pc; pc = pc_next) + { + pc_next = pc->next; + + for (i = 0; i < _PC_SLOTS_USED (pc); ++i) + pc->slot[i].fn (pc->slot[i].data); + if (!_PC_NO_FREE (pc)) + free (pc); + } +} + +static inline void +_do_frees (pool p) +{ + struct _pool_allocs *pa, *pa_next; + int i; + + for (pa = p->allocs; pa; pa = pa_next) + { + pa_next = pa->next; + + for (i = 0; i < _PA_SLOTS_USED (pa); ++i) + free (pa->slot[i]); + if (!_PA_NO_FREE (pa)) + free (pa); + } +} + +void +delete_pool (pool p) +{ + _do_cleanups (p); + + /* Clean up any sub-pools. */ + while (p->subpool_list) delete_pool (p->subpool_list); + + _do_frees (p); + + /* Do I have a parent? If so, remove myself from my parent's subpool + * list. + */ + if (p->parent_pool) + { + pool parent = p->parent_pool, this, last = 0; + + for (this = parent->subpool_list; this; last = this, this = this->next) + { + if (this == p) + { + /* Remove this one. */ + if (last != 0) + last->next = this->next; + else + parent->subpool_list = this->next; + + goto found_me; + } + } + + abort (); /* Oops - self not found on subpool list. */ + found_me:; + } + + free (p); + + TRACE (p, 0, 0, 0); +} + +void * +pmalloc (pool p, size_t n) +{ + void *ptr; + + ptr = malloc (n); + if (ptr == 0) bad_malloc_handler (); + +#if DEBUG_UNINITIALISED_MEMORY + memset (ptr, 0xef, n); +#endif + + pool_register_malloc (p, ptr); + + TRACE (p, ptr, 0, n); + + return ptr; +} + +void * +pcalloc (pool p, size_t nmemb, size_t size) +{ + void *ptr = pmalloc (p, nmemb * size); + if (ptr) memset (ptr, 0, nmemb * size); + return ptr; +} + +void * +prealloc (pool p, void *ptr, size_t n) +{ + struct _pool_allocs *pa; + int i; + void *new_ptr; + + if (ptr == 0) + return pmalloc (p, n); + + new_ptr = realloc (ptr, n); + if (new_ptr == 0) bad_malloc_handler (); + + /* XXX This is inefficient. We need to search through the + * allocations to find this one and update the pointer. + */ + if (ptr != new_ptr) + { + for (pa = p->allocs; pa; pa = pa->next) + { + for (i = 0; i < _PA_SLOTS_USED (pa); ++i) + if (pa->slot[i] == ptr) + { + pa->slot[i] = new_ptr; + goto found; + } + } + abort (); + + found:; + } + + TRACE (p, ptr, new_ptr, n); + + return new_ptr; +} + +void +pool_register_cleanup_fn (pool p, void (*fn) (void *), void *data) +{ + unsigned nr_slots; + struct _pool_cleanups *pc; + + if (_PC_SLOTS_USED (p->cleanups) < _PC_SLOTS (p->cleanups)) + { + again: + p->cleanups->slot[_PC_SLOTS_USED(p->cleanups)].fn = fn; + p->cleanups->slot[_PC_SLOTS_USED(p->cleanups)].data = data; + p->cleanups->flags++; + return; + } + + /* Allocate a new block of cleanup slots. */ + nr_slots = _PC_SLOTS (p->cleanups); + if (nr_slots < MAX_PC_SLOTS) + nr_slots *= 2; + + pc = malloc (sizeof (struct _pool_cleanups) + + nr_slots * sizeof (struct _pool_cleanup_slot)); + if (pc == 0) bad_malloc_handler (); + pc->next = p->cleanups; + pc->flags = nr_slots << 16; + p->cleanups = pc; + + goto again; +} + +void +pool_register_malloc (pool p, void *ptr) +{ + unsigned nr_slots; + struct _pool_allocs *pa; + + if (_PA_SLOTS_USED (p->allocs) < _PA_SLOTS (p->allocs)) + { + again: + p->allocs->slot[_PA_SLOTS_USED(p->allocs)] = ptr; + p->allocs->flags++; + return; + } + + /* Allocate a new block of slots. */ + nr_slots = _PA_SLOTS (p->allocs); + if (nr_slots < MAX_PA_SLOTS) + nr_slots *= 2; + + pa = malloc (sizeof (struct _pool_allocs) + nr_slots * sizeof (void *)); + if (pa == 0) bad_malloc_handler (); + pa->next = p->allocs; + pa->flags = nr_slots << 16; + p->allocs = pa; + + goto again; +} + +static void +_pool_close (void *fdv) +{ + long fd = (long) fdv; + close (fd); +} + +void +pool_register_fd (pool p, int fd) +{ + pool_register_cleanup_fn (p, _pool_close, (void *) (long) fd); +} + +#ifndef NO_GLOBAL_POOL +static void +alloc_global_pool () +{ + global_pool = new_pool (); +} + +static void +free_global_pool () +{ + delete_pool (global_pool); +} +#endif /* !NO_GLOBAL_POOL */ + +void (* +pool_set_bad_malloc_handler (void (*fn) (void))) (void) +{ + void (*old_fn) (void) = bad_malloc_handler; + bad_malloc_handler = fn; + return old_fn; +} + +static int +_get_struct_size (const pool p) +{ + pool subpool; + struct _pool_allocs *pa; + struct _pool_cleanups *pc; + int size; + + size = sizeof (*p); + + for (pa = p->allocs; pa; pa = pa->next) + size += sizeof (struct _pool_allocs) + + _PA_SLOTS (pa) * sizeof (void *); + + for (pc = p->cleanups; pc; pc = pc->next) + size += sizeof (struct _pool_cleanups) + + _PC_SLOTS (pc) * sizeof (struct _pool_cleanup_slot); + + for (subpool = p->subpool_list; subpool; subpool = subpool->next) + size += _get_struct_size (subpool); + + return size; +} + +static int +_get_nr_subpools (const pool p) +{ + pool subpool; + int count = 1; + + for (subpool = p->subpool_list; subpool; subpool = subpool->next) + count += _get_nr_subpools (subpool); + + return count; +} + +void +pool_get_stats (const pool p, struct pool_stats *stats, size_t n) +{ + struct pool_stats s; + + s.nr_subpools = _get_nr_subpools (p); + s.struct_size = _get_struct_size (p); + + memcpy (stats, &s, n); +} + +static void +open_trace_file () +{ + char msg1[] = + "\n" + "Pool allocator running in trace mode.\n" + "Trace is being saved to file "; + char msg2[] = "\n\n"; + + trace_filename = getenv ("POOL_TRACE"); + + if (trace_filename) + { + trace_fd = open (trace_filename, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (trace_fd == -1) + { + perror (trace_filename); + exit (1); + } + + write (2, msg1, sizeof msg1); + write (2, trace_filename, strlen (trace_filename)); + write (2, msg2, sizeof msg2); + } +} + +static void +trace (const char *fn, void *caller, struct pool *ptr1, void *ptr2, void *ptr3, int i1) +{ + char buffer[128]; + + sprintf (buffer, + "%s caller: %p ptr1: %p ptr2: %p ptr3: %p i1: %d\n", + fn, caller, ptr1, ptr2, ptr3, i1); + write (trace_fd, buffer, strlen (buffer)); +} diff --git a/pool.h b/pool.h new file mode 100644 index 0000000..f8ed4c4 --- /dev/null +++ b/pool.h @@ -0,0 +1,158 @@ +/* An Apache-like pool allocator. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pool.h,v 1.7 2002/06/08 11:50:44 rich Exp $ + */ + +#ifndef POOL_H +#define POOL_H + +#include + +struct pool; +typedef struct pool *pool; + +/* Function: new_pool - allocate a new pool + * + * Allocate a new pool. Pools must eventually be deleted explicitly + * by calling @ref{delete_pool(3)}. + * + * Note that @code{new_pool} is now deprecated. It is almost always + * better to create a subpool of the global pool, ie: + * + * @code{pool = new_subpool (global_pool);} + * + * This has the distinct advantage that your new pool will be cleaned + * up properly if the process calls @code{exit}. + * + * See also: @ref{new_subpool(3)}, @ref{global_pool(3)}, + * @ref{delete_pool(3)}. + */ +extern pool new_pool (void); + +/* Function: new_subpool - allocate a subpool of an existing pool + * + * Allocate a new subpool. The pool may either be deleted explicitly, or + * else is deleted implicitly when the parent pool is deleted. + */ +extern pool new_subpool (pool); + +/* Function: delete_pool - delete a pool + * + * Delete a pool or subpool. This also deletes any subpools that the + * pool may own (and recursively subpools of those subpools, etc.) + */ +extern void delete_pool (pool); + +/* Function: pmalloc - allocate memory in a pool + * Function: pcalloc + * Function: prealloc + * + * Allocate memory in a pool or, if pool is null, on the main heap + * (equivalent to plain @code{malloc}). If memory is allocated in a real + * pool, then it is automatically freed when the pool is deleted. + * + * Memory returned is word-aligned. + * + * If a memory allocation fails, the @code{bad_malloc_handler} function is + * called (which defaults to just calling @ref{abort(3)}). + * + * @code{pcalloc} is identical to @code{pmalloc} but also sets the memory + * to zero before returning it. + * + * @code{prealloc} increases the size of an existing memory allocation. + * @code{prealloc} might move the memory in the process of reallocating it. + * + * Bugs: @code{prealloc} cannot reduce the size of an existing memory + * allocation. + */ +extern void *pmalloc (pool, size_t n); +extern void *pcalloc (pool, size_t nmemb, size_t size); +extern void *prealloc (pool, void *ptr, size_t n); + +/* Function: pool_register_malloc - allow pool to own malloc'd memory + * + * Register an anonymous area of malloc-allocated memory which + * will be freed (with @ref{free(3)}) when the pool is deleted. + */ +extern void pool_register_malloc (pool, void *ptr); + +/* Function: pool_register_fd - allow pool to own file descriptor + * + * Register a file descriptor to be closed when the pool is deleted. + * There is no way to unregister a file descriptor. If you wish to + * do that, then you probably want to register the fd in a subpool. + */ +extern void pool_register_fd (pool, int fd); + +/* Function: pool_register_cleanup_fn - call function when pool is deleted + * + * Register a function to be called when the pool is deleted. There + * is no way to unregister this function. If you wish to do that, then + * you probably want to register it in a subpool. + */ +extern void pool_register_cleanup_fn (pool, void (*fn) (void *), void *data); + +/* Function: pool_set_bad_malloc_handler - set handler for when malloc fails + * + * Set the function which is called when an underlying malloc or realloc + * operation fails. The default is that @ref{abort(3)} is called. + * + * This function returns the previous handler. + */ +extern void (*pool_set_bad_malloc_handler (void (*fn) (void))) (void); + +struct pool_stats +{ + int nr_subpools; + int struct_size; +}; + +/* Function: pool_get_stats - get statistics from the pool + * + * Return various statistics collected for the pool. This function + * fills in the @code{stats} argument which should point to a + * structure of type @code{struct pool_stats}. @code{n} should be + * set to the size of this structure. + * + * @code{struct pool_stats} currently contains the following fields: + * + * @code{nr_subpools}: The number of subpools (including the current pool). + * + * @code{struct_size}: The memory overhead used by the pool allocator + * itself to store structures. This includes subpools. + */ +extern void pool_get_stats (const pool, struct pool_stats *stats, size_t n); + +/* Obsolete calls for backwards compatibility. These will be removed soon. */ +#define pool_get_size(p) (-1) +#define pool_get_areas(p) (-1) +#define pool_get_allocations(p) (-1) +#define pool_nr_subpools(p) (-1) + +#ifndef NO_GLOBAL_POOL +/* Variable: global_pool - the global pool for global allocations + * + * This is the global pool which is allocated before @code{main()} is called + * and deleted automatically upon program exit. Items allocated on this + * pool cannot be deleted until the program ends, and so it is a good + * idea not to allocate short-lived items here. + */ +extern pool global_pool; +#endif /* !NO_GLOBAL_POOL */ + +#endif /* POOL_H */ diff --git a/pre.c b/pre.c new file mode 100644 index 0000000..d616552 --- /dev/null +++ b/pre.c @@ -0,0 +1,278 @@ +/* String functions which allocate strings on the pool. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pre.c,v 1.3 2003/01/22 14:29:37 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_ALLOCA_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include +#include +#include +#include + +/* These private functions are used to capture memory allocations made + * by the PCRE library. + */ +static void *malloc_in_pool (size_t); +static void do_nothing (void *); +static pool malloc_pool = 0; + +pcre * +precomp (pool pool, const char *pattern, int options) +{ + const char *errptr; + int erroffset; + pcre *result; + void *(*old_malloc)(size_t); + void (*old_free) (void *); + + /* Allocations to the pool. */ + old_malloc = pcre_malloc; + old_free = pcre_free; + pcre_malloc = malloc_in_pool; + malloc_pool = pool; + pcre_free = do_nothing; + + /* Compile the pattern. */ + result = pcre_compile (pattern, options, &errptr, &erroffset, 0); + if (result == 0) + { + fprintf (stderr, + "pcre: internal error compiling regular expression:\n" + "pcre: %s\n" + "pcre: %s\n" + "pcre: %s^\n", + errptr, + pattern, + pchrs (pool, ' ', erroffset-1)); + exit (1); + } + + /* Restore memory allocation. */ + pcre_malloc = old_malloc; + pcre_free = old_free; + + return result; +} + +vector +prematch (pool pool, const char *str, const pcre *pattern, int options) +{ + int err, n, i, ovecsize; + int *ovector; + vector result; + void *(*old_malloc)(size_t); + void (*old_free) (void *); + + /* Allocations to the pool. */ + old_malloc = pcre_malloc; + old_free = pcre_free; + pcre_malloc = malloc_in_pool; + malloc_pool = pool; + pcre_free = do_nothing; + + /* Get the number of capturing substrings in the pattern (n). */ + if ((err = pcre_fullinfo (pattern, 0, PCRE_INFO_CAPTURECOUNT, &n)) != 0) + abort (); + + /* Allocate a vector large enough to contain the resulting substrings. */ + ovecsize = (n+1) * 3; + ovector = alloca (ovecsize * sizeof (int)); + + /* Do the match. n is the number of strings found. */ + n = pcre_exec (pattern, 0, str, strlen (str), 0, options, ovector, ovecsize); + + /* Restore memory allocation. */ + pcre_malloc = old_malloc; + pcre_free = old_free; + + if (n == PCRE_ERROR_NOMATCH) /* No match, return NULL. */ + return 0; + else if (n <= 0) /* Some other error. */ + abort (); + + /* Some matches. Construct the vector. */ + result = new_vector (pool, char *); + for (i = 0; i < n; ++i) + { + char *s = 0; + int start = ovector[i*2]; + int end = ovector[i*2+1]; + + if (start >= 0) + s = pstrndup (pool, str + start, end - start); + vector_push_back (result, s); + } + + return result; +} + +static int do_match_and_sub (pool pool, const char *str, char **newstrp, + const pcre *pattern, const char *sub, + int startoffset, int options, int cc, + int *ovector, int ovecsize, int placeholders); + +const char * +presubst (pool pool, const char *str, + const pcre *pattern, const char *sub, + int options) +{ + char *newstr = pstrdup (pool, ""); + int cc, err, n, ovecsize; + int *ovector; + void *(*old_malloc)(size_t); + void (*old_free) (void *); + int placeholders = (options & PRESUBST_NO_PLACEHOLDERS) ? 0 : 1; + int global = (options & PRESUBST_GLOBAL) ? 1 : 0; + + options &= ~(PRESUBST_NO_PLACEHOLDERS | PRESUBST_GLOBAL); + + /* Allocations to the pool. */ + old_malloc = pcre_malloc; + old_free = pcre_free; + pcre_malloc = malloc_in_pool; + malloc_pool = pool; + pcre_free = do_nothing; + + /* Get the number of capturing substrings in the pattern. */ + if ((err = pcre_fullinfo (pattern, 0, PCRE_INFO_CAPTURECOUNT, &cc)) != 0) + abort (); + + /* Allocate a vector large enough to contain the resulting substrings. */ + ovecsize = (cc+1) * 3; + ovector = alloca (ovecsize * sizeof (int)); + + /* Find a match and substitute. */ + n = do_match_and_sub (pool, str, &newstr, pattern, sub, 0, options, cc, + ovector, ovecsize, placeholders); + + if (global) + { + /* Do the remaining matches. */ + while (n > 0) + { + n = do_match_and_sub (pool, str, &newstr, pattern, sub, n, + options, cc, + ovector, ovecsize, placeholders); + } + } + else if (n > 0) + { + /* Concatenate the remainder of the string. */ + newstr = pstrcat (pool, newstr, str + n); + } + + /* Restore memory allocation. */ + pcre_malloc = old_malloc; + pcre_free = old_free; + + return newstr; +} + +static int +do_match_and_sub (pool pool, const char *str, char **newstrp, + const pcre *pattern, const char *sub, + int startoffset, int options, int cc, + int *ovector, int ovecsize, int placeholders) +{ + int so, eo, err; + char *newstr = *newstrp; + + /* Find the next match. */ + err = pcre_exec (pattern, 0, str, strlen (str), startoffset, + options, ovector, ovecsize); + if (err == PCRE_ERROR_NOMATCH) /* No match. */ + { + if (startoffset == 0) + /* Special case: we can just return the original string. */ + *newstrp = (char *) str; + else + { + /* Concatenate the end of the string. */ + newstr = pstrcat (pool, newstr, str + startoffset); + *newstrp = newstr; + } + return -1; + } + else if (err != cc+1) /* Some other error. */ + abort (); + + /* Get position of the match. */ + so = ovector[0]; + eo = ovector[1]; + + /* Substitute for the match. */ + newstr = pstrncat (pool, newstr, str + startoffset, so - startoffset); + if (placeholders) + { + int i; + + /* Substitute $1, $2, ... placeholders with captured substrings. */ + for (i = 0; i < strlen (sub); ++i) + { + if (sub[i] == '$' && (sub[i+1] >= '0' && sub[i+1] <= '9')) + { + int n = sub[i+1] - '0'; + + if (n > cc) + newstr = pstrncat (pool, newstr, &sub[i], 2); + else + { + int nso = ovector[n*2]; + int neo = ovector[n*2+1]; + + newstr = pstrncat (pool, newstr, str+nso, neo-nso); + } + + i++; + } + else + newstr = pstrncat (pool, newstr, &sub[i], 1); + } + } + else + newstr = pstrcat (pool, newstr, sub); + + *newstrp = newstr; + return eo; +} + +static void * +malloc_in_pool (size_t n) +{ + return pmalloc (malloc_pool, n); +} + +static void +do_nothing (void *p) +{ + /* Yes, really, do nothing. */ +} diff --git a/pre.h b/pre.h new file mode 100644 index 0000000..00f7913 --- /dev/null +++ b/pre.h @@ -0,0 +1,87 @@ +/* Regular expression functions which allocate in the pool. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pre.h,v 1.1 2002/10/05 16:42:04 rich Exp $ + */ + +#ifndef PRE_H +#define PRE_H + +#include + +#include +#include + +/* Function: precomp - Compile, match, substitute regular expressions. + * Function: prematch + * Function: presubst + * + * These functions are wrappers around the Perl Compatible + * Regular Expressions (PCRE) library (see + * @code{http://www.pcre.org/}). + * + * @code{precomp} compiles the regular expression @code{pattern} + * returning a pointer to the opaque @code{pcre} structure. The + * structure is allocated in @code{pool}. The @code{options} argument + * is a list of PCRE options, passed directly to the + * @code{pcre_compile} function (see @ref{pcre(3)}). You + * should normally set @code{options} to 0. + * + * @code{prematch} matches the string @code{str} with the + * compiled regular expression @code{pattern}. + * + * If there is no match, this returns @code{NULL}. If the string + * matches, then this function returns a @code{vector} of @code{char *}, + * allocated in @code{pool}. The first element of this vector is + * the portion of the original string which matched the whole + * pattern. The second and subsequent elements of this vector are + * captured substrings. It is possible in rare circumstances for some + * of these captured substrings to be @code{NULL} (see the + * @ref{pcre(3)} manual page for an example). + * + * The @code{options} argument is passed directly to + * @code{pcre_exec}. You should normally set @code{options} to 0. + * + * @code{presubst} substitutes @code{sub} for @code{pattern} + * wherever @code{pattern} occurs in @code{str}. It is equivalent + * to the @code{str =~ s/pat/sub/} function in Perl. + * + * Placeholders @code{$1}, @code{$2}, etc. in @code{sub} are + * substituted for the matching substrings of @code{pattern}. + * Placeholder substitution can be disabled completely by + * including the @code{PRESUBST_NO_PLACEHOLDERS} flag in @code{options}. + * + * If the @code{PRESUBST_GLOBAL} flag is given, then all + * matches are substituted. Otherwise only the first match + * is substituted. + * + * The @code{options} argument is passed to @code{pcre_exec} + * (after removing the @code{PRESUBST_*} flags). + * + * The return value from @code{presubst} is the string with + * replacements. + * + * See also: @ref{pcre(3)}. + */ +pcre *precomp (pool pool, const char *pattern, int options); +vector prematch (pool pool, const char *str, const pcre *pattern, int options); +const char *presubst (pool pool, const char *str, const pcre *pattern, const char *sub, int options); + +#define PRESUBST_NO_PLACEHOLDERS 0x10000000 +#define PRESUBST_GLOBAL 0x20000000 + +#endif /* PRE_H */ diff --git a/pstring.c b/pstring.c new file mode 100644 index 0000000..f57f17e --- /dev/null +++ b/pstring.c @@ -0,0 +1,721 @@ +/* String functions which allocate strings on the pool. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pstring.c,v 1.24 2003/01/22 14:29:37 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_ALLOCA_H +#include +#endif + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +/* Duplicate a string. */ +char * +pstrdup (pool pool, const char *str) +{ + int len = strlen (str); + char *ptr = pmalloc (pool, (len+1) * sizeof (char)); + return memcpy (ptr, str, len+1); +} + +/* Duplicate up to the first N characters of a string. */ +char * +pstrndup (pool pool, const char *str, int n) +{ + int len = MIN (strlen (str), n); + char *ptr = pmalloc (pool, (len+1) * sizeof (char)); + memcpy (ptr, str, len); + ptr[len] = '\0'; + return ptr; +} + +/* Duplicate a fixed-size area of memory. */ +void * +pmemdup (pool pool, const void *data, size_t size) +{ + void *ptr = pmalloc (pool, size); + return memcpy (ptr, data, size); +} + +static vector generic_split (pool pool, const char *str, const void *sep, const char *(*find) (const char *str, const void *sep, const char **end_match), int keep); + +static const char * +find_strstr (const char *str, const void *sep, const char **end_match) +{ + const char *csep = (const char *) sep; + const char *t = strstr (str, csep); + if (t) *end_match = t + strlen (csep); + return t; +} + +vector +pstrsplit (pool pool, const char *str, const char *sep) +{ + return generic_split (pool, str, sep, find_strstr, 0); +} + +static const char * +find_strchr (const char *str, const void *sep, const char **end_match) +{ + char c = * (const char *) sep; + const char *t = strchr (str, c); + if (t) *end_match = t+1; + return t; +} + +vector +pstrcsplit (pool pool, const char *str, char c) +{ + return generic_split (pool, str, &c, find_strchr, 0); +} + +static const char * +find_re (const char *str, const void *sep, const char **end_match) +{ + const pcre *re = (const pcre *) sep; +#define ovecsize 3 + int ovector[ovecsize]; + int r = pcre_exec (re, 0, str, strlen (str), 0, 0, ovector, ovecsize); + + if (r >= 0) /* Successful match. */ + { + int so = ovector[0]; + int eo = ovector[1]; + + if (so == -1) abort (); /* Bad pattern. */ + *end_match = str + eo; + return str + so; + } + else if (r == PCRE_ERROR_NOMATCH) + return 0; + else + abort (); /* Some other error reported by PCRE. */ +#undef ovecsize +} + +vector +pstrresplit (pool pool, const char *str, const pcre *re) +{ + return generic_split (pool, str, re, find_re, 0); +} + +vector +pstrsplit2 (pool pool, const char *str, const char *sep) +{ + return generic_split (pool, str, sep, find_strstr, 1); +} + +vector +pstrcsplit2 (pool pool, const char *str, char c) +{ + return generic_split (pool, str, &c, find_strchr, 1); +} + +vector +pstrresplit2 (pool pool, const char *str, const pcre *re) +{ + return generic_split (pool, str, re, find_re, 1); +} + +/* Generic split function. */ +static vector +generic_split (pool pool, const char *str, const void *sep, + const char *(*find) (const char *str, const void *sep, + const char **end_match), + int keep) +{ + const char *start_match, *end_match; + char *s; + vector v; + + /* If the string is zero length, always return a zero length vector. */ + if (strcmp (str, "") == 0) return new_vector (pool, char *); + + /* Find the splitting point. */ + start_match = find (str, sep, &end_match); + + if (start_match != 0) /* Successful match. */ + { + s = start_match > str ? pstrndup (pool, str, start_match - str) : 0; + v = generic_split (pool, end_match, sep, find, keep); + if (keep) /* Keep the matching text. */ + { + const char *match; + + match = pstrndup (pool, start_match, end_match - start_match); + vector_push_front (v, match); + } + if (s) vector_push_front (v, s); + } + else /* Not successful match. */ + { + s = pstrdup (pool, str); + v = new_vector (pool, char *); + vector_push_back (v, s); + } + + return v; +} + +/* Concatenate a vector of strings to form a string. */ +char * +pconcat (pool pool, vector v) +{ + int i; + char *s = pstrdup (pool, ""); + + for (i = 0; i < vector_size (v); ++i) + { + char *t; + + vector_get (v, i, t); + s = pstrcat (pool, s, t); + } + + return s; +} + +/* Join a vector of strings, separating each string by the given string. */ +char * +pjoin (pool pool, vector v, const char *sep) +{ + int i; + char *s = pstrdup (pool, ""); + + for (i = 0; i < vector_size (v); ++i) + { + char *t; + + vector_get (v, i, t); + s = pstrcat (pool, s, t); + if (i < vector_size (v) - 1) s = pstrcat (pool, s, sep); + } + + return s; +} + +char * +pchrs (pool pool, char c, int n) +{ + char *s = pmalloc (pool, sizeof (char) * (n + 1)); + int i; + + for (i = 0; i < n; ++i) + s[i] = c; + s[n] = '\0'; + + return s; +} + +char * +pstrs (pool pool, const char *str, int n) +{ + int len = strlen (str); + char *s = pmalloc (pool, sizeof (char) * (len * n + 1)); + int i, j; + + for (i = j = 0; i < n; ++i, j += len) + memcpy (&s[j], str, len); + + s[len * n] = '\0'; + + return s; +} + +vector +pvector (pool pool, ...) +{ + va_list args; + const char *s; + vector v = new_vector (pool, const char *); + + va_start (args, pool); + while ((s = va_arg (args, const char *)) != 0) + vector_push_back (v, s); + va_end (args); + + return v; +} + +vector +pvectora (pool pool, const char *array[], int n) +{ + int i; + vector v = new_vector (pool, const char *); + + for (i = 0; i < n; ++i) + vector_push_back (v, array[i]); + + return v; +} + +/* Sort a vector of strings. */ +void +psort (vector v, int (*compare_fn) (const char **, const char **)) +{ + vector_sort (v, (int (*) (const void *, const void *)) compare_fn); +} + +/* Remove line endings (either CR, CRLF or LF) from the string. */ +char * +pchomp (char *line) +{ + int len = strlen (line); + + while (line[len-1] == '\n' || line[len-1] == '\r') + line[--len] = '\0'; + + return line; +} + +char * +ptrimfront (char *str) +{ + char *p; + int len; + + for (p = str; *p && isspace ((int) *p); ++p) + ; + + len = strlen (p); + memmove (str, p, len + 1); + + return str; +} + +char * +ptrimback (char *str) +{ + int len; + char *p; + + len = strlen (str); + for (p = str + len - 1; p >= str && isspace ((int) *p); --p) + ; + + p[1] = '\0'; + + return str; +} + +char * +ptrim (char *str) +{ + ptrimback (str); + ptrimfront (str); + return str; +} + +/* This is equivalent to sprintf but it allocates the result string in POOL.*/ +char * +psprintf (pool pool, const char *format, ...) +{ + va_list args; + char *s; + + va_start (args, format); + s = pvsprintf (pool, format, args); + va_end (args); + + return s; +} + +/* Similar to vsprintf. */ +char * +pvsprintf (pool pool, const char *format, va_list args) +{ +#ifdef HAVE_VASPRINTF + + char *s; + + vasprintf (&s, format, args); + if (s == 0) abort (); /* XXX Should call bad_malloc_handler. */ + + /* The pool will clean up the malloc when it goes. */ + pool_register_malloc (pool, s); + + return s; + +#else /* !HAVE_VASPRINTF */ + + int r, n = 256; + char *s = alloca (n), *t; + + /* Note: according to the manual page, a return value of -1 indicates + * that the string was truncated. We have found that this is not + * actually true however. In fact, the library seems to return the + * number of characters which would have been written into the string + * excluding the '\0' (ie. r > n). + */ + r = vsnprintf (s, n, format, args); + + if (r < n) + { + /* Copy the string into a pool-allocated area of the correct size + * and return it. + */ + n = r + 1; + t = pmalloc (pool, n); + memcpy (t, s, n); + + return t; + } + else + { + /* String was truncated. Allocate enough space for the string + * in the pool and repeat the vsnprintf into this buffer. + */ + n = r + 1; + t = pmalloc (pool, n); + + vsnprintf (t, n, format, args); + + return t; + } + +#endif /* !HAVE_VASPRINTF */ +} + +/* Convert various number types to strings. */ +char * +pitoa (pool pool, int n) +{ + char *s = pmalloc (pool, 16); + snprintf (s, 16, "%d", n); + return s; +} + +char * +pdtoa (pool pool, double n) +{ + char *s = pmalloc (pool, 16); + snprintf (s, 16, "%f", n); + return s; +} + +char * +pxtoa (pool pool, unsigned n) +{ + char *s = pmalloc (pool, 16); + snprintf (s, 16, "%x", n); + return s; +} + +/* Promote vector of numbers to vector of strings. */ +vector +pvitostr (pool pool, vector v) +{ + vector nv = new_vector (pool, char *); + int i; + + vector_reallocate (nv, vector_size (v)); + + for (i = 0; i < vector_size (v); ++i) + { + char *s; + int j; + + vector_get (v, i, j); + s = pitoa (pool, j); + vector_push_back (nv, s); + } + + return nv; +} + +vector +pvdtostr (pool pool, vector v) +{ + vector nv = new_vector (pool, char *); + int i; + + vector_reallocate (nv, vector_size (v)); + + for (i = 0; i < vector_size (v); ++i) + { + char *s; + double j; + + vector_get (v, i, j); + s = pdtoa (pool, j); + vector_push_back (nv, s); + } + + return nv; +} + +vector +pvxtostr (pool pool, vector v) +{ + vector nv = new_vector (pool, char *); + int i; + + vector_reallocate (nv, vector_size (v)); + + for (i = 0; i < vector_size (v); ++i) + { + char *s; + unsigned j; + + vector_get (v, i, j); + s = pxtoa (pool, j); + vector_push_back (nv, s); + } + + return nv; +} + +/* STR is a string allocated in POOL. Append ENDING to STR, reallocating + * STR if necessary. + */ +char * +pstrcat (pool pool, char *str, const char *ending) +{ + /* There are probably more efficient ways to implement this ... */ + int slen = strlen (str); + int elen = strlen (ending); + + str = prealloc (pool, str, slen + elen + 1); + strcat (str, ending); + return str; +} + +char * +pstrncat (pool pool, char *str, const char *ending, size_t n) +{ + int slen = strlen (str); + int elen = strlen (ending); + + elen = elen > n ? n : elen; + + str = prealloc (pool, str, slen + elen + 1); + strncat (str, ending, n); + return str; +} + +/* Return the substring starting at OFFSET and of length LEN of STR, allocated + * as a new string. If LEN is negative, everything up to the end of STR + * is returned. + */ +char * +psubstr (pool pool, const char *str, int offset, int len) +{ + char *new_str; + + if (len >= 0) + { + new_str = pmalloc (pool, len + 1); + memcpy (new_str, str + offset, len); + new_str[len] = '\0'; + return new_str; + } + else + { + len = strlen (str + offset); + new_str = pmalloc (pool, len + 1); + memcpy (new_str, str + offset, len); + new_str[len] = '\0'; + return new_str; + } +} + +char * +pstrupr (char *str) +{ + char *s = str; + while (*s) { *s = toupper (*s); s++; } + return str; +} + +char * +pstrlwr (char *str) +{ + char *s = str; + while (*s) { *s = tolower (*s); s++; } + return str; +} + +/* NB. The following figures were derived by examining a large number + * of configuration files in /etc/ on a Red Hat Linux box. + */ +#define _PGETL_INITIAL_BUFFER 96 +#define _PGETL_INCR_BUFFER 32 + +char * +pgetline (pool pool, FILE *fp, char *line) +{ + int allocated = _PGETL_INITIAL_BUFFER; + int len = 0; + int c; + + /* Reallocate the buffer. */ + line = prealloc (pool, line, _PGETL_INITIAL_BUFFER); + + /* Read in the line until we reach EOF or a '\n' character. */ + while ((c = getc (fp)) != EOF && c != '\n') + { + if (len == allocated) + line = prealloc (pool, line, allocated += _PGETL_INCR_BUFFER); + line[len++] = c; + } + + /* EOF and no content? */ + if (c == EOF && len == 0) + return 0; + + /* Last character is '\r'? Remove it. */ + if (line[len-1] == '\r') + len--; + + /* Append a '\0' character to the buffer. */ + if (len == allocated) + line = prealloc (pool, line, ++allocated); + line[len] = '\0'; + + return line; +} + +char * +pgetlinex (pool pool, FILE *fp, char *line, const char *comment_set, + int flags) +{ + int i, len; + + again: + /* Read a single line. */ + line = pgetline (pool, fp, line); + if (line == 0) return 0; + + len = strlen (line); + + /* Concatenate? */ + if (!(flags & PGETL_NO_CONCAT)) + { + another_concat: + if (line[len-1] == '\\') + { + char *next; + + line[--len] = '\0'; /* Remove backslash char from first line. */ + + next = pgetline (pool, fp, 0); + if (next) + { + line = pstrcat (pool, line, next); + len = strlen (line); + goto another_concat; + } + } + } + + /* Remove comments? */ + if (!(flags & PGETL_INLINE_COMMENTS)) + { + /* No inline comments. We're searching for whitespace followed + * by a comment character. If we find it, remove the line following + * the comment character. + */ + for (i = 0; i < len; ++i) + if (!isspace ((int) line[i])) + { + if (strchr (comment_set, line[i]) != 0) + { + line[i] = '\0'; + len = i; + } + break; + } + } + else + { + /* Inline comments. Search for the first occurance of any + * comment character and just remove the rest of the line + * from that point. + */ + for (i = 0; i < len; ++i) + if (strchr (comment_set, line[i]) != 0) + { + line[i] = '\0'; + len = i; + break; + } + } + + /* Trim the line. */ + ptrim (line); + + /* Ignore blank lines. */ + if (line[0] == '\0') + goto again; + + return line; +} + +vector +pmap (pool p, const vector v, char *(*map_fn) (pool, const char *)) +{ + int i; + vector nv = new_vector (p, char *); + + for (i = 0; i < vector_size (v); ++i) + { + const char *s; + char *r; + + vector_get (v, i, s); + r = map_fn (p, s); + vector_push_back (nv, r); + } + + return nv; +} + +vector +pgrep (pool p, const vector v, int (*grep_fn) (pool, const char *)) +{ + int i; + vector nv = new_vector (p, char *); + + for (i = 0; i < vector_size (v); ++i) + { + const char *s; + + vector_get (v, i, s); + if (grep_fn (p, s)) + vector_push_back (nv, s); + } + + return nv; +} diff --git a/pstring.h b/pstring.h new file mode 100644 index 0000000..ccb280a --- /dev/null +++ b/pstring.h @@ -0,0 +1,337 @@ +/* String functions which allocate strings on the pool. + * By Richard W.M. Jones + * + * 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. + * + * $Id: pstring.h,v 1.16 2002/12/04 21:03:25 rich Exp $ + */ + +#ifndef PSTRING_H +#define PSTRING_H + +#include +#include + +#include + +#include +#include + +/* Function: pstrdup - duplicate a string or area of memory + * Function: pstrndup + * Function: pmemdup + * + * @code{pstrdup} duplicates string @code{s}, allocating new memory for the + * string in pool @code{pool}. + * + * @code{pstrndup} duplicates just the first @code{n} characters of the + * string. + * + * @code{pmemdup} duplicates an arbitrary area of memory of size + * @code{size} bytes starting at address @code{data}. + */ +extern char *pstrdup (pool, const char *s); +extern char *pstrndup (pool, const char *s, int n); +extern void *pmemdup (pool, const void *data, size_t size); + +/* Function: pstrsplit - split a string on a character, string or regexp. + * Function: pstrcsplit + * Function: pstrresplit + * Function: pstrsplit2 + * Function: pstrcsplit2 + * Function: pstrresplit2 + * + * These functions split string @code{str} on either a string + * @code{sep}, a character @code{c} or a regular expression @code{re}. + * + * The result is a vector of newly created substrings. + * + * The @code{*2} variants split the string in the same way + * on the regular expression, but keeps the matching splitting text as + * separate elements in the vector. To illustrate this, imagine that + * @code{pstrresplit} and @code{pstrresplit2} are called on the string + * "This text is bold" with the regular expression @code{[<>]}. + * + * @code{pstrresplit} will return a vector containing: + * + * @code{ ( "This text is ", "b", "bold", "/b" ) } + * + * whereas @code{pstrcsplit2} will return: + * + * @code{ ( "This text is ", "<", "b", ">", "bold", "<", "/b", ">" ) } + * + * Note that the first element of the vector might be splitting + * text, or might be ordinary text as in the example above. Also + * the elements may not be interleaved like this (think about + * what would happen if the original string contained @code{""}). + * The only way to decide would be to call @code{prematch} on each element. + * + * This turns out to be very useful for certain sorts of simple + * parsing, or if you need to reconstruct the original string (just + * concatenate all of the elements together using @code{pconcat}). + * + * In common with Perl's @code{split} function, all of these functions + * return a zero length vector if @code{str} is the empty string. + * + * See also: @ref{prematch(3)}, @ref{pconcat(3)}. + */ +extern vector pstrsplit (pool, const char *str, const char *sep); +extern vector pstrcsplit (pool, const char *str, char c); +extern vector pstrresplit (pool, const char *str, const pcre *re); +extern vector pstrsplit2 (pool, const char *str, const char *sep); +extern vector pstrcsplit2 (pool, const char *str, char c); +extern vector pstrresplit2 (pool, const char *str, const pcre *re); + +/* Function: pconcat - concatenate a vector of strings + * Function: pjoin + * + * @code{pconcat} concatenates a vector of strings to form a string. + * + * @code{pjoin} is similar except that @code{sep} is inserted between + * each concatenated string in the output. + * + * @code{pjoin} is kind of the opposite of @ref{pstrsplit(3)}. + */ +extern char *pconcat (pool, vector); +extern char *pjoin (pool, vector, const char *sep); + +/* Function: pchrs - generate a string of n repeated characters or strings + * Function: pstrs + * + * @code{pchrs (pool, 'c', n)} is similar to the Perl expression + * @code{'c' x n}. It generates a pool-allocated string of @code{n} copies + * of character @code{'c'}. + * + * @code{pstrs (pool, str, n)} is similar to the Perl expression + * @code{str x n}. It generates a pool-allocated string of @code{n} copies + * of the string @code{str}. + */ +extern char *pchrs (pool, char c, int n); +extern char *pstrs (pool, const char *str, int n); + +/* Function: pvector - generate a vector from a list or array of strings + * Function: pvectora + * + * @code{pvector} takes a NULL-terminated list of strings as arguments + * and returns a vector of strings. @code{pvectora} takes a pointer to + * an array of strings and the number of strings and returns a vector + * of strings. + * + * A typical use of this is to quickly concatenate strings: + * + * @code{s = pconcat (pool, pvector (pool, s1, s2, s3, NULL));} + * + * which is roughly equivalent to: + * + * @code{s = psprintf (pool, "%s%s%s", s1, s2, s3);} + * + * See also: @ref{pconcat(3)}, @ref{psprintf(3)}. + */ +extern vector pvector (pool, ...); +extern vector pvectora (pool, const char *array[], int n); + +/* Function: psort - sort a vector of strings + * + * Sort a vector of strings, using @code{compare_fn} to compare + * strings. The vector is sorted in-place. + * + * It is a common mistake to try to use @code{strcmp} directly + * as your comparison function. This will not work. See the + * C FAQ, section 12, question 12.2 + * (@code{http://www.lysator.liu.se/c/c-faq/c-12.html}). + */ +extern void psort (vector, int (*compare_fn) (const char **, const char **)); + +/* Function: pchomp - remove line endings from a string + * + * Remove line endings (either CR, CRLF or LF) from the string argument. + * The string is modified in-place and a pointer to the string + * is also returned. + */ +extern char *pchomp (char *line); + +/* Function: ptrim - remove whitespace from the ends of a string + * Function: ptrimfront + * Function: ptrimback + * + * @code{ptrim} modifies a string of text in place, removing any + * whitespace characters from the beginning and end of the line. + * + * @code{ptrimfront} is the same as @code{ptrim} but only removes + * whitespace from the beginning of a string. + * + * @code{ptrimback} is the same as @code{ptrim} but only removes + * whitespace from the end of a string. + */ +extern char *ptrim (char *str); +extern char *ptrimfront (char *str); +extern char *ptrimback (char *str); + +/* Function: psprintf - sprintf which allocates the result in a pool + * Function: pvsprintf + * + * The @code{psprintf} function is equivalent to @code{sprintf} + * but it allocates the result string in @code{pool}. + * + * @code{pvsprintf} works similarly to @code{vsprintf}. + */ +extern char *psprintf (pool, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +extern char *pvsprintf (pool, const char *format, va_list ap); + +/* Function: pitoa - convert number types to strings + * Function: pdtoa + * Function: pxtoa + * + * These functions convert a decimal @code{int}, @code{double} or + * hexadecimal @code{unsigned} into a string, which is allocated + * in @code{pool}. + * + * @code{pitoa} is equivalent to @code{psprintf (pool, "%d", i)}, + * and the other functions have similar equivalents. + */ +extern char *pitoa (pool, int); +extern char *pdtoa (pool, double); +extern char *pxtoa (pool, unsigned); + +/* Function: pvitostr - convert vectors of numbers to vectors of strings + * Function: pvdtostr + * Function: pvxtostr + * + * Promote vector of numbers to vector of strings. + * + * @code{pvitostr} expects a vector of @code{int}. + * + * @code{pvdtostr} expects a vector of @code{double}. + * + * @code{pvxtostr} expects a vector of hexadecimal @code{unsigned}. + * + * All functions return a vector of @code{char *}. + */ +extern vector pvitostr (pool, vector); +extern vector pvdtostr (pool, vector); +extern vector pvxtostr (pool, vector); + +/* Function: pstrcat - extend a string + * Function: pstrncat + * + * @code{str} is a string allocated in @code{pool}. + * Append @code{ending} to @code{str}, reallocating + * @code{str} if necessary. + * + * Because @code{str} may be reallocated (ie. moved) you + * must invoke this function as follows: + * + * @code{str = pstrcat (pool, str, ending);} + * + * @code{pstrncat} is similar to @code{pstrcat} except that + * only the first @code{n} characters of @code{ending} + * are appended to @code{str}. + */ +extern char *pstrcat (pool, char *str, const char *ending); +extern char *pstrncat (pool, char *str, const char *ending, size_t n); + +/* Function: psubstr - return a substring of a string + * + * Return the substring starting at @code{offset} and of length + * @code{len} of @code{str}, allocated + * as a new string. If @code{len} is negative, + * everything up to the end of @code{str} + * is returned. + */ +extern char *psubstr (pool, const char *str, int offset, int len); + +/* Function: pstrupr - convert a string to upper- or lowercase + * Function: pstrlwr + * + * Convert a string, in-place, to upper or lowercase by applying + * @code{toupper} or @code{tolower} to each character in turn. + */ +extern char *pstrupr (char *str); +extern char *pstrlwr (char *str); + +/* Function: pgetline - read a line from a file, optionally removing comments + * Function: pgetlinex + * Function: pgetlinec + * + * @code{pgetline} reads a single line from a file and returns it. It + * allocates enough space to read lines of arbitrary length. Line ending + * characters ('\r' and '\n') are automatically removed from the end + * of the line. + * + * The @code{pool} argument is a pool for allocating the line. The + * @code{fp} argument is the C @code{FILE} pointer. The @code{line} + * argument is a pointer to a string allocated in pool which will + * be reallocated and filled with the contents of the line. You may + * pass @code{line} as @code{NULL} to get a newly allocated buffer. + * + * Use @code{pgetline} in one of the following two ways: + * + * @code{line = pgetline (pool, fp, line);} + * + * or + * + * @code{line = pgetline (pool, fp, NULL);} + * + * @code{pgetlinex} is a more advanced function which reads a line + * from a file, optionally removing comments, concatenating together + * lines which have been split with a backslash, and ignoring blank + * lines. @code{pgetlinex} (and the related macro @code{pgetlinec}) are + * very useful for reading lines of input from a configuration file. + * + * The @code{pool} argument is a pool for allocating the line. The + * @code{fp} argument is the C @code{FILE} pointer. The @code{line} + * argument is a buffer allocated in pool which will be reallocated + * and filled with the result. @code{comment_set} is the set of + * possible comment characters -- eg. @code{"#!"} to allow either + * @code{#} or @code{!} to be used to introduce comments. + * @code{flags} is zero or more of the following flags OR-ed + * together: + * + * @code{PGETL_NO_CONCAT}: Don't concatenate lines which have been + * split with trailing backslash characters. + * + * @code{PGETL_INLINE_COMMENTS}: Treat everything following a comment + * character as a comment. The default is to only allow comments which + * appear on a line on their own. + * + * @code{pgetlinec} is a helper macro which calls @code{pgetlinex} + * with @code{comment_set == "#"} and @code{flags == 0}. + */ +extern char *pgetline (pool, FILE *fp, char *line); +extern char *pgetlinex (pool, FILE *fp, char *line, const char *comment_set, int flags); +#define pgetlinec(p,fp,line) pgetlinex ((p), (fp), (line), "#", 0) + +#define PGETL_NO_CONCAT 1 +#define PGETL_INLINE_COMMENTS 2 + +/* Function: pmap - map, search vectors of strings + * Function: pgrep + * + * @code{pmap} takes a @code{vector} of strings (@code{char *}) and + * transforms it into another @code{vector} of strings by applying + * the function @code{char *map_fn (pool, const char *)} to each + * string. + * + * @code{pgrep} applies the function @code{int grep_fn (pool, const char *)} + * to each element in a @code{vector} of strings, and returns a + * new vector of strings containing only those strings where + * @code{grep_fn} returns true. + * + * See also: @ref{vector_map_pool(3)}, @ref{vector_grep_pool(3)}. + */ +vector pmap (pool, const vector v, char *(*map_fn) (pool, const char *)); +vector pgrep (pool, const vector v, int (*grep_fn) (pool, const char *)); + +#endif /* PSTRING_H */ diff --git a/test_hash.c b/test_hash.c new file mode 100644 index 0000000..faebfba --- /dev/null +++ b/test_hash.c @@ -0,0 +1,99 @@ +/* Test the hash class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_hash.c,v 1.1 2001/02/08 12:51:31 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include + +/* You can't take the address of non-lvalues in C (ie. you can't + * evaluate expressions like "&2"). Hence the following constant + * definitions are necessary. + */ +const int one = 1; +const int two = 2; +const int three = 3; +const int four = 4; +const int five = 5; +const int six = 6; +const int nine = 9; +const int sixteen = 16; +const int twentyfour = 24; +const int twentyfive = 25; +const int thirtyfive = 35; +const int thirtysix = 36; + +int +main () +{ + hash h; + pool pool = new_pool (); + int v; + vector keys, values; + + /* Create a int -> int hash. */ + h = new_hash (pool, int, int); + + /* Insert some new values. */ + if (hash_insert (h, one, one) != 0) abort (); + if (hash_insert (h, two, four) != 0) abort (); + if (hash_insert (h, three, nine) != 0) abort (); + if (hash_insert (h, four, sixteen) != 0) abort (); + if (hash_insert (h, five, twentyfour) != 0) abort (); /* sic */ + if (hash_insert (h, six, thirtyfive) != 0) abort (); /* sic */ + + /* This should replace existing values. */ + if (hash_insert (h, five, twentyfive) == 0) abort (); + if (hash_insert (h, six, thirtysix) == 0) abort (); + + /* Retrieve some values. */ + if (hash_get (h, one, v) == 0 || v != 1) abort (); + if (hash_get (h, six, v) == 0 || v != 36) abort (); + if (hash_get (h, two, v) == 0 || v != 4) abort (); + if (hash_get (h, five, v) == 0 || v != 25) abort (); + + /* Copy the hash. */ + h = copy_hash (pool, h); + + /* Erase a key and check that it no longer exists. */ + if (hash_erase (h, one) == 0) abort (); + if (hash_get (h, one, v) != 0) abort (); + + /* Get list of keys and values. */ + keys = hash_keys (h); + values = hash_values (h); + + printf ("keys = [ %s ]\n", + pjoin (pool, pvitostr (pool, keys), ", ")); + printf ("values = [ %s ]\n", + pjoin (pool, pvitostr (pool, values), ", ")); + + delete_pool (pool); + exit (0); +} diff --git a/test_matvec.c b/test_matvec.c new file mode 100644 index 0000000..be20218 --- /dev/null +++ b/test_matvec.c @@ -0,0 +1,218 @@ +/* Test matrix, vector arithmetic. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_matvec.c,v 1.2 2001/11/19 17:10:55 rich Exp $ + */ + +#include +#include +#include +#include + +#include "pool.h" +#include "matvec.h" + +static inline int +is_equal (float a, float b) +{ + return fabs (a - b) < 1e-6; +} + +static void +test_identity_zero () +{ + pool p = new_subpool (global_pool); + float *m = new_identity_matrix (p); + float *v = new_zero_vec (p); + + assert (m[0] == 1 && m[1] == 0 && m[2] == 0 && m[3] == 0 && + m[4] == 0 && m[5] == 1 && m[6] == 0 && m[7] == 0 && + m[8] == 0 && m[9] == 0 && m[10] == 1 && m[11] == 0 && + m[12] == 0 && m[13] == 0 && m[14] == 0 && m[15] == 1); + assert (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 1); + + delete_pool (p); +} + +static void +test_mag_norm () +{ + float v[3] = {2, 0, 0}, r[3]; + + assert (vec_magnitude (v) == 2); + assert (vec_magnitude2d (v) == 2); + + vec_normalize (v, r); + assert (r[0] == 1 && r[1] == 0 && r[2] == 0); + + vec_normalize2d (v, r); + assert (r[0] == 1 && r[1] == 0); +} + +static void +test_dot_product () +{ + float v1[3] = { 1, 0, 0 }, v2[3] = { 0, 1, 0 }, v3[3] = { 1, 1, 0 }; + + /* Dot product of perpendicular vectors is 0. */ + assert (vec_dot_product (v1, v2) == 0); + + /* Dot product of identical normal vectors is 1. */ + assert (vec_dot_product (v1, v1) == 1); + + /* Angle between vectors. */ + assert (vec_angle_between (v1, v1) == 0); + assert (is_equal (vec_angle_between (v1, v2), M_PI/2)); + assert (is_equal (vec_angle_between (v1, v3), M_PI/4)); +} + +static void +test_point_line () +{ + float p[3], v[3], q[3], d; + + /* Line running along the x axis. */ + p[0] = 0; p[1] = 0; p[2] = 0; v[0] = 1; v[1] = 0; v[2] = 0; + + q[0] = 0; q[1] = 0; q[2] = 0; + assert (point_distance_to_line (q, p, v) == 0); + + q[0] = 1; q[1] = 0; q[2] = 0; + assert (point_distance_to_line (q, p, v) == 0); + + q[0] = 0; q[1] = 1; q[2] = 0; + assert (point_distance_to_line (q, p, v) == 1); + + q[0] = 0; q[1] = 0; q[2] = 1; + assert (point_distance_to_line (q, p, v) == 1); + + q[0] = 2; q[1] = 1; q[2] = 0; + assert (point_distance_to_line (q, p, v) == 1); + + /* Line running diagonally x-y. */ + p[0] = 2; p[1] = 2; p[2] = 0; v[0] = 1; v[1] = 1; v[2] = 0; + + q[0] = 0; q[1] = 0; q[2] = 0; + assert (point_distance_to_line (q, p, v) == 0); + + q[0] = 1; q[1] = 0; q[2] = 0; + d = point_distance_to_line (q, p, v); + assert (is_equal (d * d, 0.5)); +} + +static void +test_point_plane () +{ + float p[3], q[3], r[3], pl[4]; + + p[0] = 0; p[1] = 0; p[2] = 0; + q[0] = 2; q[1] = 0; q[2] = 0; + r[0] = 2; r[1] = 2; r[2] = 0; + plane_coefficients (p, q, r, pl); + + assert (pl[3] == 0); + vec_normalize (pl, pl); + assert (pl[0] == 0 && pl[1] == 0 && pl[2] == -1); + + assert (point_distance_to_plane (pl, p) == 0); + assert (point_distance_to_plane (pl, q) == 0); + assert (point_distance_to_plane (pl, r) == 0); + + p[0] = 5; p[1] = 5; p[2] = -3; + assert (point_distance_to_plane (pl, p) == 3); + assert (point_is_inside_plane (pl, p)); + + p[0] = 5; p[1] = 5; p[2] = 3; + assert (point_distance_to_plane (pl, p) == -3); + assert (!point_is_inside_plane (pl, p)); +} + +static void +test_point_in_face () +{ + float points[4][3] = { + { 0, 0, 0 }, + { 1, 1, 0 }, + { 1, 1, 1 }, + { 0, 0, 1 } + }; + float p[3]; + + p[0] = 0.5; p[1] = 0.5; p[2] = 0.5; + assert (point_lies_in_face ((float *) points, 4, p)); + + p[0] = 0.01; p[1] = 0.01; p[2] = 0.9; + assert (point_lies_in_face ((float *) points, 4, p)); + + p[0] = 0; p[1] = 0; p[2] = 0; + assert (point_lies_in_face ((float *) points, 4, p)); + + p[0] = 1; p[1] = 1; p[2] = 1; + assert (point_lies_in_face ((float *) points, 4, p)); + + p[0] = 1; p[1] = 0; p[2] = 0; + assert (!point_lies_in_face ((float *) points, 4, p)); + + p[0] = 1; p[1] = 1; p[2] = -1; + assert (!point_lies_in_face ((float *) points, 4, p)); + + p[0] = 0.5; p[1] = 0.5; p[2] = 2; + assert (!point_lies_in_face ((float *) points, 4, p)); +} + +static void +test_point_to_face () +{ + float points[4][3] = { + { 0, 0, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { 0, 1, 0 } + }; + float p[3]; + int edge; + + p[0] = 0.5; p[1] = 0.5; p[2] = 0; + assert (point_distance_to_face ((float *) points, 4, 0, p, &edge) == 0 + && edge == -1); + + p[0] = 0.5; p[1] = 0.5; p[2] = 1; + assert (point_distance_to_face ((float *) points, 4, 0, p, &edge) == -1 + && edge == -1); + + p[0] = 0.5; p[1] = 0.5; p[2] = -1; + assert (point_distance_to_face ((float *) points, 4, 0, p, &edge) == 1 + && edge == -1); + + p[0] = -1; p[1] = 0.5; p[2] = 0; + assert (point_distance_to_face ((float *) points, 4, 0, p, &edge) == -1 + && edge == 3); +} + +int +main () +{ + test_identity_zero (); + test_mag_norm (); + test_dot_product (); + test_point_line (); + test_point_plane (); + test_point_in_face (); + test_point_to_face (); + + exit (0); +} diff --git a/test_pool.c b/test_pool.c new file mode 100644 index 0000000..1f2e906 --- /dev/null +++ b/test_pool.c @@ -0,0 +1,281 @@ +/* Test pools, subpools, memory allocation and so on. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_pool.c,v 1.5 2002/12/07 15:18:26 rich Exp $ + */ + +#include +#include +#include +#include +#include +#include + +/* Implement a simple malloc debugger -- which counts allocations and + * frees and ensures that all memory allocated by the pool code is + * evenually freed. + */ + +static void trace_init (void); +static void trace_finish (void); +static void *trace_malloc (size_t n, const char *filename, int line); +static void *trace_realloc (void *p, size_t n, const char *filename, int line); +static void trace_free (void *p); + +#define malloc(n) trace_malloc ((n), __FILE__, __LINE__); +#define realloc(p,n) trace_realloc ((p), (n), __FILE__, __LINE__); +#define free(p) trace_free ((p)); + +#define NO_GLOBAL_POOL 1 + +#include "pool.h" +#include "pool.c" + +static void test (void); + +int +main () +{ + trace_init (); + test (); + trace_finish (); + exit (0); +} + +/* Perform the tests. */ +static void +simple_alloc_test () +{ + pool p; + int i; + + p = new_pool (); + + for (i = 0; i < 1000; ++i) + { + pmalloc (p, 1); + pmalloc (p, 1); + prealloc (p, pmalloc (p, 200), 300); + pmalloc (p, 1000); + prealloc (p, pmalloc (p, 1000), 1001); + prealloc (p, pmalloc (p, 900), 901); + pmalloc (p, 1); + pmalloc (p, 4); + pmalloc (p, 8); + pmalloc (p, 1); + pmalloc (p, 400); + } + + delete_pool (p); +} + +static void +simple_subpool_test (pool parent, int level) +{ + pool p; + int i; + + if (level >= 8) return; + + if (parent) + { + /* The following two statements must remain together. */ + p = new_subpool (parent); + prealloc (p, prealloc (p, pmalloc (p, 16), 100), + 200); + /* End of realloc test. */ + + pcalloc (p, 4, 4); + prealloc (p, 0, 8); + prealloc (p, pmalloc (p, 4), 8); + pmalloc (parent, 1); + prealloc (parent, pmalloc (parent, 8), 8); + prealloc (parent, pmalloc (parent, 8), 16); + } + else + { + p = new_pool (); + prealloc (p, pmalloc (p, 4), 8); + pmalloc (p, 8); + pmalloc (p, 1); + } + + for (i = 0; i < 3; ++i) + { + simple_subpool_test (p, level+1); + pmalloc (p, 1); + if (parent) pmalloc (parent, 1); + } + + if (parent == 0 || level == 4) + delete_pool (p); +} + +/* This is a regression test: we had reason to believe this didn't work + * at one point. + */ +static void +create_delete_test () +{ + pool p; + + p = new_pool (); + delete_pool (p); +} + +static int cleanup_called = 0; + +static void +cleanup_fn (void *v) +{ + cleanup_called ++; +} + +static void +cleanup_fn_test () +{ + pool p, sp1, sp2; + + p = new_pool (); + pool_register_cleanup_fn (p, cleanup_fn, 0); + delete_pool (p); + assert (cleanup_called == 1); + + p = new_pool (); + sp1 = new_subpool (p); + sp2 = new_subpool (p); + pool_register_cleanup_fn (p, cleanup_fn, 0); + pool_register_cleanup_fn (sp1, cleanup_fn, 0); + pool_register_cleanup_fn (sp2, cleanup_fn, 0); + delete_pool (sp1); + assert (cleanup_called == 2); + delete_pool (p); + assert (cleanup_called == 4); +} + +static void +cleanup_fd_test () +{ + int fd; + pool p; + + p = new_pool (); + fd = open ("/dev/null", O_RDONLY); + pool_register_fd (p, fd); + delete_pool (p); + + assert (close (fd) == -1 && errno == EBADF); +} + +static void +cleanup_malloc_test () +{ + void *m; + pool p; + + p = new_pool (); + m = malloc (10); + pool_register_malloc (p, m); + delete_pool (p); +} + +static void +lots_of_pmalloc_test () +{ + pool p; + pool *subpools; + int i, j, np = 0; + + /* This test kind of simulates what the chat server does, in an + * attempt to find the putative memory leak. + */ + p = new_pool (); + subpools = pcalloc (p, sizeof (struct pool), 100); + + for (i = 0; i < 10000; ++i) + { + if (subpools[np] != 0) + delete_pool (subpools[np]); + subpools[np] = new_subpool (p); + + for (j = 0; j < 100; ++j) + { + void *ptr = pmalloc (subpools[np], 100); + prealloc (subpools[np], ptr, 200); + } + + np++; + if (np == 100) np = 0; + } + + delete_pool (p); +} + +static void +test () +{ + simple_alloc_test (); + simple_subpool_test (0, 0); + create_delete_test (); + cleanup_fn_test (); + cleanup_fd_test (); + cleanup_malloc_test (); + lots_of_pmalloc_test (); +} + +/* The tracing code. */ +#undef malloc +#undef realloc +#undef free + +static int nr_allocations = 0; + +static void +trace_init () +{ +} + +static void +trace_finish () +{ + if (nr_allocations > 0) + { + fprintf (stderr, "*** error: %d allocation(s) leaked.\n", + nr_allocations); + exit (1); + } +} + +static void * +trace_malloc (size_t n, const char *filename, int line) +{ + nr_allocations++; + return malloc (n); +} + +static void * +trace_realloc (void *p, size_t n, const char *filename, int line) +{ + return realloc (p, n); +} + +static void +trace_free (void *p) +{ + nr_allocations--; + free (p); +} diff --git a/test_pre.c b/test_pre.c new file mode 100644 index 0000000..42bffd0 --- /dev/null +++ b/test_pre.c @@ -0,0 +1,152 @@ +/* Test pre library. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_pre.c,v 1.1 2002/10/05 16:42:06 rich Exp $ + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "vector.h" +#include "pstring.h" +#include "pre.h" + +static int vequals (vector v, int i, const char *str); + +int +main () +{ + pool pool; + vector v; + pcre *re1, *re2, *re3, *re4, *re5; + const char *str; + + pool = new_subpool (global_pool); + + /* Compile some regular expressions. */ + re1 = precomp (pool, "a*b+", 0); + re2 = precomp (pool, "bu(t+)ery", 0); + re3 = precomp (pool, "m(a+)rgar(ee+)ne", 0); + re4 = precomp (pool, "(a|b)(c|d)+", 0); + re5 = precomp (pool, "(a|b)((c|d)+)", 0); + + /* Matching tests. */ + v = prematch (pool, "", re1, 0); + assert (v == 0); + + v = prematch (pool, "a", re1, 0); + assert (v == 0); + + v = prematch (pool, "ab", re1, 0); + assert (v); + assert (vector_size (v) == 1); + assert (vequals (v, 0, "ab")); + + v = prematch (pool, "b", re1, 0); + assert (v); + assert (vector_size (v) == 1); + assert (vequals (v, 0, "b")); + + v = prematch (pool, "xxxaaaaaaaaaabby", re1, 0); + assert (v); + assert (vector_size (v) == 1); + assert (vequals (v, 0, "aaaaaaaaaabb")); + + v = prematch (pool, "This is quite buttery.", re2, 0); + assert (v); + assert (vector_size (v) == 2); + assert (vequals (v, 0, "buttery")); + assert (vequals (v, 1, "tt")); + + v = prematch (pool, "This is quite buttttttery.", re2, 0); + assert (v); + assert (vector_size (v) == 2); + assert (vequals (v, 0, "buttttttery")); + assert (vequals (v, 1, "tttttt")); + + v = prematch (pool, "margarene", re3, 0); + assert (v == 0); + + v = prematch (pool, "margareene", re3, 0); + assert (v); + assert (vector_size (v) == 3); + assert (vequals (v, 0, "margareene")); + assert (vequals (v, 1, "a")); + assert (vequals (v, 2, "ee")); + + v = prematch (pool, "maargareeene", re3, 0); + assert (v); + assert (vector_size (v) == 3); + assert (vequals (v, 0, "maargareeene")); + assert (vequals (v, 1, "aa")); + assert (vequals (v, 2, "eee")); + + v = prematch (pool, "abcd", re4, 0); + assert (v); + assert (vector_size (v) == 3); + assert (vequals (v, 0, "bcd")); + assert (vequals (v, 1, "b")); + assert (vequals (v, 2, "d")); + + v = prematch (pool, "abcd", re5, 0); + assert (v); + assert (vector_size (v) == 4); + assert (vequals (v, 0, "bcd")); + assert (vequals (v, 1, "b")); + assert (vequals (v, 2, "cd")); + assert (vequals (v, 3, "d")); + + /* Substitution tests. */ + + str = presubst (pool, "xxxxmaargareeeeneyy", re3, "$1$2", 0); + assert (strcmp (str, "xxxxaaeeeeyy") == 0); + + str = presubst (pool, "xxxxmaargareeeeneyy", re3, "$2$1", 0); + assert (strcmp (str, "xxxxeeeeaayy") == 0); + + str = presubst (pool, "xxxxmaargareeeeneyy xxxxmaargareeeeneyy", + re3, "$2$1", 0); + assert (strcmp (str, "xxxxeeeeaayy xxxxmaargareeeeneyy") == 0); + + str = presubst (pool, "abcd", re4, "$2$1", 0); + assert (strcmp (str, "adb") == 0); + + /* Check all the presubst flags work correctly. */ + str = presubst (pool, "xxxxmaargareeeeneyy", re3, "$1$2", + PRESUBST_NO_PLACEHOLDERS); + assert (strcmp (str, "xxxx$1$2yy") == 0); + + str = presubst (pool, "This is buttery buttery toast.", re2, "tasty", + PRESUBST_GLOBAL); + assert (strcmp (str, "This is tasty tasty toast.") == 0); + + delete_pool (pool); + exit (0); +} + +static int +vequals (vector v, int i, const char *str) +{ + const char *s; + + vector_get (v, i, s); + return strcmp (s, str) == 0; +} diff --git a/test_pstring.c b/test_pstring.c new file mode 100644 index 0000000..c02a3ad --- /dev/null +++ b/test_pstring.c @@ -0,0 +1,351 @@ +/* Test pstring library. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_pstring.c,v 1.11 2003/02/09 16:48:46 rich Exp $ + */ + +#include +#include +#include +#include + +#include + +#include "pstring.h" +#include "vector.h" + +const int i_one = 1, i_two = 2, i_three = 3, i_four = 4, + i_15 = 15, i_31 = 31, i_63 = 63, i_127 = 127; +const double d_one = 1, d_two = 2, d_three = 3, d_four = 4; +const char *s_one = "one", *s_two = "two", *s_three = "three", + *s_four = "four"; + +const char *stra[] = { "one", "two", "three", "four" }; + +const char *file1[] = { "line1\r\n", + "line2\r\n", + "line3\r\n", 0}; +const char *file2[] = { "line1\n", + "line2\n", + "line3\n", 0 }; +const char *file3[] = { "line1\n", + "line2\n", + "\n", + "line3\n", 0 }; +const char *file4[] = { "line1\\\n", + "line2\n", + "line3\n", 0 }; +const char *file5[] = { "line1\n", + "# a comment\n", + "line2\n", + "line3\n", 0 }; +const char *res1[] = { "line1", "line2", "line3", 0 }; +const char *res2[] = { "line1line2", "line3", 0 }; + +static int +my_strcmp (const char **p1, const char **p2) +{ + return strcmp (*p1, *p2); +} + +int +main () +{ + pool pool; + char *s1, *s2; + vector v1, v2, v3, v4, v5; + pcre *re; + int i; + FILE *fp; + const char **sp; + const char *errptr; + int erroffset; + + pool = new_pool (); + + /* pstrdup */ + s1 = pstrdup (pool, "sheep"); + s2 = pstrdup (pool, s1); + + s1[1] = 'l'; + + assert (strcmp (s2, "sheep") == 0); + + /* pstrndup */ + s1 = pstrndup (pool, "sheep", 3); + s2 = pstrndup (pool, "sheep", 6); + + assert (strcmp (s1, "she") == 0); + assert (strcmp (s2, "sheep") == 0); + + /* pmemdup */ + s1 = pmemdup (pool, "waves", 6); + + assert (strcmp (s1, "waves") == 0); + + /* pstrsplit */ + v1 = pstrsplit (pool, "one", "--"); + v2 = pstrsplit (pool, "--one--two", "--"); + v3 = pstrsplit (pool, "one--two--three", "--"); + v4 = pstrsplit (pool, "one--two--three--four--", "--"); + + v5 = new_vector (pool, char *); + vector_push_back (v5, s_one); + assert (vector_compare (v1, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_two); + assert (vector_compare (v2, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_three); + assert (vector_compare (v3, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_four); + assert (vector_compare (v4, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + + /* pstrcsplit */ + v1 = pstrcsplit (pool, "one", ','); + v2 = pstrcsplit (pool, ",one,two", ','); + v3 = pstrcsplit (pool, "one,two,three,", ','); + v4 = pstrcsplit (pool, "one,two,three,four", ','); + + v5 = new_vector (pool, char *); + vector_push_back (v5, s_one); + assert (vector_compare (v1, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_two); + assert (vector_compare (v2, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_three); + assert (vector_compare (v3, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_four); + assert (vector_compare (v4, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + + /* pstrresplit */ + re = pcre_compile ("[ \t]+", 0, &errptr, &erroffset, 0); + assert (re); + v1 = pstrresplit (pool, "one", re); + v2 = pstrresplit (pool, " one \ttwo", re); + v3 = pstrresplit (pool, " one\ttwo\tthree ", re); + v4 = pstrresplit (pool, " one two \t three four ", re); + + v5 = new_vector (pool, char *); + vector_push_back (v5, s_one); + assert (vector_compare (v1, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_two); + assert (vector_compare (v2, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_three); + assert (vector_compare (v3, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + vector_push_back (v5, s_four); + assert (vector_compare (v4, v5, (int (*)(const void *,const void *))my_strcmp) == 0); + free (re); + + /* pconcat, pjoin */ + v1 = new_vector (pool, char *); + vector_push_back (v1, s_one); + vector_push_back (v1, s_two); + vector_push_back (v1, s_three); + vector_push_back (v1, s_four); + s1 = pconcat (pool, v1); + assert (strcmp (s1, "onetwothreefour") == 0); + s1 = pjoin (pool, v1, ""); + assert (strcmp (s1, "onetwothreefour") == 0); + s1 = pjoin (pool, v1, ","); + assert (strcmp (s1, "one,two,three,four") == 0); + s1 = pjoin (pool, v1, ", "); + assert (strcmp (s1, "one, two, three, four") == 0); + + /* pstrresplit2 -> pconcat = original string */ + re = pcre_compile ("[ \t]+", 0, &errptr, &erroffset, 0); + s1 = "the quick brown fox"; + v1 = pstrresplit2 (pool, s1, re); + s2 = pconcat (pool, v1); + assert (strcmp (s1, s2) == 0); + + s1 = " the quick \tbrown fox"; + v1 = pstrresplit2 (pool, s1, re); + s2 = pconcat (pool, v1); + assert (strcmp (s1, s2) == 0); + + s1 = "the quick brown \tfox\t"; + v1 = pstrresplit2 (pool, s1, re); + s2 = pconcat (pool, v1); + assert (strcmp (s1, s2) == 0); + + s1 = " \tthe quick brown \tfox\t"; + v1 = pstrresplit2 (pool, s1, re); + s2 = pconcat (pool, v1); + assert (strcmp (s1, s2) == 0); + free (re); + + /* psort */ + v1 = new_vector (pool, char *); + vector_push_back (v1, s_one); + vector_push_back (v1, s_two); + vector_push_back (v1, s_three); + vector_push_back (v1, s_four); + psort (v1, my_strcmp); + s1 = pconcat (pool, v1); + assert (strcmp (s1, "fouronethreetwo") == 0); + + /* pchomp */ + s1 = pstrdup (pool, "sheep"); + pchomp (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep\r"); + pchomp (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep\r\n"); + pchomp (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep\n"); + pchomp (s1); + assert (strcmp (s1, "sheep") == 0); + + /* pchrs, pstrs */ + s1 = pchrs (pool, 'x', 20); + assert (strcmp (s1, "xxxxxxxxxxxxxxxxxxxx") == 0); + s1 = pchrs (pool, 'x', 0); + assert (strcmp (s1, "") == 0); + s1 = pstrs (pool, "x", 20); + assert (strcmp (s1, "xxxxxxxxxxxxxxxxxxxx") == 0); + s1 = pstrs (pool, "xyz", 10); + assert (strcmp (s1, "xyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") == 0); + s1 = pstrs (pool, "xyz", 0); + assert (strcmp (s1, "") == 0); + s1 = pstrs (pool, "", 100); + assert (strcmp (s1, "") == 0); + + /* psprintf (also implicitly tests pvsprintf) */ + s1 = psprintf (pool, "%d %s %s %s %s", + 4, "one", "two", "three", "four"); + assert (strcmp (s1, "4 one two three four") == 0); + for (i = 250; i < 270; ++i) + { + s1 = pchrs (pool, 'x', i); + s2 = psprintf (pool, "%s", s1); + assert (strcmp (s1, s2) == 0); + } + + /* pvector, pvectora */ + s1 = pjoin (pool, pvector (pool, "one", "two", "three", "four", 0), ","); + assert (strcmp (s1, "one,two,three,four") == 0); + s1 = pjoin (pool, pvectora (pool, stra, 4), ","); + assert (strcmp (s1, "one,two,three,four") == 0); + + /* pitoa, pdtoa, pxtoa */ + assert (strcmp (pitoa (pool, 1), "1") == 0); + assert (strcmp (pdtoa (pool, 2.1), "2.100000") == 0); + assert (strcmp (pxtoa (pool, 15), "f") == 0); + + /* pvitostr, pvdtostr, pvxtostr */ + v1 = new_vector (pool, int); + vector_push_back (v1, i_one); + vector_push_back (v1, i_two); + vector_push_back (v1, i_three); + vector_push_back (v1, i_four); + s1 = pjoin (pool, pvitostr (pool, v1), ","); + assert (strcmp (s1, "1,2,3,4") == 0); + + v1 = new_vector (pool, double); + vector_push_back (v1, d_one); + vector_push_back (v1, d_two); + vector_push_back (v1, d_three); + vector_push_back (v1, d_four); + s1 = pjoin (pool, pvdtostr (pool, v1), ","); + assert (strcmp (s1, "1.000000,2.000000,3.000000,4.000000") == 0); + + v1 = new_vector (pool, unsigned); + vector_push_back (v1, i_15); + vector_push_back (v1, i_31); + vector_push_back (v1, i_63); + vector_push_back (v1, i_127); + s1 = pjoin (pool, pvxtostr (pool, v1), ","); + assert (strcmp (s1, "f,1f,3f,7f") == 0); + + /* pstrcat */ + s1 = pstrdup (pool, "one"); + s1 = pstrcat (pool, s1, ",two"); + assert (strcmp (s1, "one,two") == 0); + + /* pstrncat */ + s1 = pstrdup (pool, "one"); + s1 = pstrncat (pool, s1, ",two,three", 4); + assert (strcmp (s1, "one,two") == 0); + + /* psubstr */ + s1 = psubstr (pool, "sheep", 1, 2); + assert (strcmp (s1, "he") == 0); + s1 = psubstr (pool, "sheep", 1, -1); + assert (strcmp (s1, "heep") == 0); + + /* pstrupr, pstrlwr */ + s1 = pstrdup (pool, "sheep"); + pstrupr (s1); + assert (strcmp (s1, "SHEEP") == 0); + pstrlwr (s1); + assert (strcmp (s1, "sheep") == 0); + + /* pgetline, pgetlinex, pgetlinec */ +#define TEST_PGETL(getfn,input,expect) s1 = pstrdup (pool, ""); fp = tmpfile (); for (sp = input; *sp; ++sp) fputs (*sp, fp); rewind (fp); for (sp = expect; *sp; ++sp) { s1 = getfn (pool, fp, s1); assert (strcmp (s1, *sp) == 0); } assert (getfn (pool, fp, s1) == 0); fclose (fp); + + TEST_PGETL (pgetline, file1, res1); + TEST_PGETL (pgetline, file2, res1); + TEST_PGETL (pgetlinec, file3, res1); + TEST_PGETL (pgetlinec, file4, res2); + TEST_PGETL (pgetlinec, file5, res1); + + /* ptrim, ptrimfront, ptrimback */ + s1 = pstrdup (pool, " sheep\t\t\t"); + ptrim (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep "); + ptrim (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, " sheep"); + ptrim (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep"); + ptrim (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, ""); + ptrim (s1); + assert (strcmp (s1, "") == 0); + + s1 = pstrdup (pool, " sheep"); + ptrimfront (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep "); + ptrimfront (s1); + assert (strcmp (s1, "sheep ") == 0); + s1 = pstrdup (pool, "sheep"); + ptrimfront (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, ""); + ptrimfront (s1); + assert (strcmp (s1, "") == 0); + + s1 = pstrdup (pool, " sheep"); + ptrimback (s1); + assert (strcmp (s1, " sheep") == 0); + s1 = pstrdup (pool, "sheep "); + ptrimback (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, "sheep"); + ptrimback (s1); + assert (strcmp (s1, "sheep") == 0); + s1 = pstrdup (pool, ""); + ptrimback (s1); + assert (strcmp (s1, "") == 0); + + delete_pool (pool); + exit (0); +} diff --git a/test_sash.c b/test_sash.c new file mode 100644 index 0000000..4c22db4 --- /dev/null +++ b/test_sash.c @@ -0,0 +1,93 @@ +/* Test the sash (string hash) class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_sash.c,v 1.1 2001/02/08 12:51:32 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include + +int +main () +{ + sash h; + pool pool = new_pool (), pool2; + const char *v; + vector keys, values; + + /* Create a string -> string hash. */ + h = new_sash (pool); + + /* Insert some new values. */ + if (sash_insert (h, "tomato", "red") != 0) abort (); + if (sash_insert (h, "orange", "orange") != 0) abort (); + if (sash_insert (h, "lemon", "yellow") != 0) abort (); + if (sash_insert (h, "lime", "green") != 0) abort (); + if (sash_insert (h, "peach", "orange") != 0) abort (); + if (sash_insert (h, "apple", "green") != 0) abort (); + if (sash_insert (h, "raspberry", "red") != 0) abort (); + + /* This should replace existing values. */ + if (sash_insert (h, "apple", "red") == 0) abort (); + if (sash_insert (h, "peach", "yellow") == 0) abort (); + + /* Retrieve some values. */ + if (sash_get (h, "apple", v) == 0 || strcmp (v, "red") != 0) abort (); + if (sash_get (h, "tomato", v) == 0 || strcmp (v, "red") != 0) abort (); + if (sash_get (h, "orange", v) == 0 || strcmp (v, "orange") != 0) abort (); + + /* Copy the sash. */ + h = copy_sash (pool, h); + + /* Erase a key and check that it no longer exists. */ + if (sash_erase (h, "apple") == 0) abort (); + if (sash_get (h, "apple", v) != 0) abort (); + + /* Get list of keys and values. */ + keys = sash_keys (h); + values = sash_values (h); + + printf ("keys = [ %s ]\n", pjoin (pool, keys, ", ")); + printf ("values = [ %s ]\n", pjoin (pool, values, ", ")); + + /* Copy the sash into another pool, delete the old pool, check all + * keys and values have been copied across. + */ + pool2 = new_pool (); + h = copy_sash (pool2, h); + delete_pool (pool); + + keys = sash_keys (h); + values = sash_values (h); + + printf ("keys = [ %s ]\n", pjoin (pool2, keys, ", ")); + printf ("values = [ %s ]\n", pjoin (pool2, values, ", ")); + + delete_pool (pool2); + exit (0); +} diff --git a/test_shash.c b/test_shash.c new file mode 100644 index 0000000..f867a42 --- /dev/null +++ b/test_shash.c @@ -0,0 +1,101 @@ +/* Test the shash (string -> something hash) class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_shash.c,v 1.2 2002/08/23 09:44:08 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include + +const int red = 1, orange = 2, yellow = 3, green = 4; + +int +main () +{ + shash h; + pool pool = new_pool (), pool2, tmp; + int v; + vector keys, values; + + /* Create a string -> string hash. */ + h = new_shash (pool, int); + + /* Insert some new values. */ + if (shash_insert (h, "tomato", red) != 0) abort (); + if (shash_insert (h, "orange", orange) != 0) abort (); + if (shash_insert (h, "lemon", yellow) != 0) abort (); + if (shash_insert (h, "lime", green) != 0) abort (); + if (shash_insert (h, "peach", orange) != 0) abort (); + if (shash_insert (h, "apple", green) != 0) abort (); + if (shash_insert (h, "raspberry", red) != 0) abort (); + + /* This should replace existing values. */ + if (shash_insert (h, "apple", red) == 0) abort (); + if (shash_insert (h, "peach", yellow) == 0) abort (); + + /* Retrieve some values. */ + if (shash_get (h, "apple", v) == 0 || v != red) abort (); + if (shash_get (h, "tomato", v) == 0 || v != red) abort (); + if (shash_get (h, "orange", v) == 0 || v != orange) abort (); + + /* Copy the shash. */ + h = copy_shash (pool, h); + + /* Erase a key and check that it no longer exists. */ + if (shash_erase (h, "apple") == 0) abort (); + if (shash_get (h, "apple", v) != 0) abort (); + + /* Get list of keys and values. */ + keys = shash_keys (h); + values = shash_values (h); + + printf ("keys = [ %s ]\n", pjoin (pool, keys, ", ")); + printf ("values = [ %s ]\n", pjoin (pool, pvitostr (pool, values), ", ")); + + /* Regression test: get list of keys into another temporary pool. */ + tmp = new_pool (); + keys = shash_keys_in_pool (h, tmp); + printf ("keys = [ %s ]\n", pjoin (pool, keys, ", ")); + delete_pool (tmp); + + /* Copy the shash into another pool, delete the old pool, check all + * keys and values have been copied across. + */ + pool2 = new_pool (); + h = copy_shash (pool2, h); + delete_pool (pool); + + keys = shash_keys (h); + values = shash_values (h); + + printf ("keys = [ %s ]\n", pjoin (pool2, keys, ", ")); + printf ("values = [ %s ]\n", pjoin (pool2, pvitostr (pool2, values), ", ")); + + delete_pool (pool2); + exit (0); +} diff --git a/test_tree.c b/test_tree.c new file mode 100644 index 0000000..200bd54 --- /dev/null +++ b/test_tree.c @@ -0,0 +1,148 @@ +/* Test the tree class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_tree.c,v 1.1 2002/09/15 15:08:52 rich Exp $ + * + * XXX This test is incomplete. + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ASSERT_H +#include +#endif + +#include "pool.h" +#include "tree.h" + +int +main () +{ + pool pool1 = new_subpool (global_pool), pool2; + tree root, leaf1, leaf2, leaf3, t; + const char *root_node = "root node"; + const char *leaf1_node = "leaf1 node"; + const char *leaf2_node = "leaf2 node"; + const char *leaf3_node = "leaf3 node"; + char *str; + + /* Create a simple node and test node access functions. */ + root = new_tree (pool1, char *); + + tree_set_data (root, root_node); + + leaf1 = new_tree (pool1, char *); + tree_set_data (leaf1, leaf1_node); + leaf2 = new_tree (pool1, char *); + tree_set_data (leaf2, leaf2_node); + leaf3 = new_tree (pool1, char *); + tree_set_data (leaf3, leaf3_node); + tree_push_back (root, leaf1); + tree_push_back (root, leaf2); + tree_push_back (root, leaf3); + + assert (tree_size (root) == 3); + + tree_get (root, 0, t); + assert (t == leaf1); + tree_get (root, 1, t); + assert (t == leaf2); + tree_get (root, 2, t); + assert (t == leaf3); + + tree_pop_front (root, t); + assert (t == leaf1); + tree_pop_back (root, t); + assert (t == leaf3); + tree_pop_front (root, t); + assert (t == leaf2); + + assert (tree_size (root) == 0); + + tree_insert (root, 0, leaf1); + tree_insert (root, 1, leaf2); + tree_insert (root, 2, leaf3); + + tree_get (root, 0, t); + assert (t == leaf1); + tree_get (root, 1, t); + assert (t == leaf2); + tree_get (root, 2, t); + assert (t == leaf3); + + tree_replace (root, 0, leaf3); + tree_replace (root, 1, leaf1); + tree_replace (root, 2, leaf2); + + tree_get (root, 0, t); + assert (t == leaf3); + tree_get (root, 1, t); + assert (t == leaf1); + tree_get (root, 2, t); + assert (t == leaf2); + + tree_erase (root, 0); + assert (tree_size (root) == 2); + + tree_erase_range (root, 0, 2); + assert (tree_size (root) == 0); + + tree_insert (root, 0, leaf1); + tree_insert (root, 1, leaf2); + tree_insert (root, 2, leaf3); + + tree_clear (root); + assert (tree_size (root) == 0); + + tree_get_data (root, str); + assert (strcmp (str, root_node) == 0); + + /* Copy the tree into another pool, delete the original. */ + tree_insert (root, 0, leaf1); + tree_insert (root, 1, leaf2); + tree_insert (root, 2, leaf3); + + pool2 = new_subpool (global_pool); + root = copy_tree (pool2, root); + delete_pool (pool1); + + assert (tree_size (root) == 3); + + tree_get_data (root, str); + assert (strcmp (str, root_node) == 0); + + tree_get (root, 0, t); + tree_get_data (t, str); + assert (strcmp (str, leaf1_node) == 0); + + tree_get (root, 1, t); + tree_get_data (t, str); + assert (strcmp (str, leaf2_node) == 0); + + tree_get (root, 2, t); + tree_get_data (t, str); + assert (strcmp (str, leaf3_node) == 0); + + exit (0); +} diff --git a/test_vector.c b/test_vector.c new file mode 100644 index 0000000..28fb569 --- /dev/null +++ b/test_vector.c @@ -0,0 +1,78 @@ +/* Test the vector class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: test_vector.c,v 1.2 2001/02/16 12:55:54 rich Exp $ + * + * XXX This test is very incomplete at present. + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ASSERT_H +#include +#endif + +#include +#include +#include + +/* These are the numbers we'll be inserting into the array. */ +static int numbers1to9[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + +static void sqr_ptr (int *a, int *r) { *r = *a * *a; } +static int gt20_ptr (int *a) { return *a > 20; } + +int +main () +{ + pool pool = new_pool (); + vector numbers, squares, squaresgt20; + + /* Create initial vector. */ + numbers = new_vector (pool, int); + vector_insert_array (numbers, 0, numbers1to9, 9); + assert (vector_size (numbers) == 9); + + /* Print numbers. */ + printf ("numbers = [ %s ]\n", + pjoin (pool, pvitostr (pool, numbers), ", ")); + + /* Square each number. */ + squares = vector_map (pool, numbers, + (void (*) (const void *, void *)) sqr_ptr, + int); + assert (vector_size (squares) == 9); + printf ("squares = [ %s ]\n", + pjoin (pool, pvitostr (pool, squares), ", ")); + + /* Get squares > 20. */ + squaresgt20 = vector_grep (pool, squares, + (int (*) (const void *)) gt20_ptr); + assert (vector_size (squaresgt20) == 5); + printf ("squares > 20 = [ %s ]\n", + pjoin (pool, pvitostr (pool, squaresgt20), ", ")); + + delete_pool (pool); + exit (0); +} diff --git a/trace/.cvsignore b/trace/.cvsignore new file mode 100644 index 0000000..e69de29 diff --git a/trace/curallocs.pl b/trace/curallocs.pl new file mode 100755 index 0000000..30901ae --- /dev/null +++ b/trace/curallocs.pl @@ -0,0 +1,187 @@ +#!/usr/bin/perl -w + +# Show current allocations from a trace file. If run over a trace file +# from a program which has exited, this will show memory leaks. If run +# over a trace file for a program which is currently running, this will +# show currently allocated space. +# +# By Richard W.M. Jones +# +# $Id: curallocs.pl,v 1.1 2001/02/08 12:51:35 rich Exp $ + +use strict; + +my %pools = (); + +my $lineno = 0; + +while (<>) + { + $lineno++; + + s/[\n\r]+$//; + + if (/^([a-z_]+)\s+caller:\s+([0-9a-fx]+)\s+ptr1:\s+([0-9a-fx]+|\(nil\))\s+ptr2:\s+([0-9a-fx]+|\(nil\))\s+ptr3:\s+([0-9a-fx]+|\(nil\))\s+i1:\s+([0-9]+)\s*$/) + { + my $fn = $1; + my $caller = $2; + my $ptr1 = $3 ne '(nil)' ? $3 : 0; + my $ptr2 = $4 ne '(nil)' ? $4 : 0; + my $ptr3 = $5 ne '(nil)' ? $4 : 0; + my $i1 = $6; + + if ($fn eq "new_pool") + { + die "new_pool: pool exists, line $lineno" + if exists $pools{$ptr1}; + + $pools{$ptr1} = { + creator => $caller, + pool => $ptr1, + children => {}, + allocations => {} + }; + } + elsif ($fn eq "new_subpool") + { + die "new_subpool: pool exists, line $lineno" + if exists $pools{$ptr1}; + + $pools{$ptr1} = { + creator => $caller, + pool => $ptr1, + parent => $ptr2, + children => {}, + allocations => {} + }; + $pools{$ptr2}{children}{$ptr1} = 1; + } + elsif ($fn eq "delete_pool") + { + if ($pools{$ptr1}{parent}) + { + delete $pools{$pools{$ptr1}{parent}}{children}{$ptr1}; + } + + remove_pool_recursively ($ptr1); + } + elsif ($fn eq "pmalloc") + { + die "pmalloc: no pool $ptr1, line $lineno" + unless exists $pools{$ptr1}; + + $pools{$ptr1}{allocations}{$ptr2} = { + creator => $caller, + pool => $ptr1, + address => $ptr2, + size => $i1 + }; + } + elsif ($fn eq "prealloc") + { + die "prealloc: no pool $ptr1, line $lineno" + unless exists $pools{$ptr1}; + die "prealloc: allocation already exists, line $lineno" + unless exists $pools{$ptr1}{allocations}{$ptr2}; + + # Delete the old allocation. + delete $pools{$ptr1}{allocations}{$ptr2}; + + $pools{$ptr1}{allocations}{$ptr3} = { + creator => $caller, + pool => $ptr1, + address => $ptr3, + size => $i1 + }; + } + else + { + die "unknown pool function traced: $fn, line $lineno"; + } + } + else + { + print "$lineno: $_\n"; + die "cannot parse line"; + } + } + +if (keys %pools > 0) { + show_pools (); +} else { + print "No pools are currently allocated.\n"; +} + +exit 0; + +sub remove_pool_recursively + { + my $pool = shift; + local $_; + + die unless exists $pools{$pool}; + + # Remove children first. + foreach (keys %{$pools{$pool}{children}}) + { + remove_pool_recursively ($_); + } + + delete $pools{$pool}; + } + +sub show_pools + { + local $_; + + foreach (keys %pools) + { + show_pool ($_); + } + } + +sub show_pool + { + my $pool = shift; + my $indent = shift || 0; + local $_; + + my $sp = " " x $indent; + + print $sp, "pool $pool created by $pools{$pool}{creator}:\n"; + print $sp, " number of direct allocations: ", 0 + keys %{$pools{$pool}{allocations}}, "\n"; + print $sp, " number of children: ", 0 + keys %{$pools{$pool}{children}}, "\n"; + print $sp, " allocations:\n"; + + show_allocations ($pools{$pool}{allocations}, $indent); + + print $sp, " children:\n"; + + foreach (keys %{$pools{$pool}{children}}) + { + show_pool ($_, $indent + 2); + } + } + +sub show_allocations + { + my $allocations = shift; + my $indent = shift || 0; + local $_; + + foreach (keys %$allocations) + { + show_allocation ($allocations->{$_}, $indent); + } + } + +sub show_allocation + { + my $allocation = shift; + my $indent = shift || 0; + local $_; + + my $sp = " " x $indent; + + print $sp, " allocation $allocation->{address} created by $allocation->{creator} size $allocation->{size}\n"; + } diff --git a/tree.c b/tree.c new file mode 100644 index 0000000..06d10a8 --- /dev/null +++ b/tree.c @@ -0,0 +1,78 @@ +/* A tree class. + * - By Richard W.M. Jones + * + * 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. + * + * $Id: tree.c,v 1.2 2002/10/08 15:10:28 rich Exp $ + */ + +#include "config.h" + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include + +#include "tree.h" + +tree +_tree_new (pool pool, size_t size) +{ + tree t = (tree) new_vector (pool, tree); + + t = prealloc (pool, t, sizeof (*t) + size); + t->size = size; + + return t; +} + +extern tree +copy_tree (pool pool, tree t) +{ + tree nt = _tree_new (pool, t->size); + int i; + + /* Copy the node data. */ + memcpy (nt->data, t->data, t->size); + + /* Copy each subnode, recursively. */ + for (i = 0; i < tree_size (t); ++i) + { + tree st, nst; + + tree_get (t, i, st); + nst = copy_tree (pool, st); + tree_push_back (nt, nst); + } + + return nt; +} + +void +_tree_get_data (tree t, void *ptr) +{ + if (ptr) memcpy (ptr, t->data, t->size); +} + +void +_tree_set_data (tree t, const void *ptr) +{ + if (ptr) memcpy (t->data, ptr, t->size); +} diff --git a/tree.h b/tree.h new file mode 100644 index 0000000..ecb282f --- /dev/null +++ b/tree.h @@ -0,0 +1,188 @@ +/* A tree class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: tree.h,v 1.1 2002/09/15 15:08:52 rich Exp $ + */ + +#ifndef TREE_H +#define TREE_H + +#include +#include + +struct tree +{ + struct vector v; /* Vector of subnodes. */ + size_t size; /* Size of the data. */ + char data[0]; /* Opaque data (used by the application). */ +}; + +typedef struct tree *tree; + +/* Function: new_tree - allocate a new tree, node or leaf + * Function: _tree_new + * + * Allocate a new tree / node / leaf. + * + * A node in the tree is defined as a list of pointers to subnodes + * and some data stored in the node itself. Because of the recursive + * definition of trees, a tree is just a node, the special 'root' + * node. A leaf is just a node which happens to have no subnodes. You + * can add subnodes to a leaf later if you want. + * + * The @code{new_vector} macro is used to allocate a node in the + * tree storing data @code{type} in the node. It just evaluates the + * size of @code{type} and calls @code{_tree_new} which actually + * allocates the node. + * + * Unless you are very careful with types, you should always make + * sure that each node in your tree has the same @code{type}. + * + * Returns: The tree / node (of type @code{tree}). + */ +#define new_tree(pool,type) _tree_new ((pool), sizeof (type)) +extern tree _tree_new (pool, size_t size); + +/* Function: tree_get_data - access the data stored in a node + * Function: _tree_get_data + * Function: tree_set_data + * Function: _tree_set_data + * + * These functions allow you to access the data stored in the node. + * + * @code{tree_get_data} copies the data out of the node into the + * local variable. + * + * @code{tree_set_data} copies the data from the local variable into + * the node. + */ +#define tree_get_data(t,obj) _tree_get_data ((t), &(obj)) +extern void _tree_get_data (tree t, void *ptr); +#define tree_set_data(t,obj) _tree_set_data ((t), &(obj)) +extern void _tree_set_data (tree t, const void *ptr); + +/* Function: copy_tree - make a deep copy of a tree + * + * Make a deep copy of tree @code{t} into pool @code{pool}. This + * copies all of the nodes and the data in those nodes recursively + * Note however that if the data in a node is a / contains a pointer + * then the pointed-to data will not be copied. + * + * Returns: The copied tree (of type @code{tree}). + */ +extern tree copy_tree (pool, tree t); + +/* Function: tree_push_back - add or remove subnodes to or from a node + * Function: tree_pop_back + * Function: tree_push_front + * Function: tree_pop_front + * + * The @code{*_push_*} functions push subnodes into nodes. + * + * The @code{*_pop_*} functions pop subnodes off nodes into local variables. + * + * The @code{*_front} functions push and pop subnodes off the front + * of a node. + * + * The @code{*_back} functions push and pop subnodes + * off the end of the node. + * + * Array indexes are checked. You cannot pop a node which has + * no subnodes. + */ +#define tree_push_back(t,subnode) (vector_push_back ((vector)(t), (subnode))) +#define tree_pop_back(t,subnode) (vector_pop_back ((vector)(t), (subnode))) +#define tree_push_front(t,subnode) (vector_push_front ((vector)(t), (subnode))) +#define tree_pop_front(t,subnode) (vector_pop_front ((vector)(t), (subnode))) + +/* Function: tree_get_subnode - get a particular subnode of a node + * Function: tree_get + * + * @code{tree_get_subnode} returns the @code{i}th subnode of a node. The + * node is unaffected. + * + * @code{tree_get} is identical. + */ +#define tree_get_subnode(t,i,subnode) tree_get((t), (i), (subnode)) +#define tree_get(t,i,subnode) (vector_get ((vector)(t), (i), (subnode))) + +/* Function: tree_insert - insert subnodes into a tree + * Function: tree_insert_array + * + * @code{tree_insert} inserts a single subnode @code{subnode} before subnode + * @code{i}. All other subnodes are moved up to make space. + * + * @code{tree_insert_array} inserts an array of @code{n} subnodes + * starting at address @code{ptr} into the node before index + * @code{i}. + * + * Array indexes are checked. + */ +#define tree_insert(t,i,subnode) (vector_insert ((vector)(t), (i), (subnode))) +#define tree_insert_array(t,i,ptr,n) (vector_insert_array ((vector)(t), (i), (ptr), (n))) + +/* Function: tree_replace - replace subnodes of a node + * Function: tree_replace_array + * + * @code{tree_replace} replaces the single subnode at + * @code{v[i]} with @code{subnode}. + * + * @code{tree_replace_array} replaces the @code{n} subnodes + * in the node starting at index @code{i} with the @code{n} + * subnodes from the array @code{ptr}. + * + * Array indexes are checked. + */ +#define tree_replace(t,i,subnode) (vector_replace ((vector)(t), (i), (subnode))) +#define tree_replace_array(t,i,ptr,n) (vector_replace_array ((vector)(t), (i), (ptr), (n))) + +/* Function: tree_erase - erase subnodes of a node + * Function: tree_erase_range + * Function: tree_clear + * + * @code{tree_erase} removes the subnode index @code{i}, shuffling + * the later subnodes down by one place to fill the space. + * + * @code{tree_erase_range} removes a range of subnodes @code{i} + * to @code{j-1} (@code{i <= j}), shuffling later subnodes down + * to fill the space. + * + * @code{tree_clear} removes all subnodes from the node, setting + * its size to @code{0}, and effectively making the node into a leaf. + * + * Array indexes are checked. + */ +#define tree_erase(t,i) (vector_erase ((vector)(t), (i))) +#define tree_erase_range(t,i,j) (vector_erase_range ((vector)(t), (i), (j))) +#define tree_clear(t) (vector_clear ((vector)(t))) + +/* Function: tree_size - return the number of subnodes of a node + * Function: tree_nr_subnodes + * + * Return the size (ie. number of subnodes) in the node. The + * @code{tree_nr_subnodes} macro is identical. + */ +#define tree_size(t) (vector_size ((vector)(t))) +#define tree_nr_subnodes(t) tree_size(t) + +/* Function: tree_swap - swap the order of two subnodes of a node + * + * Swap subnodes @code{i} and @code{j} of tree @code{t}. + */ +#define tree_swap(t,i,j) (vector_swap ((vector)(t), (i), (j))) + +#endif /* TREE_H */ diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..5f4e43b --- /dev/null +++ b/vector.c @@ -0,0 +1,353 @@ +/* A vector class. + * - By Richard W.M. Jones + * + * 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. + * + * $Id: vector.c,v 1.4 2002/10/27 16:04:42 rich Exp $ + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_ASSERT_H +#include +#endif + +#include +#include +#include + +#define INCREMENT 16 + +vector +_vector_new (pool pool, size_t size) +{ + vector v = pmalloc (pool, sizeof *v); + + v->pool = pool; + v->size = size; + v->data = 0; + v->used = v->allocated = 0; + + return v; +} + +inline vector +new_subvector (pool pool, vector v, int i, int j) +{ + vector new_v = pmalloc (pool, sizeof *v); + + assert (0 <= i && j <= v->used); + + new_v->pool = pool; + new_v->size = v->size; + + if (i < j) + { + new_v->data = pmemdup (pool, v->data + i * v->size, (j - i) * v->size); + new_v->used = new_v->allocated = j - i; + } + else + { + new_v->data = 0; + new_v->used = new_v->allocated = 0; + } + + return new_v; +} + +vector +copy_vector (pool pool, vector v) +{ + return new_subvector (pool, v, 0, v->used); +} + +inline void +_vector_push_back (vector v, const void *ptr) +{ + if (v->used >= v->allocated) + { + int a = v->allocated + INCREMENT; + void *d = prealloc (v->pool, v->data, a * v->size); + v->allocated = a; + v->data = d; + } + + if (ptr) memcpy (v->data + v->used * v->size, ptr, v->size); + v->used++; +} + +void +_vector_pop_back (vector v, void *ptr) +{ + assert (v->used > 0); + v->used--; + if (ptr) memcpy (ptr, v->data + v->used * v->size, v->size); +} + +inline void +vector_insert_array (vector v, int i, const void *ptr, int n) +{ + int j; + + assert (0 <= i && i <= v->used); + + /* Insert n dummy elements at the end of the list. */ + for (j = 0; j < n; ++j) _vector_push_back (v, 0); + + /* Move the other elements up. */ + for (j = v->used-1; j > i; --j) + memcpy (v->data + j * v->size, v->data + (j-n) * v->size, v->size); + + /* Insert these elements at position i. */ + if (ptr) memcpy (v->data + i * v->size, ptr, v->size * n); +} + +void +_vector_insert (vector v, int i, const void *ptr) +{ + vector_insert_array (v, i, ptr, 1); +} + +void +_vector_push_front (vector v, const void *ptr) +{ + _vector_insert (v, 0, ptr); +} + +void +_vector_pop_front (vector v, void *ptr) +{ + _vector_get (v, 0, ptr); + vector_erase (v, 0); +} + +void +vector_push_back_vector (vector v, const vector w) +{ + int size = v->size; + + assert (size == w->size); + + if (v->used + w->used > v->allocated) + { + int a = v->used + w->used; + void *d = prealloc (v->pool, v->data, a * size); + v->allocated = a; + v->data = d; + } + + memcpy (v->data + v->used * size, w->data, size * w->used); + v->used += w->used; +} + +void +vector_push_front_vector (vector v, const vector w) +{ + int size = v->size; + + assert (size == w->size); + + if (v->used + w->used > v->allocated) + { + int a = v->used + w->used; + void *d = prealloc (v->pool, v->data, a * size); + v->allocated = a; + v->data = d; + } + + memmove (v->data + w->used * size, v->data, v->used * size); + memcpy (v->data, w->data, size * w->used); + v->used += w->used; +} + +void +_vector_replace (vector v, int i, const void *ptr) +{ + assert (0 <= i && i < v->used); + + if (ptr) memcpy (v->data + i * v->size, ptr, v->size); +} + +inline void +vector_erase_range (vector v, int i, int j) +{ + assert (0 <= i && i < v->used && 0 <= j && j <= v->used); + + if (i < j) + { + int n = j - i, k; + + for (k = i+n; k < v->used; ++k) + memcpy (v->data + (k-n) * v->size, v->data + k * v->size, v->size); + + v->used -= n; + } +} + +void +vector_erase (vector v, int i) +{ + vector_erase_range (v, i, i+1); +} + +void +vector_clear (vector v) +{ + v->used = 0; +} + +void +_vector_get (vector v, int i, void *ptr) +{ + assert (0 <= i && i < v->used); + if (ptr) memcpy (ptr, v->data + i * v->size, v->size); +} + +const void * +_vector_get_ptr (vector v, int i) +{ + assert (0 <= i && i < v->used); + return v->data + i * v->size; +} + +void +_vector_sort (vector v, int (*compare_fn) (const void *, const void *)) +{ + qsort (v->data, v->used, v->size, compare_fn); +} + +int +_vector_compare (vector v1, vector v2, + int (*compare_fn) (const void *, const void *)) +{ + int i, r; + void *p1, *p2; + + if (vector_size (v1) < vector_size (v2)) return -1; + else if (vector_size (v1) > vector_size (v2)) return 1; + + for (i = 0; i < vector_size (v1); ++i) + { + vector_get_ptr (v1, i, p1); + vector_get_ptr (v2, i, p2); + + r = compare_fn (p1, p2); + + if (r != 0) return r; + } + + return 0; +} + +void +_vector_fill (vector v, const void *ptr, int n) +{ + while (n--) + _vector_push_back (v, ptr); +} + +void +vector_swap (vector v, int i, int j) +{ + void *pi, *pj; + char data[v->size]; + + if (i == j) return; + + vector_get_ptr (v, i, pi); + vector_get_ptr (v, j, pj); + + memcpy (data, pi, v->size); + memcpy (pi, pj, v->size); + memcpy (pj, data, v->size); +} + +void +vector_reallocate (vector v, int n) +{ + if (n > v->allocated) + { + void *d = prealloc (v->pool, v->data, n * v->size); + v->allocated = n; + v->data = d; + } +} + +vector +vector_grep (pool p, vector v, int (*match_fn) (const void *)) +{ + vector nv = _vector_new (p, v->size); + int i; + + for (i = 0; i < v->used; ++i) + if (match_fn (v->data + i * v->size)) + _vector_push_back (nv, v->data + i * v->size); + + return nv; +} + +vector +vector_grep_pool (pool p, vector v, int (*match_fn) (pool, const void *)) +{ + vector nv = _vector_new (p, v->size); + int i; + + for (i = 0; i < v->used; ++i) + if (match_fn (p, v->data + i * v->size)) + _vector_push_back (nv, v->data + i * v->size); + + return nv; +} + +vector +_vector_map (pool p, vector v, + void (*map_fn) (const void *, void *), + size_t result_size) +{ + vector nv = _vector_new (p, result_size); + int i; + + vector_reallocate (nv, v->used); + nv->used = v->used; + + for (i = 0; i < v->used; ++i) + map_fn (v->data + i * v->size, nv->data + i * nv->size); + + return nv; +} + +vector +_vector_map_pool (pool p, vector v, + void (*map_fn) (pool, const void *, void *), + size_t result_size) +{ + vector nv = _vector_new (p, result_size); + int i; + + vector_reallocate (nv, v->used); + nv->used = v->used; + + for (i = 0; i < v->used; ++i) + map_fn (p, v->data + i * v->size, nv->data + i * nv->size); + + return nv; +} diff --git a/vector.h b/vector.h new file mode 100644 index 0000000..aff02cd --- /dev/null +++ b/vector.h @@ -0,0 +1,304 @@ +/* A vector class. + * By Richard W.M. Jones + * + * 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. + * + * $Id: vector.h,v 1.4 2002/10/27 16:04:42 rich Exp $ + */ + +#ifndef VECTOR_H +#define VECTOR_H + +#include + +struct vector +{ + pool pool; + size_t size; + void *data; + int used, allocated; +}; + +typedef struct vector *vector; + +/* Function: new_vector - allocate a new vector + * Function: _vector_new + * + * Allocate a new vector in @code{pool} of type @code{type}. The + * first form is just a macro which evaluates the size of @code{type}. + * The second form creates a vector with elements of the given + * @code{size} directly. + */ +#define new_vector(pool,type) _vector_new ((pool), sizeof (type)) +extern vector _vector_new (pool, size_t size); + +/* Function: copy_vector - copy a vector + * Function: new_subvector + * + * Copy a vector @code{v} into pool @code{pool}. If the vector + * contains pointers, then this function will not copy the pointed-to + * data as well: you will need to copy this yourself if appropriate. + * + * @code{new_subvector} creates a copy of part of an existing vector. + * The new vector contains the @code{j-i} elements of the old vector + * starting at element number @code{i} and finishing at element number + * @code{j-1}. + */ +extern vector copy_vector (pool, vector v); +extern vector new_subvector (pool, vector v, int i, int j); + +/* Function: vector_push_back - push and pop objects into and out of vectors + * Function: _vector_push_back + * Function: vector_pop_back + * Function: _vector_pop_back + * Function: vector_push_front + * Function: _vector_push_front + * Function: vector_pop_front + * Function: _vector_pop_front + * + * The @code{*_push_*} functions push objects onto vectors. + * + * The @code{*_pop_*} functions pop objects off vectors into local variables. + * + * The @code{*_front} functions push and pop objects off the front + * of a vector. This type of operation is not very efficient, because + * it involves moving all other elements of the vector up or down + * by one place. + * + * The @code{*_back} functions push and pop elements + * off the end of the vector, which is efficient. + * + * Each function has two forms: a macro version and an underlying + * function. + * + * Array indexes are checked. You cannot pop an empty vector. If + * @code{ptr} is @code{NULL} then the popped object is discarded. + */ +#define vector_push_back(v,obj) _vector_push_back((v),&(obj)) +extern void _vector_push_back (vector, const void *ptr); +#define vector_pop_back(v,obj) _vector_pop_back((v),&(obj)) +extern void _vector_pop_back (vector, void *ptr); +#define vector_push_front(v,obj) _vector_push_front((v),&(obj)) +extern void _vector_push_front (vector, const void *ptr); +#define vector_pop_front(v,obj) _vector_pop_front((v),&(obj)) +extern void _vector_pop_front (vector, void *ptr); + +/* Function: vector_push_back_vector - push list of objects on to vector + * Function: vector_push_front_vector + * + * @code{vector_push_back_vector} appends the elements of vector + * @code{w} on to the end of vector @code{v}. + * + * @code{vector_push_front_vector} prepends the elements of vector + * @code{w} on to the front of vector @code{v}. + * + * In both cases, vector @code{w} is left unchanged. + * + * See also: @ref{vector_push_back(3)}, @ref{vector_push_front(3)}. + */ +extern void vector_push_back_vector (vector v, const vector w); +extern void vector_push_front_vector (vector v, const vector w); + +/* Function: vector_get - array-style indexing for vectors + * Function: _vector_get + * Function: vector_get_ptr + * Function: _vector_get_ptr + * + * @code{vector_get} copies the element at index @code{v[i]} into + * local variable @code{obj}. The vector is unaffected. + * + * @code{_vector_get} copies the element into the memory pointed + * to by @code{ptr}. If @code{ptr} is @code{NULL} then the effect + * is simply to check that element @code{v[i]} exists. + * + * @code{vector_get_ptr} and @code{_vector_get_ptr} are used to + * get a pointer to an element in the vector. This pointer actually + * points to the vector's internal data array. It is only valid + * as long as the user does not cause the internal data array to + * be reallocated or moved - typically this can happen when the + * user performs some operation which inserts more elements into + * the array. + * + * Array indexes are checked. An attempt to access an out-of-bounds + * element will result in a call to @ref{abort(3)}. + */ +#define vector_get(v,i,obj) _vector_get((v),(i),&(obj)) +extern void _vector_get (vector, int i, void *ptr); +#define vector_get_ptr(v,i,ptr) (ptr) =((typeof (ptr))_vector_get_ptr((v),(i))) +extern const void *_vector_get_ptr (vector, int i); + +/* Function: vector_insert - insert elements into a vector + * Function: _vector_insert + * Function: vector_insert_array + * + * @code{vector_insert} inserts a single object @code{obj} before element + * @code{i}. All other elements are moved up to make space. + * + * @code{vector_insert_array} inserts an array of @code{n} objects + * starting at address @code{ptr} into the vector before index + * @code{i}. + * + * Array indexes are checked. + */ +#define vector_insert(v,i,obj) _vector_insert((v),(i),&(obj)) +extern void _vector_insert (vector, int i, const void *ptr); +extern void vector_insert_array (vector v, int i, const void *ptr, int n); + +/* Function: vector_replace - replace elements of a vector + * Function: _vector_replace + * Function: vector_replace_array + * + * @code{vector_replace} replaces the single element at + * @code{v[i]} with object @code{obj}. + * + * @code{vector_replace_array} replaces the @code{n} elements + * in the vector starting at index @code{i} with the @code{n} + * elements from the array @code{ptr}. + * + * Array indexes are checked. + */ +#define vector_replace(v,i,obj) _vector_replace((v),(i),&(obj)) +extern void _vector_replace (vector, int i, const void *ptr); +extern void vector_replace_array (vector v, int i, const void *ptr, int n); + +/* Function: vector_erase - erase elements of a vector + * Function: vector_erase_range + * Function: vector_clear + * + * @code{vector_erase} removes the element @code{v[i]}, shuffling + * the later elements down by one place to fill the space. + * + * @code{vector_erase_range} removes a range of elements @code{v[i]} + * to @code{v[j-1]} (@code{i <= j}), shuffling later elements down + * to fill the space. + * + * @code{vector_clear} removes all elements from the vector, setting + * its size to @code{0}. + * + * Array indexes are checked. + */ +extern void vector_erase (vector v, int i); +extern void vector_erase_range (vector v, int i, int j); +extern void vector_clear (vector v); + +/* Function: vector_fill - fill a vector with identical elements + * Function: _vector_fill + * + * @code{vector_fill} appends @code{n} identical copies of + * @code{obj} to the vector. It is equivalent to calling + * @ref{vector_push_back(3)} in a loop @code{n} times. + */ +#define vector_fill(v,obj,n) _vector_fill((v),&(obj),(n)) +extern void _vector_fill (vector, const void *ptr, int n); + +/* Function: vector_size - return the size of a vector + * + * Return the size (ie. number of elements) in the vector. + */ +#define vector_size(v) ((v)->used) + +/* Function: vector_allocated - return the space allocated to a vector + * + * Return the amount of space which has been allocated for storing + * elements of the vector. This is different from the number of + * elements actually stored by the vector (see @ref{vector_size(3)}) + * and also different from the size of each element in bytes + * (see @ref{vector_element_size(3)}). + */ +#define vector_allocated(v) ((v)->allocated) + +/* Function: vector_element_size - return the size of each element of a vector + * + * Return the size in bytes of each element in vector. + */ +#define vector_element_size(v) ((v)->size) + +/* Function: vector_reallocate - change allocation for a vector + * + * Increase the amount of space allocated to a vector. See also + * @ref{vector_allocated(3)}. This function can be used to avoid + * the vector itself making too many calls to the underlying + * @ref{prealloc(3)}, particularly if you know in advance exactly + * how many elements the vector will contain. + */ +extern void vector_reallocate (vector v, int n); + +/* Function: vector_grep - produce a new vector containing elements of the old vector which match a boolean function + * + * This macro calls @code{match_fn(&t)} for each element @code{t} of + * vector @code{v}. It constructs and returns a new vector containing + * all those elements where the function returns true. + */ +extern vector vector_grep (pool, vector v, int (*match_fn) (const void *)); + +/* Function: vector_grep_pool - produce a new vector containing elements of the old vector which match a boolean function + * + * This macro calls @code{match_fn(pool, &t)} for each element @code{t} of + * vector @code{v}. It constructs and returns a new vector containing + * all those elements where the function returns true. + */ +extern vector vector_grep_pool (pool, vector v, int (*match_fn) (pool, const void *)); + +/* Function: vector_map - apply function to each element of a vector + * Function: _vector_map + * + * Call @code{map_fn(&t, &r)} for each element @code{t} of vector @code{v}. + * The result (@code{r}) should have type @code{result_type} + * and these are concatenated to form a new vector which is returned. + */ +#define vector_map(pool,v,map_fn,result_type) _vector_map ((pool), (v), (map_fn), sizeof (result_type)) +extern vector _vector_map (pool, vector v, void (*map_fn) (const void *, void *), size_t result_size); + +/* Function: vector_map_pool - apply function to each element of a vector + * Function: _vector_map_pool + * + * Call @code{map_fn(pool, &t, &r)} for each element @code{t} of vector + * @code{v}. The result (@code{r}) should have type @code{result_type} + * and these are concatenated to form a new vector which is returned. + */ +#define vector_map_pool(pool,v,map_fn,result_type) _vector_map_pool ((pool), (v), (map_fn), sizeof (result_type)) +extern vector _vector_map_pool (pool, vector v, void (*map_fn_pool) (pool, const void *, void *), size_t result_size); + +/* Function: vector_sort - sort a vector in-place + * Function: _vector_sort + * + * Sort a vector in-place, comparing elements using @code{compare_fn}. + */ +#define vector_sort(v,compare_fn) _vector_sort ((v), (int (*)(const void *,const void *)) (compare_fn)) +extern void _vector_sort (vector v, int (*compare_fn) (const void *, const void *)); + +/* Function: vector_compare - compare two vectors + * Function: _vector_compare + * + * Compare two vectors. This returns 0 if the two vectors are + * identical. It returns > 0 if @code{v1} > @code{v2}. This + * returns < 0 if @code{v1} < @code{v2}. + */ +#define vector_compare(v1,v2,compare_fn) _vector_compare ((v1), (v2), (int (*)(const void *,const void *)) (compare_fn)) +extern int _vector_compare (vector, vector, int (*compare_fn) (const void *, const void *)); + +/* Function: vector_reverse - reverse the elements of a vector in-place + * + * Reverse the elements of a vector in-place. + */ +extern void vector_reverse (vector v); + +/* Function: vector_swap - swap two elements of a vector + * + * Swap elements @code{i} and @code{j} of vector @code{v}. + */ +extern void vector_swap (vector v, int i, int j); + +#endif /* VECTOR_H */