From 2b18c31fb295d0f1325570a65aac498cb42f5b96 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 25 Apr 2014 11:38:47 +0100 Subject: [PATCH] Add to git. --- .cvsignore | 1 + COPYING.LIB | 481 ++++++++++++++ INSTALL | 30 + Makefile+ | 411 ++++++++++++ README | 6 + README.Solaris | 1 + configure | 66 ++ doc/Makefile | 11 + doc/collision_moving_sphere_and_face.3.html | 105 ++++ doc/copy_hash.3.html | 74 +++ doc/copy_sash.3.html | 74 +++ doc/copy_shash.3.html | 74 +++ doc/copy_vector.3.html | 85 +++ doc/delete_pool.3.html | 74 +++ doc/eg_join.c | 11 + doc/eg_sash.c | 31 + doc/eg_string.c | 37 ++ doc/eg_vectorint.c | 25 + doc/eg_vectorint2.c | 33 + doc/face_translate_along_normal.3.html | 94 +++ doc/global_pool.3.html | 76 +++ doc/hash_erase.3.html | 74 +++ doc/hash_exists.3.html | 97 +++ doc/hash_get.3.html | 97 +++ doc/hash_get_buckets_allocated.3.html | 76 +++ doc/hash_get_buckets_used.3.html | 76 +++ doc/hash_get_ptr.3.html | 97 +++ doc/hash_insert.3.html | 77 +++ doc/hash_keys.3.html | 78 +++ doc/hash_keys_in_pool.3.html | 78 +++ doc/hash_set_buckets_allocated.3.html | 76 +++ doc/hash_size.3.html | 73 +++ doc/hash_values.3.html | 78 +++ doc/hash_values_in_pool.3.html | 78 +++ doc/identity_matrix.3.html | 105 ++++ doc/index.html | 852 +++++++++++++++++++++++++ doc/make_identity_matrix.3.html | 105 ++++ doc/make_zero_vec.3.html | 105 ++++ doc/new_hash.3.html | 90 +++ doc/new_identity_matrix.3.html | 105 ++++ doc/new_matrix.3.html | 109 ++++ doc/new_pool.3.html | 105 ++++ doc/new_sash.3.html | 81 +++ doc/new_shash.3.html | 81 +++ doc/new_subpool.3.html | 74 +++ doc/new_subvector.3.html | 85 +++ doc/new_vec.3.html | 109 ++++ doc/new_vector.3.html | 76 +++ doc/new_zero_vec.3.html | 105 ++++ doc/pcalloc.3.html | 116 ++++ doc/pchomp.3.html | 74 +++ doc/pchrs.3.html | 85 +++ doc/pconcat.3.html | 88 +++ doc/pdtoa.3.html | 84 +++ doc/pgetline.3.html | 171 +++++ doc/pgetlinec.3.html | 171 +++++ doc/pgetlinex.3.html | 171 +++++ doc/pitoa.3.html | 84 +++ doc/pjoin.3.html | 88 +++ doc/plane_coefficients.3.html | 114 ++++ doc/plane_translate_along_normal.3.html | 94 +++ doc/pmalloc.3.html | 116 ++++ doc/pmatch.3.html | 109 ++++ doc/pmatchx.3.html | 109 ++++ doc/pmemdup.3.html | 90 +++ doc/point_distance_to_face.3.html | 152 +++++ doc/point_distance_to_line.3.html | 86 +++ doc/point_distance_to_line_segment.3.html | 84 +++ doc/point_distance_to_plane.3.html | 99 +++ doc/point_face_angle_sum.3.html | 103 +++ doc/point_is_inside_plane.3.html | 99 +++ doc/point_lies_in_face.3.html | 103 +++ doc/pool_get_stats.3.html | 98 +++ doc/pool_register_cleanup_fn.3.html | 75 +++ doc/pool_register_fd.3.html | 75 +++ doc/pool_register_malloc.3.html | 74 +++ doc/pool_set_bad_malloc_handler.3.html | 74 +++ doc/prealloc.3.html | 116 ++++ doc/psort.3.html | 82 +++ doc/psprintf.3.html | 82 +++ doc/pstrcat.3.html | 96 +++ doc/pstrcsplit.3.html | 95 +++ doc/pstrdup.3.html | 90 +++ doc/pstrlwr.3.html | 75 +++ doc/pstrncat.3.html | 96 +++ doc/pstrndup.3.html | 90 +++ doc/pstrresplit.3.html | 95 +++ doc/pstrs.3.html | 85 +++ doc/pstrsplit.3.html | 95 +++ doc/pstrupr.3.html | 75 +++ doc/psubst.3.html | 117 ++++ doc/psubstr.3.html | 75 +++ doc/psubstx.3.html | 117 ++++ doc/ptrim.3.html | 91 +++ doc/ptrimback.3.html | 91 +++ doc/ptrimfront.3.html | 91 +++ doc/pvdtostr.3.html | 100 +++ doc/pvector.3.html | 112 ++++ doc/pvectora.3.html | 112 ++++ doc/pvitostr.3.html | 100 +++ doc/pvsprintf.3.html | 82 +++ doc/pvxtostr.3.html | 100 +++ doc/pxtoa.3.html | 84 +++ doc/sash_erase.3.html | 73 +++ doc/sash_exists.3.html | 85 +++ doc/sash_get.3.html | 85 +++ doc/sash_get_buckets_allocated.3.html | 76 +++ doc/sash_get_buckets_used.3.html | 76 +++ doc/sash_insert.3.html | 76 +++ doc/sash_keys.3.html | 78 +++ doc/sash_keys_in_pool.3.html | 78 +++ doc/sash_set_buckets_allocated.3.html | 76 +++ doc/sash_size.3.html | 73 +++ doc/sash_values.3.html | 78 +++ doc/sash_values_in_pool.3.html | 78 +++ doc/shash_erase.3.html | 73 +++ doc/shash_exists.3.html | 97 +++ doc/shash_get.3.html | 97 +++ doc/shash_get_buckets_allocated.3.html | 76 +++ doc/shash_get_buckets_used.3.html | 76 +++ doc/shash_get_ptr.3.html | 97 +++ doc/shash_insert.3.html | 77 +++ doc/shash_keys.3.html | 78 +++ doc/shash_keys_in_pool.3.html | 78 +++ doc/shash_set_buckets_allocated.3.html | 76 +++ doc/shash_size.3.html | 73 +++ doc/shash_values.3.html | 78 +++ doc/shash_values_in_pool.3.html | 78 +++ doc/vec_angle_between.3.html | 83 +++ doc/vec_dot_product.3.html | 107 ++++ doc/vec_magnitude.3.html | 85 +++ doc/vec_magnitude2d.3.html | 85 +++ doc/vec_magnitude_in_direction.3.html | 88 +++ doc/vec_normalize.3.html | 98 +++ doc/vec_normalize2d.3.html | 98 +++ doc/vector_allocated.3.html | 77 +++ doc/vector_clear.3.html | 97 +++ doc/vector_compare.3.html | 76 +++ doc/vector_element_size.3.html | 73 +++ doc/vector_erase.3.html | 97 +++ doc/vector_erase_range.3.html | 97 +++ doc/vector_fill.3.html | 76 +++ doc/vector_get.3.html | 106 ++++ doc/vector_get_ptr.3.html | 106 ++++ doc/vector_grep.3.html | 75 +++ doc/vector_grep_pool.3.html | 75 +++ doc/vector_insert.3.html | 90 +++ doc/vector_insert_array.3.html | 90 +++ doc/vector_map.3.html | 76 +++ doc/vector_map_pool.3.html | 76 +++ doc/vector_pop_back.3.html | 118 ++++ doc/vector_pop_front.3.html | 118 ++++ doc/vector_push_back.3.html | 118 ++++ doc/vector_push_front.3.html | 118 ++++ doc/vector_reallocate.3.html | 77 +++ doc/vector_replace.3.html | 89 +++ doc/vector_replace_array.3.html | 89 +++ doc/vector_reverse.3.html | 72 +++ doc/vector_size.3.html | 73 +++ doc/vector_sort.3.html | 74 +++ doc/vector_swap.3.html | 73 +++ doc/zero_vec.3.html | 105 ++++ hash.c | 936 ++++++++++++++++++++++++++++ hash.h | 358 +++++++++++ matvec.c | 909 +++++++++++++++++++++++++++ matvec.h | 392 ++++++++++++ pool.c | 488 +++++++++++++++ pool.h | 158 +++++ pre.c | 278 +++++++++ pre.h | 87 +++ pstring.c | 721 +++++++++++++++++++++ pstring.h | 337 ++++++++++ test_hash.c | 99 +++ test_matvec.c | 218 +++++++ test_pool.c | 281 +++++++++ test_pre.c | 152 +++++ test_pstring.c | 351 +++++++++++ test_sash.c | 93 +++ test_shash.c | 101 +++ test_tree.c | 148 +++++ test_vector.c | 78 +++ trace/.cvsignore | 0 trace/curallocs.pl | 187 ++++++ tree.c | 78 +++ tree.h | 188 ++++++ vector.c | 353 +++++++++++ vector.h | 304 +++++++++ 187 files changed, 22708 insertions(+) create mode 100644 .cvsignore create mode 100644 COPYING.LIB create mode 100644 INSTALL create mode 100644 Makefile+ create mode 100644 README create mode 100644 README.Solaris create mode 100755 configure create mode 100644 doc/Makefile create mode 100644 doc/collision_moving_sphere_and_face.3.html create mode 100644 doc/copy_hash.3.html create mode 100644 doc/copy_sash.3.html create mode 100644 doc/copy_shash.3.html create mode 100644 doc/copy_vector.3.html create mode 100644 doc/delete_pool.3.html create mode 100644 doc/eg_join.c create mode 100644 doc/eg_sash.c create mode 100644 doc/eg_string.c create mode 100644 doc/eg_vectorint.c create mode 100644 doc/eg_vectorint2.c create mode 100644 doc/face_translate_along_normal.3.html create mode 100644 doc/global_pool.3.html create mode 100644 doc/hash_erase.3.html create mode 100644 doc/hash_exists.3.html create mode 100644 doc/hash_get.3.html create mode 100644 doc/hash_get_buckets_allocated.3.html create mode 100644 doc/hash_get_buckets_used.3.html create mode 100644 doc/hash_get_ptr.3.html create mode 100644 doc/hash_insert.3.html create mode 100644 doc/hash_keys.3.html create mode 100644 doc/hash_keys_in_pool.3.html create mode 100644 doc/hash_set_buckets_allocated.3.html create mode 100644 doc/hash_size.3.html create mode 100644 doc/hash_values.3.html create mode 100644 doc/hash_values_in_pool.3.html create mode 100644 doc/identity_matrix.3.html create mode 100644 doc/index.html create mode 100644 doc/make_identity_matrix.3.html create mode 100644 doc/make_zero_vec.3.html create mode 100644 doc/new_hash.3.html create mode 100644 doc/new_identity_matrix.3.html create mode 100644 doc/new_matrix.3.html create mode 100644 doc/new_pool.3.html create mode 100644 doc/new_sash.3.html create mode 100644 doc/new_shash.3.html create mode 100644 doc/new_subpool.3.html create mode 100644 doc/new_subvector.3.html create mode 100644 doc/new_vec.3.html create mode 100644 doc/new_vector.3.html create mode 100644 doc/new_zero_vec.3.html create mode 100644 doc/pcalloc.3.html create mode 100644 doc/pchomp.3.html create mode 100644 doc/pchrs.3.html create mode 100644 doc/pconcat.3.html create mode 100644 doc/pdtoa.3.html create mode 100644 doc/pgetline.3.html create mode 100644 doc/pgetlinec.3.html create mode 100644 doc/pgetlinex.3.html create mode 100644 doc/pitoa.3.html create mode 100644 doc/pjoin.3.html create mode 100644 doc/plane_coefficients.3.html create mode 100644 doc/plane_translate_along_normal.3.html create mode 100644 doc/pmalloc.3.html create mode 100644 doc/pmatch.3.html create mode 100644 doc/pmatchx.3.html create mode 100644 doc/pmemdup.3.html create mode 100644 doc/point_distance_to_face.3.html create mode 100644 doc/point_distance_to_line.3.html create mode 100644 doc/point_distance_to_line_segment.3.html create mode 100644 doc/point_distance_to_plane.3.html create mode 100644 doc/point_face_angle_sum.3.html create mode 100644 doc/point_is_inside_plane.3.html create mode 100644 doc/point_lies_in_face.3.html create mode 100644 doc/pool_get_stats.3.html create mode 100644 doc/pool_register_cleanup_fn.3.html create mode 100644 doc/pool_register_fd.3.html create mode 100644 doc/pool_register_malloc.3.html create mode 100644 doc/pool_set_bad_malloc_handler.3.html create mode 100644 doc/prealloc.3.html create mode 100644 doc/psort.3.html create mode 100644 doc/psprintf.3.html create mode 100644 doc/pstrcat.3.html create mode 100644 doc/pstrcsplit.3.html create mode 100644 doc/pstrdup.3.html create mode 100644 doc/pstrlwr.3.html create mode 100644 doc/pstrncat.3.html create mode 100644 doc/pstrndup.3.html create mode 100644 doc/pstrresplit.3.html create mode 100644 doc/pstrs.3.html create mode 100644 doc/pstrsplit.3.html create mode 100644 doc/pstrupr.3.html create mode 100644 doc/psubst.3.html create mode 100644 doc/psubstr.3.html create mode 100644 doc/psubstx.3.html create mode 100644 doc/ptrim.3.html create mode 100644 doc/ptrimback.3.html create mode 100644 doc/ptrimfront.3.html create mode 100644 doc/pvdtostr.3.html create mode 100644 doc/pvector.3.html create mode 100644 doc/pvectora.3.html create mode 100644 doc/pvitostr.3.html create mode 100644 doc/pvsprintf.3.html create mode 100644 doc/pvxtostr.3.html create mode 100644 doc/pxtoa.3.html create mode 100644 doc/sash_erase.3.html create mode 100644 doc/sash_exists.3.html create mode 100644 doc/sash_get.3.html create mode 100644 doc/sash_get_buckets_allocated.3.html create mode 100644 doc/sash_get_buckets_used.3.html create mode 100644 doc/sash_insert.3.html create mode 100644 doc/sash_keys.3.html create mode 100644 doc/sash_keys_in_pool.3.html create mode 100644 doc/sash_set_buckets_allocated.3.html create mode 100644 doc/sash_size.3.html create mode 100644 doc/sash_values.3.html create mode 100644 doc/sash_values_in_pool.3.html create mode 100644 doc/shash_erase.3.html create mode 100644 doc/shash_exists.3.html create mode 100644 doc/shash_get.3.html create mode 100644 doc/shash_get_buckets_allocated.3.html create mode 100644 doc/shash_get_buckets_used.3.html create mode 100644 doc/shash_get_ptr.3.html create mode 100644 doc/shash_insert.3.html create mode 100644 doc/shash_keys.3.html create mode 100644 doc/shash_keys_in_pool.3.html create mode 100644 doc/shash_set_buckets_allocated.3.html create mode 100644 doc/shash_size.3.html create mode 100644 doc/shash_values.3.html create mode 100644 doc/shash_values_in_pool.3.html create mode 100644 doc/vec_angle_between.3.html create mode 100644 doc/vec_dot_product.3.html create mode 100644 doc/vec_magnitude.3.html create mode 100644 doc/vec_magnitude2d.3.html create mode 100644 doc/vec_magnitude_in_direction.3.html create mode 100644 doc/vec_normalize.3.html create mode 100644 doc/vec_normalize2d.3.html create mode 100644 doc/vector_allocated.3.html create mode 100644 doc/vector_clear.3.html create mode 100644 doc/vector_compare.3.html create mode 100644 doc/vector_element_size.3.html create mode 100644 doc/vector_erase.3.html create mode 100644 doc/vector_erase_range.3.html create mode 100644 doc/vector_fill.3.html create mode 100644 doc/vector_get.3.html create mode 100644 doc/vector_get_ptr.3.html create mode 100644 doc/vector_grep.3.html create mode 100644 doc/vector_grep_pool.3.html create mode 100644 doc/vector_insert.3.html create mode 100644 doc/vector_insert_array.3.html create mode 100644 doc/vector_map.3.html create mode 100644 doc/vector_map_pool.3.html create mode 100644 doc/vector_pop_back.3.html create mode 100644 doc/vector_pop_front.3.html create mode 100644 doc/vector_push_back.3.html create mode 100644 doc/vector_push_front.3.html create mode 100644 doc/vector_reallocate.3.html create mode 100644 doc/vector_replace.3.html create mode 100644 doc/vector_replace_array.3.html create mode 100644 doc/vector_reverse.3.html create mode 100644 doc/vector_size.3.html create mode 100644 doc/vector_sort.3.html create mode 100644 doc/vector_swap.3.html create mode 100644 doc/zero_vec.3.html create mode 100644 hash.c create mode 100644 hash.h create mode 100644 matvec.c create mode 100644 matvec.h create mode 100644 pool.c create mode 100644 pool.h create mode 100644 pre.c create mode 100644 pre.h create mode 100644 pstring.c create mode 100644 pstring.h create mode 100644 test_hash.c create mode 100644 test_matvec.c create mode 100644 test_pool.c create mode 100644 test_pre.c create mode 100644 test_pstring.c create mode 100644 test_sash.c create mode 100644 test_shash.c create mode 100644 test_tree.c create mode 100644 test_vector.c create mode 100644 trace/.cvsignore create mode 100755 trace/curallocs.pl create mode 100644 tree.c create mode 100644 tree.h create mode 100644 vector.c create mode 100644 vector.h 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 */ -- 1.8.3.1