From ce73e625ae5d21612eaadf8d928e2bce9e4e00b1 Mon Sep 17 00:00:00 2001 From: xtraeme Date: Mon, 20 Oct 2008 13:52:54 +0000 Subject: [PATCH] Imported Portable proplib version 0.1 without autotools stuff generated. git-svn-id: http://portableproplib.googlecode.com/svn/trunk@2 7c44cb52-9ead-11dd-b1d9-6d7c01a26949 --- AUTHORS | 1 + COPYING | 340 +++++++++++ ChangeLog | 2 + INSTALL | 229 ++++++++ Makefile.am | 2 + NEWS | 2 + README | 27 + bootstrap | 7 + configure.ac | 65 +++ include/Makefile.am | 7 + include/prop_array.h | 140 +++++ include/prop_bool.h | 49 ++ include/prop_data.h | 55 ++ include/prop_dictionary.h | 145 +++++ include/prop_ingest.h | 90 +++ include/prop_number.h | 57 ++ include/prop_object.h | 67 +++ include/prop_string.h | 60 ++ include/proplib.h | 45 ++ man/Makefile.am | 3 + man/prop_array.3 | 285 +++++++++ man/prop_array_util.3 | 218 +++++++ man/prop_bool.3 | 82 +++ man/prop_data.3 | 148 +++++ man/prop_dictionary.3 | 328 +++++++++++ man/prop_dictionary_util.3 | 186 ++++++ man/prop_ingest.3 | 181 ++++++ man/prop_number.3 | 204 +++++++ man/prop_object.3 | 140 +++++ man/prop_string.3 | 188 ++++++ man/proplib.3 | 137 +++++ src/Makefile.am | 15 + src/prop_array.3 | 285 +++++++++ src/prop_array.c | 906 +++++++++++++++++++++++++++++ src/prop_array.h | 140 +++++ src/prop_array_util.3 | 218 +++++++ src/prop_array_util.c | 240 ++++++++ src/prop_bool.3 | 82 +++ src/prop_bool.c | 223 +++++++ src/prop_bool.h | 48 ++ src/prop_data.3 | 148 +++++ src/prop_data.c | 603 +++++++++++++++++++ src/prop_data.h | 54 ++ src/prop_dictionary.3 | 328 +++++++++++ src/prop_dictionary.c | 1387 ++++++++++++++++++++++++++++++++++++++++++++ src/prop_dictionary.h | 143 +++++ src/prop_dictionary_util.3 | 186 ++++++ src/prop_dictionary_util.c | 208 +++++++ src/prop_ingest.3 | 181 ++++++ src/prop_ingest.c | 159 +++++ src/prop_ingest.h | 90 +++ src/prop_number.3 | 204 +++++++ src/prop_number.c | 560 ++++++++++++++++++ src/prop_number.h | 57 ++ src/prop_object.3 | 140 +++++ src/prop_object.c | 1184 +++++++++++++++++++++++++++++++++++++ src/prop_object.h | 67 +++ src/prop_object_impl.h | 271 +++++++++ src/prop_rb.c | 1056 +++++++++++++++++++++++++++++++++ src/prop_rb_impl.h | 137 +++++ src/prop_stack.c | 118 ++++ src/prop_stack.h | 63 ++ src/prop_string.3 | 188 ++++++ src/prop_string.c | 471 +++++++++++++++ src/prop_string.h | 60 ++ src/proplib.3 | 137 +++++ src/proplib.h | 43 ++ src/queue.h | 697 ++++++++++++++++++++++ 68 files changed, 14587 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 include/Makefile.am create mode 100644 include/prop_array.h create mode 100644 include/prop_bool.h create mode 100644 include/prop_data.h create mode 100644 include/prop_dictionary.h create mode 100644 include/prop_ingest.h create mode 100644 include/prop_number.h create mode 100644 include/prop_object.h create mode 100644 include/prop_string.h create mode 100644 include/proplib.h create mode 100644 man/Makefile.am create mode 100644 man/prop_array.3 create mode 100644 man/prop_array_util.3 create mode 100644 man/prop_bool.3 create mode 100644 man/prop_data.3 create mode 100644 man/prop_dictionary.3 create mode 100644 man/prop_dictionary_util.3 create mode 100644 man/prop_ingest.3 create mode 100644 man/prop_number.3 create mode 100644 man/prop_object.3 create mode 100644 man/prop_string.3 create mode 100644 man/proplib.3 create mode 100644 src/Makefile.am create mode 100644 src/prop_array.3 create mode 100644 src/prop_array.c create mode 100644 src/prop_array.h create mode 100644 src/prop_array_util.3 create mode 100644 src/prop_array_util.c create mode 100644 src/prop_bool.3 create mode 100644 src/prop_bool.c create mode 100644 src/prop_bool.h create mode 100644 src/prop_data.3 create mode 100644 src/prop_data.c create mode 100644 src/prop_data.h create mode 100644 src/prop_dictionary.3 create mode 100644 src/prop_dictionary.c create mode 100644 src/prop_dictionary.h create mode 100644 src/prop_dictionary_util.3 create mode 100644 src/prop_dictionary_util.c create mode 100644 src/prop_ingest.3 create mode 100644 src/prop_ingest.c create mode 100644 src/prop_ingest.h create mode 100644 src/prop_number.3 create mode 100644 src/prop_number.c create mode 100644 src/prop_number.h create mode 100644 src/prop_object.3 create mode 100644 src/prop_object.c create mode 100644 src/prop_object.h create mode 100644 src/prop_object_impl.h create mode 100644 src/prop_rb.c create mode 100644 src/prop_rb_impl.h create mode 100644 src/prop_stack.c create mode 100644 src/prop_stack.h create mode 100644 src/prop_string.3 create mode 100644 src/prop_string.c create mode 100644 src/prop_string.h create mode 100644 src/proplib.3 create mode 100644 src/proplib.h create mode 100644 src/queue.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..8dd435d --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +The NetBSD's proplib implementation was written by Jason R. Thorpe. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, 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 software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, 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 redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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 program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..632cd5a --- /dev/null +++ b/ChangeLog @@ -0,0 +1,2 @@ +0.1: + Initial import of NetBSD's libprop. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..54caf7c --- /dev/null +++ b/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..419ac34 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +ACLOCAL_AMFLAGS = -I m4 +SUBDIRS = include man src diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..9a55039 --- /dev/null +++ b/NEWS @@ -0,0 +1,2 @@ +0.1: + Initial public release matching libprop from NetBSD 4.99.73. diff --git a/README b/README new file mode 100644 index 0000000..94c0c09 --- /dev/null +++ b/README @@ -0,0 +1,27 @@ +Portable Property container object library +------------------------------------------------------------------------------ + +The proplib library provides an abstract interface for creating and +manipulating property lists. Property lists have object types for +boolean values, opaque data, numbers, and strings. Structure is provided +by the array and dictionary collection types. + +Property lists can be passed across protection boundaries by translating +them to an external representation. This external representation is an +XML document whose format is described by the following DTD: + + http://www.apple.com/DTDs/PropertyList-1.0.dtd + +-- + +This proplib version is the same version than is available on NetBSD, but +with the exception that NetBSD specific code has been removed and +it has been converted to be built throught the GNU autotools. + +Also it should be mentioned that NetBSD's proplib code is a free, +clean room and from scratch implementation based in the specifications +available for Mac OS X, written by Jason R. Thorpe. + +I'd like to thank you Jason R. Thorpe for such a great library. + + -- Juan Romero Pardines diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..672c62b --- /dev/null +++ b/bootstrap @@ -0,0 +1,7 @@ +#!/bin/sh + +aclocal +libtoolize --force --copy +autoheader +automake --add-missing --copy +autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c9c58e2 --- /dev/null +++ b/configure.ac @@ -0,0 +1,65 @@ +# +# GNU Autoconf stuff for libprop. +# +AC_PREREQ(2.52) + +m4_define([proplib_major_version], [0]) +m4_define([proplib_minor_version], [1]) +m4_define([proplib_micro_version], [0]) +m4_define([proplib_version], + [proplib_major_version.proplib_minor_version.proplib_micro_version]) + +AC_INIT([proplib], [proplib_version]) +## must come before we use the $USE_MAINTAINER_MODE variable later +AM_MAINTAINER_MODE + +# libtool versioning +# +# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details +# + +## increment if the interface has additions, changes, removals. +LT_CURRENT=0 + +## increment any time the source changes; set to +## 0 if you increment CURRENT +LT_REVISION=7 + +## increment if any interfaces have been added; set to 0 +## if any interfaces have been changed or removed. removal has +## precedence over adding, so set to 0 if both happened. +LT_AGE=0 + +AC_SUBST(LT_CURRENT) +AC_SUBST(LT_REVISION) +AC_SUBST(LT_AGE) + +AM_INIT_AUTOMAKE +AC_PROG_CC +AC_PROG_LIBTOOL +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile include/Makefile man/Makefile src/Makefile]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CHECK_FUNCS(memmove memset munmap strchr strtoul stroull) +AC_CHECK_HEADERS(limits.h stddef.h fcntl.h pthread.h) + +AC_C_CONST +AC_FUNC_MEMCMP +AC_FUNC_MMAP +AC_HEADER_STDBOOL +AC_HEADER_STDC +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_INT8_T +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +AC_OUTPUT diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..f093eec --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,7 @@ +# +# Public headers installed by libprop. +# +proplibincludedir = $(includedir)/prop +proplibinclude_HEADERS = \ + prop_array.h prop_bool.h prop_data.h prop_dictionary.h \ + prop_ingest.h proplib.h prop_number.h prop_object.h prop_string.h diff --git a/include/prop_array.h b/include/prop_array.h new file mode 100644 index 0000000..6af2668 --- /dev/null +++ b/include/prop_array.h @@ -0,0 +1,140 @@ +/* $NetBSD: prop_array.h,v 1.8 2008/09/11 13:15:13 haad Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_ARRAY_H_ +#define _PROPLIB_PROP_ARRAY_H_ + +#include +#include + +typedef struct _prop_array *prop_array_t; + +__BEGIN_DECLS +prop_array_t prop_array_create(void); +prop_array_t prop_array_create_with_capacity(unsigned int); + +prop_array_t prop_array_copy(prop_array_t); +prop_array_t prop_array_copy_mutable(prop_array_t); + +unsigned int prop_array_capacity(prop_array_t); +unsigned int prop_array_count(prop_array_t); +bool prop_array_ensure_capacity(prop_array_t, unsigned int); + +void prop_array_make_immutable(prop_array_t); +bool prop_array_mutable(prop_array_t); + +prop_object_iterator_t prop_array_iterator(prop_array_t); + +prop_object_t prop_array_get(prop_array_t, unsigned int); +bool prop_array_set(prop_array_t, unsigned int, prop_object_t); +bool prop_array_add(prop_array_t, prop_object_t); +void prop_array_remove(prop_array_t, unsigned int); + +bool prop_array_equals(prop_array_t, prop_array_t); + +char * prop_array_externalize(prop_array_t); +prop_array_t prop_array_internalize(const char *); + +bool prop_array_externalize_to_file(prop_array_t, const char *); +prop_array_t prop_array_internalize_from_file(const char *); + +/* + * Utility routines to make it more convenient to work with values + * stored in dictionaries. + */ +bool prop_array_get_bool(prop_array_t, unsigned int, + bool *); +bool prop_array_set_bool(prop_array_t, unsigned int, + bool); + +bool prop_array_get_int8(prop_array_t, unsigned int, + int8_t *); +bool prop_array_get_uint8(prop_array_t, unsigned int, + uint8_t *); +bool prop_array_set_int8(prop_array_t, unsigned int, + int8_t); +bool prop_array_set_uint8(prop_array_t, unsigned int, + uint8_t); + +bool prop_array_get_int16(prop_array_t, unsigned int, + int16_t *); +bool prop_array_get_uint16(prop_array_t, unsigned int, + uint16_t *); +bool prop_array_set_int16(prop_array_t, unsigned int, + int16_t); +bool prop_array_set_uint16(prop_array_t, unsigned int, + uint16_t); + +bool prop_array_get_int32(prop_array_t, unsigned int, + int32_t *); +bool prop_array_get_uint32(prop_array_t, unsigned int, + uint32_t *); +bool prop_array_set_int32(prop_array_t, unsigned int, + int32_t); +bool prop_array_set_uint32(prop_array_t, unsigned int, + uint32_t); + +bool prop_array_get_int64(prop_array_t, unsigned int, + int64_t *); +bool prop_array_get_uint64(prop_array_t, unsigned int, + uint64_t *); +bool prop_array_set_int64(prop_array_t, unsigned int, + int64_t); +bool prop_array_set_uint64(prop_array_t, unsigned int, + uint64_t); + +bool prop_array_add_int8(prop_array_t, int8_t); +bool prop_array_add_uint8(prop_array_t, uint8_t); + +bool prop_array_add_int16(prop_array_t, int16_t); +bool prop_array_add_uint16(prop_array_t, uint16_t); + +bool prop_array_add_int32(prop_array_t, int32_t); +bool prop_array_add_uint32(prop_array_t, uint32_t); + +bool prop_array_add_int64(prop_array_t, int64_t); +bool prop_array_add_uint64(prop_array_t, uint64_t); + +bool prop_array_get_cstring(prop_array_t, unsigned int, + char **); +bool prop_array_set_cstring(prop_array_t, unsigned int, + const char *); + +bool prop_array_get_cstring_nocopy(prop_array_t, + unsigned int, + const char **); +bool prop_array_set_cstring_nocopy(prop_array_t, + unsigned int, + const char *); + +__END_DECLS + +#endif /* _PROPLIB_PROP_ARRAY_H_ */ diff --git a/include/prop_bool.h b/include/prop_bool.h new file mode 100644 index 0000000..c21d28b --- /dev/null +++ b/include/prop_bool.h @@ -0,0 +1,49 @@ +/* $NetBSD: prop_bool.h,v 1.4 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_BOOL_H_ +#define _PROPLIB_PROP_BOOL_H_ + +#include +#include + +typedef struct _prop_bool *prop_bool_t; + +__BEGIN_DECLS +prop_bool_t prop_bool_create(bool); +prop_bool_t prop_bool_copy(prop_bool_t); + +bool prop_bool_true(prop_bool_t); + +bool prop_bool_equals(prop_bool_t, prop_bool_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_BOOL_H_ */ diff --git a/include/prop_data.h b/include/prop_data.h new file mode 100644 index 0000000..30e12b2 --- /dev/null +++ b/include/prop_data.h @@ -0,0 +1,55 @@ +/* $NetBSD: prop_data.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_DATA_H_ +#define _PROPLIB_PROP_DATA_H_ + +#include +#include + +typedef struct _prop_data *prop_data_t; + +__BEGIN_DECLS +prop_data_t prop_data_create_data(const void *, size_t); +prop_data_t prop_data_create_data_nocopy(const void *, size_t); + +prop_data_t prop_data_copy(prop_data_t); + +size_t prop_data_size(prop_data_t); + +void * prop_data_data(prop_data_t); +const void * prop_data_data_nocopy(prop_data_t); + +bool prop_data_equals(prop_data_t, prop_data_t); +bool prop_data_equals_data(prop_data_t, const void *, size_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_DATA_H_ */ diff --git a/include/prop_dictionary.h b/include/prop_dictionary.h new file mode 100644 index 0000000..ac4896c --- /dev/null +++ b/include/prop_dictionary.h @@ -0,0 +1,145 @@ +/* $NetBSD: prop_dictionary.h,v 1.9 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_DICTIONARY_H_ +#define _PROPLIB_PROP_DICTIONARY_H_ + +#include +#include +#include + +typedef struct _prop_dictionary *prop_dictionary_t; +typedef struct _prop_dictionary_keysym *prop_dictionary_keysym_t; + +__BEGIN_DECLS +prop_dictionary_t prop_dictionary_create(void); +prop_dictionary_t prop_dictionary_create_with_capacity(unsigned int); + +prop_dictionary_t prop_dictionary_copy(prop_dictionary_t); +prop_dictionary_t prop_dictionary_copy_mutable(prop_dictionary_t); + +unsigned int prop_dictionary_count(prop_dictionary_t); +bool prop_dictionary_ensure_capacity(prop_dictionary_t, + unsigned int); + +void prop_dictionary_make_immutable(prop_dictionary_t); +bool prop_dictionary_mutable(prop_dictionary_t); + +prop_object_iterator_t prop_dictionary_iterator(prop_dictionary_t); +prop_array_t prop_dictionary_all_keys(prop_dictionary_t); + +prop_object_t prop_dictionary_get(prop_dictionary_t, const char *); +bool prop_dictionary_set(prop_dictionary_t, const char *, + prop_object_t); +void prop_dictionary_remove(prop_dictionary_t, const char *); + +prop_object_t prop_dictionary_get_keysym(prop_dictionary_t, + prop_dictionary_keysym_t); +bool prop_dictionary_set_keysym(prop_dictionary_t, + prop_dictionary_keysym_t, + prop_object_t); +void prop_dictionary_remove_keysym(prop_dictionary_t, + prop_dictionary_keysym_t); + +bool prop_dictionary_equals(prop_dictionary_t, prop_dictionary_t); + +char * prop_dictionary_externalize(prop_dictionary_t); +prop_dictionary_t prop_dictionary_internalize(const char *); + +bool prop_dictionary_externalize_to_file(prop_dictionary_t, + const char *); +prop_dictionary_t prop_dictionary_internalize_from_file(const char *); + +const char * prop_dictionary_keysym_cstring_nocopy(prop_dictionary_keysym_t); + +bool prop_dictionary_keysym_equals(prop_dictionary_keysym_t, + prop_dictionary_keysym_t); + +/* + * Utility routines to make it more convenient to work with values + * stored in dictionaries. + */ +bool prop_dictionary_get_bool(prop_dictionary_t, const char *, + bool *); +bool prop_dictionary_set_bool(prop_dictionary_t, const char *, + bool); + +bool prop_dictionary_get_int8(prop_dictionary_t, const char *, + int8_t *); +bool prop_dictionary_get_uint8(prop_dictionary_t, const char *, + uint8_t *); +bool prop_dictionary_set_int8(prop_dictionary_t, const char *, + int8_t); +bool prop_dictionary_set_uint8(prop_dictionary_t, const char *, + uint8_t); + +bool prop_dictionary_get_int16(prop_dictionary_t, const char *, + int16_t *); +bool prop_dictionary_get_uint16(prop_dictionary_t, const char *, + uint16_t *); +bool prop_dictionary_set_int16(prop_dictionary_t, const char *, + int16_t); +bool prop_dictionary_set_uint16(prop_dictionary_t, const char *, + uint16_t); + +bool prop_dictionary_get_int32(prop_dictionary_t, const char *, + int32_t *); +bool prop_dictionary_get_uint32(prop_dictionary_t, const char *, + uint32_t *); +bool prop_dictionary_set_int32(prop_dictionary_t, const char *, + int32_t); +bool prop_dictionary_set_uint32(prop_dictionary_t, const char *, + uint32_t); + +bool prop_dictionary_get_int64(prop_dictionary_t, const char *, + int64_t *); +bool prop_dictionary_get_uint64(prop_dictionary_t, const char *, + uint64_t *); +bool prop_dictionary_set_int64(prop_dictionary_t, const char *, + int64_t); +bool prop_dictionary_set_uint64(prop_dictionary_t, const char *, + uint64_t); + +bool prop_dictionary_get_cstring(prop_dictionary_t, const char *, + char **); +bool prop_dictionary_set_cstring(prop_dictionary_t, const char *, + const char *); + +bool prop_dictionary_get_cstring_nocopy(prop_dictionary_t, + const char *, + const char **); +bool prop_dictionary_set_cstring_nocopy(prop_dictionary_t, + const char *, + const char *); + +__END_DECLS + +#endif /* _PROPLIB_PROP_DICTIONARY_H_ */ diff --git a/include/prop_ingest.h b/include/prop_ingest.h new file mode 100644 index 0000000..f82a57d --- /dev/null +++ b/include/prop_ingest.h @@ -0,0 +1,90 @@ +/* $NetBSD: prop_ingest.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_INGEST_H_ +#define _PROPLIB_PROP_INGEST_H_ + +#include + +typedef enum { + PROP_INGEST_ERROR_NO_ERROR = 0, + PROP_INGEST_ERROR_NO_KEY = 1, + PROP_INGEST_ERROR_WRONG_TYPE = 2, + PROP_INGEST_ERROR_HANDLER_FAILED = 3 +} prop_ingest_error_t; + +typedef enum { + PROP_INGEST_FLAG_OPTIONAL = 0x01 +} prop_ingest_flag_t; + +typedef struct _prop_ingest_context *prop_ingest_context_t; + +typedef bool (*prop_ingest_handler_t)(prop_ingest_context_t, prop_object_t); + +typedef struct { + const char *pite_key; + prop_type_t pite_type; + unsigned int pite_flags; + prop_ingest_handler_t pite_handler; +} prop_ingest_table_entry; + +#define PROP_INGEST(key_, type_, handler_) \ + { .pite_key = key_ , \ + .pite_type = type_ , \ + .pite_flags = 0 , \ + .pite_handler = handler_ } + +#define PROP_INGEST_OPTIONAL(key_, type_, handler_) \ + { .pite_key = key_ , \ + .pite_type = type_ , \ + .pite_flags = PROP_INGEST_FLAG_OPTIONAL , \ + .pite_handler = handler_ } + +#define PROP_INGEST_END \ + { .pite_key = NULL } + +__BEGIN_DECLS +prop_ingest_context_t + prop_ingest_context_alloc(void *); +void prop_ingest_context_free(prop_ingest_context_t); + +prop_ingest_error_t + prop_ingest_context_error(prop_ingest_context_t); +prop_type_t prop_ingest_context_type(prop_ingest_context_t); +const char * prop_ingest_context_key(prop_ingest_context_t); +void * prop_ingest_context_private(prop_ingest_context_t); + +bool prop_dictionary_ingest(prop_dictionary_t, + const prop_ingest_table_entry[], + prop_ingest_context_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_INGEST_H_ */ diff --git a/include/prop_number.h b/include/prop_number.h new file mode 100644 index 0000000..234e0df --- /dev/null +++ b/include/prop_number.h @@ -0,0 +1,57 @@ +/* $NetBSD: prop_number.h,v 1.6 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_NUMBER_H_ +#define _PROPLIB_PROP_NUMBER_H_ + +#include +#include + +typedef struct _prop_number *prop_number_t; + +__BEGIN_DECLS +prop_number_t prop_number_create_integer(int64_t); +prop_number_t prop_number_create_unsigned_integer(uint64_t); + +prop_number_t prop_number_copy(prop_number_t); + +int prop_number_size(prop_number_t); +bool prop_number_unsigned(prop_number_t); + +int64_t prop_number_integer_value(prop_number_t); +uint64_t prop_number_unsigned_integer_value(prop_number_t); + +bool prop_number_equals(prop_number_t, prop_number_t); +bool prop_number_equals_integer(prop_number_t, int64_t); +bool prop_number_equals_unsigned_integer(prop_number_t, uint64_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_NUMBER_H_ */ diff --git a/include/prop_object.h b/include/prop_object.h new file mode 100644 index 0000000..82f9c06 --- /dev/null +++ b/include/prop_object.h @@ -0,0 +1,67 @@ +/* $NetBSD: prop_object.h,v 1.7 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_OBJECT_H_ +#define _PROPLIB_PROP_OBJECT_H_ + +#include +#include + +typedef void *prop_object_t; + +typedef enum { + PROP_TYPE_UNKNOWN = 0x00000000, + PROP_TYPE_BOOL = 0x626f6f6c, /* 'bool' */ + PROP_TYPE_NUMBER = 0x6e6d6272, /* 'nmbr' */ + PROP_TYPE_STRING = 0x73746e67, /* 'stng' */ + PROP_TYPE_DATA = 0x64617461, /* 'data' */ + PROP_TYPE_ARRAY = 0x61726179, /* 'aray' */ + PROP_TYPE_DICTIONARY = 0x64696374, /* 'dict' */ + PROP_TYPE_DICT_KEYSYM = 0x646b6579 /* 'dkey' */ +} prop_type_t; + +__BEGIN_DECLS +void prop_object_retain(prop_object_t); +void prop_object_release(prop_object_t); + +prop_type_t prop_object_type(prop_object_t); + +bool prop_object_equals(prop_object_t, prop_object_t); +bool prop_object_equals_with_error(prop_object_t, prop_object_t, bool *); + +typedef struct _prop_object_iterator *prop_object_iterator_t; + +prop_object_t prop_object_iterator_next(prop_object_iterator_t); +void prop_object_iterator_reset(prop_object_iterator_t); +void prop_object_iterator_release(prop_object_iterator_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_OBJECT_H_ */ diff --git a/include/prop_string.h b/include/prop_string.h new file mode 100644 index 0000000..eb64e87 --- /dev/null +++ b/include/prop_string.h @@ -0,0 +1,60 @@ +/* $NetBSD: prop_string.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_STRING_H_ +#define _PROPLIB_PROP_STRING_H_ + +#include + +typedef struct _prop_string *prop_string_t; + +__BEGIN_DECLS +prop_string_t prop_string_create(void); +prop_string_t prop_string_create_cstring(const char *); +prop_string_t prop_string_create_cstring_nocopy(const char *); + +prop_string_t prop_string_copy(prop_string_t); +prop_string_t prop_string_copy_mutable(prop_string_t); + +size_t prop_string_size(prop_string_t); +bool prop_string_mutable(prop_string_t); + +char * prop_string_cstring(prop_string_t); +const char * prop_string_cstring_nocopy(prop_string_t); + +bool prop_string_append(prop_string_t, prop_string_t); +bool prop_string_append_cstring(prop_string_t, const char *); + +bool prop_string_equals(prop_string_t, prop_string_t); +bool prop_string_equals_cstring(prop_string_t, const char *); +__END_DECLS + +#endif /* _PROPLIB_PROP_STRING_H_ */ diff --git a/include/proplib.h b/include/proplib.h new file mode 100644 index 0000000..74770dd --- /dev/null +++ b/include/proplib.h @@ -0,0 +1,45 @@ +/* $NetBSD: proplib.h,v 1.6 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROPLIB_H_ +#define _PROPLIB_PROPLIB_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#endif /* _PROPLIB_PROPLIB_H_ */ diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..08a37b4 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,3 @@ +man_MANS = prop_array.3 prop_array_util.3 prop_bool.3 prop_data.3 \ + prop_dictionary.3 prop_dictionary_util.3 prop_ingest.3 \ + proplib.3 prop_number.3 prop_object.3 prop_string.3 diff --git a/man/prop_array.3 b/man/prop_array.3 new file mode 100644 index 0000000..8f9ef22 --- /dev/null +++ b/man/prop_array.3 @@ -0,0 +1,285 @@ +.\" $NetBSD: prop_array.3,v 1.8 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 19, 2006 +.Dt PROP_ARRAY 3 +.Os +.Sh NAME +.Nm prop_array , +.Nm prop_array_create , +.Nm prop_array_create_with_capacity , +.Nm prop_array_copy , +.Nm prop_array_copy_mutable , +.Nm prop_array_capacity , +.Nm prop_array_count , +.Nm prop_array_ensure_capacity , +.Nm prop_array_iterator , +.Nm prop_array_make_immutable , +.Nm prop_array_mutable , +.Nm prop_array_get , +.Nm prop_array_set , +.Nm prop_array_add , +.Nm prop_array_remove , +.Nm prop_array_externalize , +.Nm prop_array_internalize , +.Nm prop_array_externalize_to_file , +.Nm prop_array_internalize_from_file , +.Nm prop_array_equals +.Nd array property collection object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_array_t +.Fn prop_array_create "void" +.Ft prop_array_t +.Fn prop_array_create_with_capacity "unsigned int capacity" +.\" +.Ft prop_array_t +.Fn prop_array_copy "prop_array_t array" +.Ft prop_array_t +.Fn prop_array_copy_mutable "prop_array_t array" +.\" +.Ft unsigned int +.Fn prop_array_capacity "prop_array_t array" +.Ft unsigned int +.Fn prop_array_count "prop_array_t array" +.Ft bool +.Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity" +.\" +.Ft prop_object_iterator_t +.Fn prop_array_iterator "prop_array_t array" +.\" +.Ft void +.Fn prop_array_make_immutable "prop_array_t array" +.Ft bool +.Fn prop_array_mutable "prop_array_t array" +.\" +.Ft prop_object_t +.Fn prop_array_get "prop_array_t array" "unsigned int index" +.Ft bool +.Fn prop_array_set "prop_array_t array" "unsigned int index" "prop_object_t obj" +.Ft bool +.Fn prop_array_add "prop_array_t array" "prop_object_t obj" +.Ft void +.Fn prop_array_remove "prop_array_t array" "unsigned int index" +.\" +.Ft char * +.Fn prop_array_externalize "prop_array_t array" +.Ft prop_array_t +.Fn prop_array_internalize "const char *xml" +.\" +.Ft bool +.Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" +.Ft prop_array_t +.Fn prop_array_internalize_from_file "const char *path" +.\" +.Ft bool +.Fn prop_array_equals "prop_array_t array1" "prop_array_t array2" +.Sh DESCRIPTION +The +.Nm prop_array +family of functions operate on the array property collection object type. +An array is an ordered set; an iterated array will return objects in the +same order with which they were stored. +.Bl -tag -width "xxxxx" +.It Fn prop_array_create "void" +Create an empty array. +The array initially has no capacity. +Returns +.Dv NULL +on failure. +.It Fn prop_array_create_with_capacity "unsigned int capacity" +Create an array with the capacity to store +.Fa capacity +objects. +Returns +.Dv NULL +on failure. +.It Fn prop_array_copy "prop_array_t array" +Copy an array. +The new array has an initial capacity equal to the number of objects stored +in the array being copied. +The new array contains references to the original array's objects, not +copies of those objects +.Pq i.e. a shallow copy is made . +If the original array is immutable, the resulting array is also immutable. +Returns +.Dv NULL +on failure. +.It Fn prop_array_copy_mutable "prop_array_t array" +Like +.Fn prop_array_copy , +except the resulting array is always mutable. +.It Fn prop_array_capacity "prop_array_t array" +Returns the total capacity of the array, including objects already stored +in the array. +If the supplied object isn't an array, zero is returned. +.It Fn prop_array_count "prop_array_t array" +Returns the number of objects stored in the array. +If the supplied object isn't an array, zero is returned. +.It Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity" +Ensure that the array has a total capacity of +.Fa capacity , +including objects already stored in the array. +Returns +.Dv true +if the capacity of the array is greater or equal to +.Fa capacity +or if expansion of the array's capacity was successful +and +.Dv false +otherwise. +.It Fn prop_array_iterator "prop_array_t array" +Create an iterator for the array. +The array is retained by the iterator. +An array iterator returns the object references stored in the array. +Storing to or removing from the array invalidates any active iterators for +the array. +Returns +.Dv NULL +on failure. +.It Fn prop_array_make_immutable "prop_array_t array" +Make +.Fa array +immutable. +.It Fn prop_array_mutable "prop_array_t array" +Returns +.Dv true +if the array is mutable. +.It Fn prop_array_get "prop_array_t array" "unsigned int index" +Return the object stored at the array index +.Fa index . +Returns +.Dv NULL +on failure. +.It Fn prop_array_set "prop_array_t array" "unsigned int index" \ + "prop_object_t obj" +Store a reference to the object +.Fa obj +at the array index +.Fa index . +This function is not allowed to create holes in the array; +the caller must either be setting the object just beyond the existing +count or replacing an already existing object reference. +The object will be retained by the array. +If an existing object reference is being replaced, that object will be +released. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.It Fn prop_array_add "prop_array_t array" "prop_object_t obj" +Add a reference to the object +.Fa obj +to the array, appending to the end and growing the array's capacity if +necessary. +The object will be retained by the array. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.Pp +During expansion, array's capacity is augmented by the +.Dv EXPAND_STEP +constant, as defined in +.Pa libprop/prop_array.c +file, e.g. +.Pp +#define EXPAND_STEP 16 +.It Fn prop_array_remove "prop_array_t array" "unsigned int index" +Remove the reference to the object stored at array index +.Fa index . +The object will be released and the array compacted following +the removal. +.It Fn prop_array_equals "prop_array_t array1" "prop_array_t array2" +Returns +.Dv true +if the two arrays are equivalent. +If at least one of the supplied objects isn't an array, +.Dv false +is returned. +Note: Objects contained in the array are compared by value, not by reference. +.It Fn prop_array_externalize "prop_array_t array" +Externalizes an array, returning a NUL-terminated buffer containing +the XML representation of the array. +The caller is responsible for freeing the returned buffer. +If converting to the external representation fails for any reason, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_array_internalize "const char *xml" +Parse the XML representation of a property list in the NUL-terminated +buffer +.Fa xml +and return the corresponding array. +Returns +.Dv NULL +if parsing fails for any reason. +.It Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" +Externalizes an array and writes it to the file specified by +.Fa path . +The file is saved with the mode +.Dv 0666 +as modified by the process's file creation mask +.Pq see Xr umask 3 +and is written atomically. +Returns +.Dv false +if externalizing or writing the array fails for any reason. +.It Fn prop_array_internalize_from_file "const char *path" +Reads the XML property list contained in the file specified by +.Fa path , +internalizes it, and returns the corresponding array. +Returns +.Dv NULL +on failure. +.El +.Sh SEE ALSO +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_array_util.3 b/man/prop_array_util.3 new file mode 100644 index 0000000..27561a7 --- /dev/null +++ b/man/prop_array_util.3 @@ -0,0 +1,218 @@ +.\" $NetBSD: prop_array_util.3,v 1.3 2008/09/11 13:15:13 haad Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 2, 2008 +.Dt PROP_ARRAY_UTIL 3 +.Os +.Sh NAME +.Nm prop_array_util , +.Nm prop_array_get_bool , +.Nm prop_array_set_bool , +.Nm prop_array_get_int8 , +.Nm prop_array_get_uint8 , +.Nm prop_array_set_int8 , +.Nm prop_array_set_uint8 , +.Nm prop_array_get_int16 , +.Nm prop_array_get_uint16 , +.Nm prop_array_set_int16 , +.Nm prop_array_set_uint16 , +.Nm prop_array_get_int32 , +.Nm prop_array_get_uint32 , +.Nm prop_array_set_int32 , +.Nm prop_array_set_uint32 , +.Nm prop_array_get_int64 , +.Nm prop_array_get_uint64 , +.Nm prop_array_set_int64 , +.Nm prop_array_set_uint64 , +.Nm prop_array_add_int8 , +.Nm prop_array_add_uint8 , +.Nm prop_array_add_int16 , +.Nm prop_array_add_uint16 , +.Nm prop_array_add_int32 , +.Nm prop_array_add_uint32 , +.Nm prop_array_add_int64 , +.Nm prop_array_add_uint64 , +.Nm prop_array_get_cstring , +.Nm prop_array_set_cstring , +.Nm prop_array_get_cstring_nocopy , +.Nm prop_array_set_cstring_nocopy +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft bool +.Fn prop_array_get_bool "prop_array_t dict" "unsigned int indx" \ + "bool *valp" +.Ft bool +.Fn prop_array_set_bool "prop_array_t dict" "unsigned int indx" \ + "bool val" +.\" +.Ft bool +.Fn prop_array_get_int8 "prop_array_t dict" "unsigned int indx" \ + "int8_t *valp" +.Ft bool +.Fn prop_array_get_uint8 "prop_array_t dict" "unsigned int indx" \ + "uint8_t *valp" +.Ft bool +.Fn prop_array_set_int8 "prop_array_t dict" "unsigned int indx" \ + "int8_t val" +.Ft bool +.Fn prop_array_set_uint8 "prop_array_t dict" "unsigned int indx" \ + "uint8_t val" +.\" +.Ft bool +.Fn prop_array_get_int16 "prop_array_t dict" "unsigned int indx" \ + "int16_t *valp" +.Ft bool +.Fn prop_array_get_uint16 "prop_array_t dict" "unsigned int indx" \ + "uint16_t *valp" +.Ft bool +.Fn prop_array_set_int16 "prop_array_t dict" "unsigned int indx" \ + "int16_t val" +.Ft bool +.Fn prop_array_set_uint16 "prop_array_t dict" "unsigned int indx" \ + "uint16_t val" +.\" +.Ft bool +.Fn prop_array_get_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t *valp" +.Ft bool +.Fn prop_array_get_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t *valp" +.Ft bool +.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t val" +.Ft bool +.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_array_get_int64 "prop_array_t dict" "unsigned int indx" \ + "int64_t *valp" +.Ft bool +.Fn prop_array_get_uint64 "prop_array_t dict" "unsigned int indx" \ + "uint64_t *valp" +.Ft bool +.Fn prop_array_set_int64 "prop_array_t dict" "unsigned int indx" \ + "int64_t val" +.Ft bool +.Fn prop_array_set_uint64 "prop_array_t dict" "unsigned int indx" \ + "uint64_t val" +.\" +.Ft bool +.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t val" +.Ft bool +.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_array_add_int8 "prop_array_t dict" "int8_t val" +.Ft bool +.Fn prop_array_add_uint8 "prop_array_t dict" "uint8_t val" +.Ft bool +.Fn prop_array_add_int16 "prop_array_t dict" "int16_t val" +.Ft bool +.Fn prop_array_add_uint16 "prop_array_t dict" "uint16_t val" +.Ft bool +.Fn prop_array_add_int32 "prop_array_t dict" "int32_t val" +.Ft bool +.Fn prop_array_add_uint32 "prop_array_t dict" "uint32_t val" +.Ft bool +.Fn prop_array_add_int64 "prop_array_t dict" "int64_t val" +.Ft bool +.Fn prop_array_add_uint64 "prop_array_t dict" "uint64_t val" +.\" +.Ft bool +.Fn prop_array_get_cstring "prop_array_t dict" "unsigned int indx" \ + "char **strp" +.Ft bool +.Fn prop_array_set_cstring "prop_array_t dict" "unsigned int indx" \ + "const char *str" +.\" +.Ft bool +.Fn prop_array_get_cstring_nocopy "prop_array_t dict" \ + "unsigned int indx" "const char **strp" +.Ft bool +.Fn prop_array_set_cstring_nocopy "prop_array_t dict" \ + "unsigned int indx" "const char *strp" +.Sh DESCRIPTION +The +.Nm prop_array_util +family of functions are provided to make getting and setting values in +arrays more convenient in some applications. +.Pp +The getters check the type of the returned object and, in some cases, also +ensure that the returned value is within the range implied by the getter's +value type. +.Pp +The setters handle object creation and release for the caller. +.Pp +The +.Fn prop_array_get_cstring +function returns dynamically allocated memory. +See +.Xr prop_string 3 +for more information. +.Pp +The +.Fn prop_array_get_cstring_nocopy +and +.Fn prop_array_set_cstring_nocopy +functions do not copy the string that is set or returned. +See +.Xr prop_string 3 +for more information. +.Sh RETURN VALUES +The +.Nm prop_array_util +getter functions return +.Dv true +if the object exists in the array and the value is in-range, or +.Dv false +otherwise. +.Pp +The +.Nm prop_array_util +setter functions return +.Dv true +if creating the object and storing it in the array is successful, or +.Dv false +otherwise. +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_number 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_bool.3 b/man/prop_bool.3 new file mode 100644 index 0000000..f56382d --- /dev/null +++ b/man/prop_bool.3 @@ -0,0 +1,82 @@ +.\" $NetBSD: prop_bool.3,v 1.6 2008/08/03 03:11:28 thorpej Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 22, 2006 +.Dt PROP_BOOL 3 +.Os +.Sh NAME +.Nm prop_bool , +.Nm prop_bool_create , +.Nm prop_bool_copy , +.Nm prop_bool_true +.Nd boolean value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_bool_t +.Fn prop_bool_create "bool val" +.Ft prop_bool_t +.Fn prop_bool_copy "prop_bool_t bool" +.\" +.Ft bool +.Fn prop_bool_true "prop_bool_t bool" +.Sh DESCRIPTION +The +.Nm prop_bool +family of functions operate on a boolean value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_bool_create "bool val" +Create a boolean value object with the value +.Fa val . +.It Fn prop_bool_copy "prop_bool_t bool" +Copy a boolean value object. +If the supplied object isn't a boolean, +.Dv NULL +is returned. +.It Fn prop_bool_true "prop_bool_t bool" +Returns the value of the boolean value object. +If the supplied object isn't a boolean, +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_data.3 b/man/prop_data.3 new file mode 100644 index 0000000..16e2f6a --- /dev/null +++ b/man/prop_data.3 @@ -0,0 +1,148 @@ +.\" $NetBSD: prop_data.3,v 1.6 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 22, 2006 +.Dt PROP_DATA 3 +.Os +.Sh NAME +.Nm prop_data , +.Nm prop_data_create_data , +.Nm prop_data_create_data_nocopy , +.Nm prop_data_copy , +.Nm prop_data_size , +.Nm prop_data_data , +.Nm prop_data_data_nocopy , +.Nm prop_data_equals , +.Nm prop_data_equals_data +.Nd opaque data value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_data_t +.Fn prop_data_create_data "const void *blob" "size_t len" +.Ft prop_data_t +.Fn prop_data_create_data_nocopy "const void *blob" "size_t len" +.\" +.Ft prop_data_t +.Fn prop_data_copy "prop_data_t data" +.\" +.Ft void * +.Fn prop_data_data "prop_data_t data" +.Ft size_t +.Fn prop_data_size "prop_data_t data" +.Ft const void * +.Fn prop_data_data_nocopy "prop_data_t data" +.\" +.Ft bool +.Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2" +.Ft bool +.Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len" +.Sh DESCRIPTION +The +.Nm prop_data +family of functions operate on an opaque data value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_data_create_data "const void *blob" "size_t len" +Create a data object that contains a copy of +.Fa blob +with size +.Fa len . +Returns +.Dv NULL +on failure. +.It Fn prop_data_create_data_nocopy "const void *blob" "size_t len" +Create a data object that contains a reference to +.Fa blob +with size +.Fa len . +Returns +.Dv NULL +on failure. +.It Fn prop_data_copy "prop_data_t data" +Copy a data object. +If the data object being copied is an external data reference, +then the copy also references the same external data. +Returns +.Dv NULL +on failure. +.It Fn prop_data_size "prop_data_t data" +Returns the size of the data object. +If the supplied object isn't a data object, zero is returned. +.It Fn prop_data_data "prop_data_t data" +Returns a copy of the data object's contents. +The caller is responsible for freeing the returned buffer. +If the supplied object isn't a data object or +if the data container is empty, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_data_data_nocopy "prop_data_t data" +Returns an immutable reference to the contents of the data object. +If the supplied object isn't a data object, +.Dv NULL +is returned. +.It Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2" +Returns +.Dv true +if the two data objects are equivalent. +If at least one of the supplied objects isn't a data object, +.Dv false +is returned. +.It Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len" +Returns +.Dv true +if the data object's value is equivalent to +.Fa blob +with size +.Fa len . +If the supplied object isn't a data object, +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_dictionary.3 b/man/prop_dictionary.3 new file mode 100644 index 0000000..77a6b7e --- /dev/null +++ b/man/prop_dictionary.3 @@ -0,0 +1,328 @@ +.\" $NetBSD: prop_dictionary.3,v 1.13 2008/05/06 17:23:38 xtraeme Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 6, 2008 +.Dt PROP_DICTIONARY 3 +.Os +.Sh NAME +.Nm prop_dictionary , +.Nm prop_dictionary_create , +.Nm prop_dictionary_create_with_capacity , +.Nm prop_dictionary_copy , +.Nm prop_dictionary_copy_mutable , +.Nm prop_dictionary_count , +.Nm prop_dictionary_ensure_capacity , +.Nm prop_dictionary_iterator , +.Nm prop_dictionary_all_keys , +.Nm prop_dictionary_make_immutable , +.Nm prop_dictionary_mutable , +.Nm prop_dictionary_get , +.Nm prop_dictionary_set , +.Nm prop_dictionary_remove , +.Nm prop_dictionary_get_keysym , +.Nm prop_dictionary_set_keysym , +.Nm prop_dictionary_remove_keysym , +.Nm prop_dictionary_externalize , +.Nm prop_dictionary_internalize , +.Nm prop_dictionary_externalize_to_file , +.Nm prop_dictionary_internalize_from_file , +.Nm prop_dictionary_equals , +.Nm prop_dictionary_keysym_cstring_nocopy , +.Nm prop_dictionary_keysym_equals +.Nd dictionary property collection object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_dictionary_t +.Fn prop_dictionary_create "void" +.Ft prop_dictionary_t +.Fn prop_dictionary_create_with_capacity "unsigned int capacity" +.\" +.Ft prop_dictionary_t +.Fn prop_dictionary_copy "prop_dictionary_t dict" +.Ft prop_dictionary_t +.Fn prop_dictionary_copy_mutable "prop_dictionary_t dict" +.\" +.Ft unsigned int +.Fn prop_dictionary_count "prop_dictionary_t dict" +.Ft bool +.Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" \ + "unsigned int capacity" +.\" +.Ft prop_object_iterator_t +.Fn prop_dictionary_iterator "prop_dictionary_t dict" +.Ft prop_array_t +.Fn prop_dictionary_all_keys "prop_dictionary_t dict" +.\" +.Ft void +.Fn prop_dictionary_make_immutable "prop_dictionary_t dict" +.Ft bool +.Fn prop_dictionary_mutable "prop_dictionary_t dict" +.\" +.Ft prop_object_t +.Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key" +.Ft bool +.Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \ + "prop_object_t obj" +.Ft void +.Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key" +.\" +.Ft prop_object_t +.Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" +.Ft bool +.Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" "prop_object_t obj" +.Ft void +.Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" +.\" +.Ft bool +.Fn prop_dictionary_equals "prop_dictionary_t dict1" "prop_dictionary_t dict2" +.\" +.Ft const char * +.Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t sym" +.\" +.Ft bool +.Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \ + "prop_dictionary_keysym_t keysym2" +.\" +.Ft char * +.Fn prop_dictionary_externalize "prop_dictionary_t dict" +.Ft prop_dictionary_t +.Fn prop_dictionary_internalize "const char *xml" +.\" +.Ft bool +.Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \ + "const char *path" +.Ft prop_dictionary_t +.Fn prop_dictionary_internalize_from_file "const char *path" +.\" +.Sh DESCRIPTION +The +.Nm prop_dictionary +family of functions operate on the dictionary property collection object type. +A dictionary is an unordered set of objects stored as key-value pairs. +.Bl -tag -width "xxxxx" +.It Fn prop_dictionary_create "void" +Create an empty dictionary. +The dictionary initially has no capacity. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_create_with_capacity "unsigned int capacity" +Create a dictionary with the capacity to store +.Fa capacity +objects. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_copy "prop_dictionary_t dict" +Copy a dictionary. +The new dictionary has an initial capacity equal to the number of objects +stored in the dictionary being copied. +The new dictionary contains references to the original dictionary's objects, +not copies of those objects +.Pq i.e. a shallow copy is made . +If the original dictionary is immutable, the resulting dictionary is also +immutable. +.It Fn prop_dictionary_copy_mutable "prop_dictionary_t dict" +Like +.Fn prop_dictionary_copy , +except the resulting dictionary is always mutable. +.It Fn prop_dictionary_count "prop_dictionary_t dict" +Returns the number of objects stored in the dictionary. +.It Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" +Ensure that the dictionary has a total capacity of +.Fa capacity , +including objects already stored in the dictionary. +Returns +.Dv true +if the capacity of the dictionary is greater or equal to +.Fa capacity +or if the expansion of the dictionary's capacity was successful +and +.Dv false +otherwise. +If the supplied object isn't a dictionary, +.Dv false +is returned. +.It Fn prop_dictionary_iterator "prop_dictionary_t dict" +Create an iterator for the dictionary. +The dictionary is retained by the iterator. +A dictionary iterator returns the key symbols used to look up objects stored +in the dictionary; to get the object itself, a dictionary lookup using this +key symbol must be performed. +Storing to or removing from the dictionary invalidates any active iterators for +the dictionary. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_all_keys "prop_dictionary_t dict" +Return an array of all of the dictionary key symbols +.Pq prop_dictionary_keysym_t +in the dictionary. +This provides a way to iterate over the items in the dictionary while +retaining the ability to mutate the dictionary; instead of iterating +over the dictionary itself, iterate over the array of keys. +The caller is responsible for releasing the array. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_make_immutable "prop_dictionary_t dict" +Make +.Fa dict +immutable. +.It Fn prop_dictionary_mutable "prop_dictionary_t dict" +Returns +.Dv true +if the dictionary is mutable. +.It Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key" +Return the object stored in the dictionary with the key +.Fa key . +If no object is stored with the specified key, +.Dv NULL +is returned. +.It Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \ + "prop_object_t obj" +Store a reference to the object +.Fa obj +with the key +.Fa key . +The object will be retained by the dictionary. +If the key already exists in the dictionary, the object associated with +that key will be released and replaced with the new object. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.It Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key" +Remove the reference to the object stored in the dictionary with the key +.Fa key . +The object will be released. +.It Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" +Like +.Fn prop_dictionary_get , +but the lookup is performed using a key symbol returned by a dictionary +iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" "prop_object_t obj" +Like +.Fn prop_dictionary_set , +but the lookup of the object to replace is performed using a key symbol +returned by a dictionary iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" +Like +.Fn prop_dictionary_remove , +but the lookup of the object to remove is performed using a key symbol +returned by a dictionary iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_equals "prop_dictionary_t dict1" \ + "prop_dictionary_t dict2" +Returns +.Dv true +if the two dictionaries are equivalent. +Note: Objects contained in the dictionary are compared by value, not by +reference. +.It Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t keysym" +Returns an immutable reference to the dictionary key symbol's string value. +.It Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \ + "prop_dictionary_keysym_t keysym2" +Returns +.Dv true +if the two dictionary key symbols are equivalent. +.It Fn prop_dictionary_externalize "prop_dictionary_t dict" +Externalizes a dictionary, returning a NUL-terminated buffer containing +the XML representation of the dictionary. +The caller is responsible for freeing the returned buffer. +If converting to the external representation fails for any reason, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_dictionary_internalize "const char *xml" +Parse the XML representation of a property list in the NUL-terminated +buffer +.Fa xml +and return the corresponding dictionary. +Returns +.Dv NULL +if parsing fails for any reason. +.It Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \ + "const char *path" +Externalizes a dictionary and writes it to the file specified by +.Fa path . +The file is saved with the mode +.Dv 0666 +as modified by the process's file creation mask +.Pq see Xr umask 3 +and is written atomically. +Returns +.Dv false +if externalizing or writing the dictionary fails for any reason. +.It Fn prop_dictionary_internalize_from_file "const char *path" +Reads the XML property list contained in the file specified by +.Fa path , +internalizes it, and returns the corresponding array. +Returns +.Dv NULL +on failure. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary_util 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_dictionary_util.3 b/man/prop_dictionary_util.3 new file mode 100644 index 0000000..2eb7694 --- /dev/null +++ b/man/prop_dictionary_util.3 @@ -0,0 +1,186 @@ +.\" $NetBSD: prop_dictionary_util.3,v 1.4 2008/06/02 09:27:04 haad Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd October 25, 2006 +.Dt PROP_DICTIONARY_UTIL 3 +.Os +.Sh NAME +.Nm prop_dictionary_util , +.Nm prop_dictionary_get_bool , +.Nm prop_dictionary_set_bool , +.Nm prop_dictionary_get_int8 , +.Nm prop_dictionary_get_uint8 , +.Nm prop_dictionary_set_int8 , +.Nm prop_dictionary_set_uint8 , +.Nm prop_dictionary_get_int16 , +.Nm prop_dictionary_get_uint16 , +.Nm prop_dictionary_set_int16 , +.Nm prop_dictionary_set_uint16 , +.Nm prop_dictionary_get_int32 , +.Nm prop_dictionary_get_uint32 , +.Nm prop_dictionary_set_int32 , +.Nm prop_dictionary_set_uint32 , +.Nm prop_dictionary_get_int64 , +.Nm prop_dictionary_get_uint64 , +.Nm prop_dictionary_set_int64 , +.Nm prop_dictionary_set_uint64 , +.Nm prop_dictionary_get_cstring , +.Nm prop_dictionary_set_cstring , +.Nm prop_dictionary_get_cstring_nocopy , +.Nm prop_dictionary_set_cstring_nocopy +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft bool +.Fn prop_dictionary_get_bool "prop_dictionary_t dict" "const char *key" \ + "bool *valp" +.Ft bool +.Fn prop_dictionary_set_bool "prop_dictionary_t dict" "const char *key" \ + "bool val" +.\" +.Ft bool +.Fn prop_dictionary_get_int8 "prop_dictionary_t dict" "const char *key" \ + "int8_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint8 "prop_dictionary_t dict" "const char *key" \ + "uint8_t *valp" +.Ft bool +.Fn prop_dictionary_set_int8 "prop_dictionary_t dict" "const char *key" \ + "int8_t val" +.Ft bool +.Fn prop_dictionary_set_uint8 "prop_dictionary_t dict" "const char *key" \ + "uint8_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int16 "prop_dictionary_t dict" "const char *key" \ + "int16_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint16 "prop_dictionary_t dict" "const char *key" \ + "uint16_t *valp" +.Ft bool +.Fn prop_dictionary_set_int16 "prop_dictionary_t dict" "const char *key" \ + "int16_t val" +.Ft bool +.Fn prop_dictionary_set_uint16 "prop_dictionary_t dict" "const char *key" \ + "uint16_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int32 "prop_dictionary_t dict" "const char *key" \ + "int32_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint32 "prop_dictionary_t dict" "const char *key" \ + "uint32_t *valp" +.Ft bool +.Fn prop_dictionary_set_int32 "prop_dictionary_t dict" "const char *key" \ + "int32_t val" +.Ft bool +.Fn prop_dictionary_set_uint32 "prop_dictionary_t dict" "const char *key" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int64 "prop_dictionary_t dict" "const char *key" \ + "int64_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint64 "prop_dictionary_t dict" "const char *key" \ + "uint64_t *valp" +.Ft bool +.Fn prop_dictionary_set_int64 "prop_dictionary_t dict" "const char *key" \ + "int64_t val" +.Ft bool +.Fn prop_dictionary_set_uint64 "prop_dictionary_t dict" "const char *key" \ + "uint64_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_cstring "prop_dictionary_t dict" "const char *key" \ + "char **strp" +.Ft bool +.Fn prop_dictionary_set_cstring "prop_dictionary_t dict" "const char *key" \ + "const char *str" +.\" +.Ft bool +.Fn prop_dictionary_get_cstring_nocopy "prop_dictionary_t dict" \ + "const char *key" "const char **strp" +.Ft bool +.Fn prop_dictionary_set_cstring_nocopy "prop_dictionary_t dict" \ + "const char *key" "const char *strp" +.Sh DESCRIPTION +The +.Nm prop_dictionary_util +family of functions are provided to make getting and setting values in +dictionaries more convenient in some applications. +.Pp +The getters check the type of the returned object and, in some cases, also +ensure that the returned value is within the range implied by the getter's +value type. +.Pp +The setters handle object creation and release for the caller. +.Pp +The +.Fn prop_dictionary_get_cstring +function returns dynamically allocated memory. +See +.Xr prop_string 3 +for more information. +.Pp +The +.Fn prop_dictionary_get_cstring_nocopy +and +.Fn prop_dictionary_set_cstring_nocopy +functions do not copy the string that is set or returned. +See +.Xr prop_string 3 +for more information. +.Sh RETURN VALUES +The +.Nm prop_dictionary_util +getter functions return +.Dv true +if the object exists in the dictionary and the value is in-range, or +.Dv false +otherwise. +.Pp +The +.Nm prop_dictionary_util +setter functions return +.Dv true +if creating the object and storing it in the dictionary is successful, or +.Dv false +otherwise. +.Sh SEE ALSO +.Xr prop_bool 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_ingest.3 b/man/prop_ingest.3 new file mode 100644 index 0000000..307ad8d --- /dev/null +++ b/man/prop_ingest.3 @@ -0,0 +1,181 @@ +.\" $NetBSD: prop_ingest.3,v 1.5 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_INGEST 3 +.Os +.Sh NAME +.Nm prop_ingest_context_alloc , +.Nm prop_ingest_context_free , +.Nm prop_ingest_context_error , +.Nm prop_ingest_context_type , +.Nm prop_ingest_context_key , +.Nm prop_ingest_context_private , +.Nm prop_dictionary_ingest +.Nd Ingest a dictionary into an arbitrary binary format +.Sh SYNOPSIS +.In prop/proplib.h +.Ft prop_ingest_context_t +.Fn prop_ingest_context_alloc "void *private" +.Ft void +.Fn prop_ingest_context_free "prop_ingest_context_t ctx" +.Ft prop_ingest_error_t +.Fn prop_ingest_context_error "prop_ingest_context_t ctx" +.Ft prop_type_t +.Fn prop_ingest_context_type "prop_ingest_context_t ctx" +.Ft const char * +.Fn prop_ingest_context_key "prop_ingest_context_t ctx" +.Ft void * +.Fn prop_ingest_context_private "prop_ingest_context_t ctx" +.Ft bool +.Fn prop_dictionary_ingest "prop_dictionary_t dict" \ + "const prop_ingest_table_entry rules[]" \ + "prop_ingest_context_t ctx" +.Pp +.Ft typedef bool +.Fn (*prop_ingest_handler_t) "prop_ingest_context_t" "prop_object_t" +.Sh DESCRIPTION +The +.Nm prop_dictionary_ingest +function provides a convenient way to convert a property list into +an arbitrary binary format or to extract values from dictionaries in a +way that is convenient to an application +.Pq for configuration files, for example . +.Pp +.Nm prop_dictionary_ingest +is driven by a table of rules provided by the application. +Each rule consists of three items: +.Bl -bullet +.It +A C string containing a key to be looked up in the dictionary. +.It +The expected property type of the object associated with the key +(or +.Dv PROP_TYPE_UNKNOWN +to specify that any type is allowed). +.It +A callback function of type +.Dv prop_ingest_handler_t +that will perform the translation for the application. +.El +.Pp +The table is constructed using a series of macros as follows: +.Bd -literal +static const prop_ingest_table_entry ingest_rules[] = { + PROP_INGEST("file-name", PROP_TYPE_STRING, ingest_filename), + PROP_INGEST("count", PROP_TYPE_NUMBER, ingest_count), + PROP_INGEST_OPTIONAL("required", PROP_TYPE_BOOL, ingest_required), + PROP_INGEST_OPTIONAL("extra", PROP_TYPE_UNKNOWN, ingest_extra), + PROP_INGEST_END +}; +.Ed +.Pp +The +.Dv PROP_INGEST +macro specifies that the key is required to be present in the dictionary. +The +.Dv PROP_INGEST_OPTIONAL +macro specifies that the presence of the key in the dictionary is optional. +The +.Dv PROP_INGEST_END +macro marks the end of the rules table. +.Pp +In each case, +.Nm prop_dictionary_ingest +looks up the rule's key in the dictionary. +If an object is present in the dictionary at that key, its type is checked +against the type specified in the rule. +A type specification of +.Dv PROP_TYPE_UNKNOWN +allows the object to be of any type. +If the object does not exist and the rule is not marked as optional, then +an error is returned. +Otherwise, the handler specified in the rule is invoked with the ingest +context and the object +(or +.Dv NULL +if the key does not exist in the dictionary). +The handler should return +.Dv false +if the value of the object is invalid to indicate failure and +.Dv true +otherwise. +.Pp +The ingest context contains several pieces of information that are +useful during the ingest process. +The context also provides specific error information should the ingest +fail. +.Bl -tag -width "xxxxx" +.It Fn prop_ingest_context_alloc "void *private" +Allocate an ingest context. +The argument +.Fa private +may be used to pass application-specific context to the ingest handlers. +Note that an ingest context can be re-used to perform multiple ingests. +Returns +.Dv NULL +on failure. +.It Fn prop_ingest_context_free "prop_ingest_context_t ctx" +Free an ingest context. +.It Fn prop_ingest_context_error "prop_ingest_context_t ctx" +Returns the code indicating the error encountered during ingest. +The following error codes are defined: +.Pp +.Bl -tag -width "PROP_INGEST_ERROR_HANDLER_FAILED" -compact +.It Dv PROP_INGEST_ERROR_NO_ERROR +No error was encountered during ingest. +.It Dv PROP_INGEST_ERROR_NO_KEY +A non-optional key was not found in the dictionary. +.It Dv PROP_INGEST_ERROR_WRONG_TYPE +An object in the dictionary was not the same type specifed in the rules. +.It Dv PROP_INGEST_ERROR_HANDLER_FAILED +An object's handler returned +.Dv false . +.El +.Pp +.It Fn prop_ingest_context_type "prop_ingest_context_t ctx" +Returns the type of the last object visited during an ingest. +When called by an ingest handler, it returns the type of the object +currently being processed. +.It Fn prop_ingest_context_key "prop_ingest_context_t ctx" +Returns the last dictionary key looked up during an ingest. +When called by an ingest handler, it returns the dictionary key corresponding +to the object currently being processed. +.It Fn prop_ingest_context_private "prop_ingest_context_t ctx" +Returns the private data set when the context was allocated with +.Fn prop_ingest_context_alloc . +.El +.Sh SEE ALSO +.Xr prop_dictionary 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_number.3 b/man/prop_number.3 new file mode 100644 index 0000000..5082a1f --- /dev/null +++ b/man/prop_number.3 @@ -0,0 +1,204 @@ +.\" $NetBSD: prop_number.3,v 1.9 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_NUMBER 3 +.Os +.Sh NAME +.Nm prop_number , +.Nm prop_number_create_integer , +.Nm prop_number_create_unsigned_integer , +.Nm prop_number_copy , +.Nm prop_number_size , +.Nm prop_number_unsigned , +.Nm prop_number_integer_value , +.Nm prop_number_unsigned_integer_value , +.Nm prop_number_equals , +.Nm prop_number_equals_integer , +.Nm prop_number_equals_unsigned_integer +.Nd numeric value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_number_t +.Fn prop_number_create_integer "int64_t val" +.Ft prop_number_t +.Fn prop_number_create_unsigned_integer "uint64_t val" +.Ft prop_number_t +.Fn prop_number_copy "prop_number_t number" +.\" +.Ft int +.Fn prop_number_size "prop_number_t number" +.Ft bool +.Fn prop_number_unsigned "prop_number_t number" +.Ft int64_t +.Fn prop_number_integer_value "prop_number_t number" +.Ft uint64_t +.Fn prop_number_unsigned_integer_value "prop_number_t number" +.\" +.Ft bool +.Fn prop_number_equals "prop_number_t num1" "prop_number_t num2" +.Ft bool +.Fn prop_number_equals_integer "prop_number_t number" "int64_t val" +.Ft bool +.Fn prop_number_equals_unsigned_integer "prop_number_t number" "uint64_t val" +.Sh DESCRIPTION +The +.Nm prop_number +family of functions operate on a numeric value property object type. +Values are either signed or unsigned, and promoted to a 64-bit type +.Pq int64_t or uint64_t , respectively . +.Pp +It is possible to compare number objects that differ in sign. +Such comparisons first test to see if each object is within the valid +number range of the other: +.Bl -bullet +.It +Signed numbers that are greater than or equal to 0 can be compared to +unsigned numbers. +.It +Unsigned numbers that are less than or equal to the largest signed 64-bit +value +.Pq Dv INT64_MAX +can be compared to signed numbers. +.El +.Pp +Number objects have a different externalized representation depending +on their sign: +.Bl -bullet +.It +Signed numbers are externalized in base-10 +.Pq decimal . +.It +Unsigned numbers are externalized in base-16 +.Pq hexadecimal . +.El +.Pp +When numbers are internalized, the sign of the resulting number object +.Pq and thus its valid range +is determined by a set of rules evaluated in the following order: +.Bl -bullet +.It +If the first character of the number is a +.Sq - +then the number is signed. +.It +If the first two characters of the number are +.Sq 0x +then the number is unsigned. +.It +If the number value fits into the range of a signed number then the +number is signed. +.It +In all other cases, the number is unsigned. +.El +.Bl -tag -width "xxxxx" +.It Fn prop_number_create_integer "int64_t val" +Create a numeric value object with the signed value +.Fa val . +Returns +.Dv NULL +on failure. +.It Fn prop_number_create_unsigned_integer "uint64_t val" +Create a numeric value object with the unsigned value +.Fa val . +Returns +.Dv NULL +on failure. +.It Fn prop_number_copy "prop_number_t number" +Copy a numeric value object. +If the supplied object isn't a numeric value, +.Dv NULL +is returned. +.It Fn prop_number_size "prop_number_t number" +Returns 8, 16, 32, or 64, representing the number of bits required to +hold the value of the object. +If the supplied object isn't a numeric value, +.Dv NULL +is returned. +.It Fn prop_number_unsigned "prop_number_t number" +Returns +.Dv true +if the numeric value object has an unsigned value. +.It Fn prop_number_integer_value "prop_number_t number" +Returns the signed integer value of the numeric value object. +If the supplied object isn't a numeric value, zero is returned. Thus, +it is not possible to distinguish between ``not a prop_number_t'' +and ``prop_number_t has a value of 0''. +.It Fn prop_number_unsigned_integer_value "prop_number_t number" +Returns the unsigned integer value of the numeric value object. +If the supplied object isn't a numeric value, zero is returned. Thus, +it is not possible to distinguish between ``not a prop_number_t'' +and ``prop_number_t has a value of 0''. +.It Fn prop_number_equals "prop_number_t num1" "prop_number_t num2" +Returns +.Dv true +if the two numeric value objects are equivalent. +If at least one of the supplied objects isn't a numeric value, +.Dv false +is returned. +.It Fn prop_number_equals_integer "prop_number_t number" "int64_t val" +Returns +.Dv true +if the object's value is equivalent to the signed value +.Fa val . +If the supplied object isn't a numerical value or if +.Fa val +exceeds +.Dv INT64_MAX , +.Dv false +is returned. +.It Fn prop_number_equals_unsigned_integer "prop_number_t number" \ + "uint64_t val" +Returns +.Dv true +if the object's value is equivalent to the unsigned value +.Fa val . +If the supplied object isn't a numerical value or if +.Fa val +exceeds +.Dv INT64_MAX , +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_object.3 b/man/prop_object.3 new file mode 100644 index 0000000..bb1a3f1 --- /dev/null +++ b/man/prop_object.3 @@ -0,0 +1,140 @@ +.\" $NetBSD: prop_object.3,v 1.7 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 21, 2006 +.Dt PROP_OBJECT 3 +.Os +.Sh NAME +.Nm prop_object , +.Nm prop_object_retain , +.Nm prop_object_release , +.Nm prop_object_type , +.Nm prop_object_equals , +.Nm prop_object_iterator_next , +.Nm prop_object_iterator_reset , +.Nm prop_object_iterator_release +.Nd general property container object functions +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft void +.Fn prop_object_retain "prop_object_t obj" +.Ft void +.Fn prop_object_release "prop_object_t obj" +.\" +.Ft prop_type_t +.Fn prop_object_type "prop_object_t obj" +.Ft bool +.Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2" +.\" +.Ft prop_object_t +.Fn prop_object_iterator_next "prop_object_iterator_t iter" +.Ft void +.Fn prop_object_iterator_reset "prop_object_iterator_t iter" +.Ft void +.Fn prop_object_iterator_release "prop_object_iterator_t iter" +.Sh DESCRIPTION +The +.Nm prop_object +family of functions operate on all property container object types. +.Bl -tag -width "" +.It Fn prop_object_retain "prop_object_t obj" +Increment the reference count on an object. +.It Fn prop_object_release "prop_object_t obj" +Decrement the reference count on an object. +If the last reference is dropped, the object is freed. +.It Fn prop_object_type "prop_object_t obj" +Determine the type of the object. Objects are one of the following types: +.Pp +.Bl -tag -width "PROP_TYPE_DICT_KEYSYM" -compact +.It Dv PROP_TYPE_BOOL +Boolean value +.Pq prop_bool_t +.It Dv PROP_TYPE_NUMBER +Number +.Pq prop_number_t +.It Dv PROP_TYPE_STRING +String +.Pq prop_string_t +.It Dv PROP_TYPE_DATA +Opaque data +.Pq prop_data_t +.It Dv PROP_TYPE_ARRAY +Array +.Pq prop_array_t +.It Dv PROP_TYPE_DICTIONARY +Dictionary +.Pq prop_dictionary_t +.It Dv PROP_TYPE_DICT_KEYSYM +Dictionary key symbol +.Pq prop_dictionary_keysym_t +.El +.Pp +If +.Fa obj +is +.Dv NULL , +then +.Dv PROP_TYPE_UNKNOWN +is returned. +.It Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2" +Returns +.Dv true +if the two objects are of the same type and are equivalent. +.It Fn prop_object_iterator_next "prop_object_iterator_t iter" +Return the next object in the collection +.Pq array or dictionary +being iterated by the iterator +.Fa iter . +If there are no more objects in the collection, +.Dv NULL +is returned. +.It Fn prop_object_iterator_reset "prop_object_iterator_t iter" +Reset the iterator to the first object in the collection being iterated +by the iterator +.Fa iter . +.It Fn prop_object_iterator_release "prop_object_iterator_t iter" +Release the iterator +.Fa iter . +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/prop_string.3 b/man/prop_string.3 new file mode 100644 index 0000000..5b8542a --- /dev/null +++ b/man/prop_string.3 @@ -0,0 +1,188 @@ +.\" $NetBSD: prop_string.3,v 1.6 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_STRING 3 +.Os +.Sh NAME +.Nm prop_string , +.Nm prop_string_create , +.Nm prop_string_create_cstring , +.Nm prop_string_create_cstring_nocopy , +.Nm prop_string_copy , +.Nm prop_string_copy_mutable , +.Nm prop_string_size , +.Nm prop_string_mutable , +.Nm prop_string_cstring , +.Nm prop_string_cstring_nocopy , +.Nm prop_string_append , +.Nm prop_string_append_cstring , +.Nm prop_string_equals , +.Nm prop_string_equals_cstring +.Nd string value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_string_t +.Fn prop_string_create "void" +.Ft prop_string_t +.Fn prop_string_create_cstring "const char *cstring" +.Ft prop_string_t +.Fn prop_string_create_cstring_nocopy "const char *cstring" +.\" +.Ft prop_string_t +.Fn prop_string_copy "prop_string_t string" +.Ft prop_string_t +.Fn prop_string_copy_mutable "prop_string_t string" +.\" +.Ft char * +.Fn prop_string_cstring "prop_string_t string" +.Ft const char * +.Fn prop_string_cstring_nocopy "prop_string_t string" +.\" +.Ft bool +.Fn prop_string_append "prop_string_t str1" "prop_string_t str2" +.Ft bool +.Fn prop_string_append_cstring "prop_string_t string" "const char *cstring" +.\" +.Ft bool +.Fn prop_string_equals "prop_string_t str1" "prop_string_t str2" +.Ft bool +.Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring" +.Sh DESCRIPTION +The +.Nm prop_string +family of functions operate on a string value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_string_create "void" +Create an empty mutable string. +Returns +.Dv NULL +on failure. +.It Fn prop_string_create_cstring "const char *cstring" +Create a mutable string that contains a copy of +.Fa cstring . +Returns +.Dv NULL +on failure. +.It Fn prop_string_create_cstring_nocopy "const char *cstring" +Create an immutable string that contains a reference to +.Fa cstring . +Returns +.Dv NULL +on failure. +.It Fn prop_string_copy "prop_string_t string" +Copy a string. +If the the string being copied is an immutable external C string reference, +then the copy is also immutable and references the same external C string. +Returns +.Dv NULL +on failure. +.It Fn prop_string_copy_mutable "prop_string_t string" +Copy a string, always creating a mutable copy. +Returns +.Dv NULL +on failure. +.It Fn prop_string_size "prop_string_t string" +Returns the size of the string, not including the terminating NUL. +If the supplied object isn't a string, zero is returned. +.It Fn prop_string_mutable "prop_string_t string" +Returns +.Dv true +if the string is mutable. +If the supplied object isn't a string, +.Dv false +is returned. +.It Fn prop_string_cstring "prop_string_t string" +Returns a copy of the string's contents as a C string. +The caller is responsible for freeing the returned buffer. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.Pp +Returns +.Dv NULL +on failure. +.It Fn prop_string_cstring_nocopy "prop_string_t string" +Returns an immutable reference to the contents of the string as a +C string. +If the supplied object isn't a string, +.Dv NULL +is returned. +.It Fn prop_string_append "prop_string_t str1" "prop_string_t str2" +Append the contents of +.Fa str2 +to +.Fa str1 , +which must be mutable. +Returns +.Dv true +upon success and +.Dv false +otherwise. +.It Fn prop_string_append_cstring "prop_string_t string" "const char *cstring" +Append the C string +.Fa cstring +to +.Fa string , +which must be mutable. +Returns +.Dv true +upon success and +.Dv false +otherwise. +.It Fn prop_string_equals "prop_string_t str1" "prop_string_t str2" +Returns +.Dv true +if the two string objects are equivalent. +.It Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring" +Returns +.Dv true +if the string's value is equivalent to +.Fa cstring . +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/man/proplib.3 b/man/proplib.3 new file mode 100644 index 0000000..b0f01fd --- /dev/null +++ b/man/proplib.3 @@ -0,0 +1,137 @@ +.\" $NetBSD: proplib.3,v 1.5 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 21, 2007 +.Dt PROPLIB 3 +.Os +.Sh NAME +.Nm proplib +.Nd property container object library +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.Sh DESCRIPTION +The +.Nm +library provides an abstract interface for creating and manipulating +property lists. +Property lists have object types for boolean values, opaque data, numbers, +and strings. +Structure is provided by the array and dictionary collection types. +.Pp +Property lists can be passed across protection boundaries by translating +them to an external representation. +This external representation is an XML document whose format is described +by the following DTD: +.Bd -literal -offset indent +http://www.apple.com/DTDs/PropertyList-1.0.dtd +.Ed +.Pp +Property container objects are reference counted. +When an object is created, its reference count is set to 1. +Any code that keeps a reference to an object, including the collection +types +.Pq arrays and dictionaries , +must +.Dq retain +the object +.Pq increment its reference count . +When that reference is dropped, the object must be +.Dq released +.Pq reference count decremented . +When an object's reference count drops to 0, it is automatically freed. +.Pp +The rules for managing reference counts are very simple: +.Bl -bullet +.It +If you create an object and do not explicitly maintain a reference to it, +you must release it. +.It +If you get a reference to an object from other code and wish to maintain +a reference to it, you must retain the object. You are responsible for +releasing the object once you drop that reference. +.It +You must never release an object unless you create it or retain it. +.El +.Pp +Object collections may be iterated by creating a special iterator object. +Iterator objects are special; they may not be retained, and they are +released using an iterator-specific release function. +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_dictionary_util 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_send_ioctl 3 , +.Xr prop_string 3 +.Sh HISTORY +The +.Nm +property container object library first appeared in +.Nx 4.0 . +.Sh CAVEATS +.Nm +does not have a +.Sq date +object type, and thus will not parse +.Sq date +elements from an Apple XML property list. +.Pp +The +.Nm +.Sq number +object type differs from the Apple XML property list format in the following +ways: +.Bl -bullet +.It +The external representation is in base 16, not base 10. +.Nm +is able to parse base 8, base 10, and base 16 +.Sq integer +elements. +.It +Internally, integers are always stored as unsigned numbers +.Pq uint64_t . +Therefore, the external representation will never be negative. +.It +Because floating point numbers are not supported, +.Sq real +elements from an Apple XML property list will not be parsed. +.El +.Pp +In order to facilitate use of +.Nm +in kernel, standalone, and user space environments, the +.Nm +parser is not a real XML parser. +It is hard-coded to parse only the property list external representation. diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..2e957e8 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,15 @@ +# +# Makefile.am for proplib. +# +AM_CPPFLAGS = -I$(srcdir) + +lib_LTLIBRARIES = libprop.la +libprop_la_SOURCES = prop_array.c prop_array_util.c prop_bool.c prop_data.c \ + prop_dictionary.c prop_dictionary_util.c \ + prop_ingest.c prop_number.c prop_object.c prop_rb.c \ + prop_stack.c prop_string.c +# +# We match the version that NetBSD is currently using. +# +libprop_la_LIBADD = -lpthread +libprop_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/src/prop_array.3 b/src/prop_array.3 new file mode 100644 index 0000000..8f9ef22 --- /dev/null +++ b/src/prop_array.3 @@ -0,0 +1,285 @@ +.\" $NetBSD: prop_array.3,v 1.8 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 19, 2006 +.Dt PROP_ARRAY 3 +.Os +.Sh NAME +.Nm prop_array , +.Nm prop_array_create , +.Nm prop_array_create_with_capacity , +.Nm prop_array_copy , +.Nm prop_array_copy_mutable , +.Nm prop_array_capacity , +.Nm prop_array_count , +.Nm prop_array_ensure_capacity , +.Nm prop_array_iterator , +.Nm prop_array_make_immutable , +.Nm prop_array_mutable , +.Nm prop_array_get , +.Nm prop_array_set , +.Nm prop_array_add , +.Nm prop_array_remove , +.Nm prop_array_externalize , +.Nm prop_array_internalize , +.Nm prop_array_externalize_to_file , +.Nm prop_array_internalize_from_file , +.Nm prop_array_equals +.Nd array property collection object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_array_t +.Fn prop_array_create "void" +.Ft prop_array_t +.Fn prop_array_create_with_capacity "unsigned int capacity" +.\" +.Ft prop_array_t +.Fn prop_array_copy "prop_array_t array" +.Ft prop_array_t +.Fn prop_array_copy_mutable "prop_array_t array" +.\" +.Ft unsigned int +.Fn prop_array_capacity "prop_array_t array" +.Ft unsigned int +.Fn prop_array_count "prop_array_t array" +.Ft bool +.Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity" +.\" +.Ft prop_object_iterator_t +.Fn prop_array_iterator "prop_array_t array" +.\" +.Ft void +.Fn prop_array_make_immutable "prop_array_t array" +.Ft bool +.Fn prop_array_mutable "prop_array_t array" +.\" +.Ft prop_object_t +.Fn prop_array_get "prop_array_t array" "unsigned int index" +.Ft bool +.Fn prop_array_set "prop_array_t array" "unsigned int index" "prop_object_t obj" +.Ft bool +.Fn prop_array_add "prop_array_t array" "prop_object_t obj" +.Ft void +.Fn prop_array_remove "prop_array_t array" "unsigned int index" +.\" +.Ft char * +.Fn prop_array_externalize "prop_array_t array" +.Ft prop_array_t +.Fn prop_array_internalize "const char *xml" +.\" +.Ft bool +.Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" +.Ft prop_array_t +.Fn prop_array_internalize_from_file "const char *path" +.\" +.Ft bool +.Fn prop_array_equals "prop_array_t array1" "prop_array_t array2" +.Sh DESCRIPTION +The +.Nm prop_array +family of functions operate on the array property collection object type. +An array is an ordered set; an iterated array will return objects in the +same order with which they were stored. +.Bl -tag -width "xxxxx" +.It Fn prop_array_create "void" +Create an empty array. +The array initially has no capacity. +Returns +.Dv NULL +on failure. +.It Fn prop_array_create_with_capacity "unsigned int capacity" +Create an array with the capacity to store +.Fa capacity +objects. +Returns +.Dv NULL +on failure. +.It Fn prop_array_copy "prop_array_t array" +Copy an array. +The new array has an initial capacity equal to the number of objects stored +in the array being copied. +The new array contains references to the original array's objects, not +copies of those objects +.Pq i.e. a shallow copy is made . +If the original array is immutable, the resulting array is also immutable. +Returns +.Dv NULL +on failure. +.It Fn prop_array_copy_mutable "prop_array_t array" +Like +.Fn prop_array_copy , +except the resulting array is always mutable. +.It Fn prop_array_capacity "prop_array_t array" +Returns the total capacity of the array, including objects already stored +in the array. +If the supplied object isn't an array, zero is returned. +.It Fn prop_array_count "prop_array_t array" +Returns the number of objects stored in the array. +If the supplied object isn't an array, zero is returned. +.It Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity" +Ensure that the array has a total capacity of +.Fa capacity , +including objects already stored in the array. +Returns +.Dv true +if the capacity of the array is greater or equal to +.Fa capacity +or if expansion of the array's capacity was successful +and +.Dv false +otherwise. +.It Fn prop_array_iterator "prop_array_t array" +Create an iterator for the array. +The array is retained by the iterator. +An array iterator returns the object references stored in the array. +Storing to or removing from the array invalidates any active iterators for +the array. +Returns +.Dv NULL +on failure. +.It Fn prop_array_make_immutable "prop_array_t array" +Make +.Fa array +immutable. +.It Fn prop_array_mutable "prop_array_t array" +Returns +.Dv true +if the array is mutable. +.It Fn prop_array_get "prop_array_t array" "unsigned int index" +Return the object stored at the array index +.Fa index . +Returns +.Dv NULL +on failure. +.It Fn prop_array_set "prop_array_t array" "unsigned int index" \ + "prop_object_t obj" +Store a reference to the object +.Fa obj +at the array index +.Fa index . +This function is not allowed to create holes in the array; +the caller must either be setting the object just beyond the existing +count or replacing an already existing object reference. +The object will be retained by the array. +If an existing object reference is being replaced, that object will be +released. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.It Fn prop_array_add "prop_array_t array" "prop_object_t obj" +Add a reference to the object +.Fa obj +to the array, appending to the end and growing the array's capacity if +necessary. +The object will be retained by the array. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.Pp +During expansion, array's capacity is augmented by the +.Dv EXPAND_STEP +constant, as defined in +.Pa libprop/prop_array.c +file, e.g. +.Pp +#define EXPAND_STEP 16 +.It Fn prop_array_remove "prop_array_t array" "unsigned int index" +Remove the reference to the object stored at array index +.Fa index . +The object will be released and the array compacted following +the removal. +.It Fn prop_array_equals "prop_array_t array1" "prop_array_t array2" +Returns +.Dv true +if the two arrays are equivalent. +If at least one of the supplied objects isn't an array, +.Dv false +is returned. +Note: Objects contained in the array are compared by value, not by reference. +.It Fn prop_array_externalize "prop_array_t array" +Externalizes an array, returning a NUL-terminated buffer containing +the XML representation of the array. +The caller is responsible for freeing the returned buffer. +If converting to the external representation fails for any reason, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_array_internalize "const char *xml" +Parse the XML representation of a property list in the NUL-terminated +buffer +.Fa xml +and return the corresponding array. +Returns +.Dv NULL +if parsing fails for any reason. +.It Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" +Externalizes an array and writes it to the file specified by +.Fa path . +The file is saved with the mode +.Dv 0666 +as modified by the process's file creation mask +.Pq see Xr umask 3 +and is written atomically. +Returns +.Dv false +if externalizing or writing the array fails for any reason. +.It Fn prop_array_internalize_from_file "const char *path" +Reads the XML property list contained in the file specified by +.Fa path , +internalizes it, and returns the corresponding array. +Returns +.Dv NULL +on failure. +.El +.Sh SEE ALSO +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_array.c b/src/prop_array.c new file mode 100644 index 0000000..cb1be1b --- /dev/null +++ b/src/prop_array.c @@ -0,0 +1,906 @@ +/* $NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $ */ + +/*- + * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_array.h" +#include "prop_object_impl.h" +#include + +struct _prop_array { + struct _prop_object pa_obj; + _PROP_RWLOCK_DECL(pa_rwlock) + prop_object_t * pa_array; + unsigned int pa_capacity; + unsigned int pa_count; + int pa_flags; + + uint32_t pa_version; +}; + +#define PA_F_IMMUTABLE 0x01 /* array is immutable */ + +_PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay") +_PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array", + "property array container object") + +static _prop_object_free_rv_t + _prop_array_free(prop_stack_t, prop_object_t *); +static void _prop_array_emergency_free(prop_object_t); +static bool _prop_array_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_array_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); +static void _prop_array_equals_finish(prop_object_t, prop_object_t); +static prop_object_iterator_t + _prop_array_iterator_locked(prop_array_t); +static prop_object_t + _prop_array_iterator_next_object_locked(void *); +static void _prop_array_iterator_reset_locked(void *); + +static const struct _prop_object_type _prop_object_type_array = { + .pot_type = PROP_TYPE_ARRAY, + .pot_free = _prop_array_free, + .pot_emergency_free = _prop_array_emergency_free, + .pot_extern = _prop_array_externalize, + .pot_equals = _prop_array_equals, + .pot_equals_finish = _prop_array_equals_finish, +}; + +#define prop_object_is_array(x) \ + ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array) + +#define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0) + +struct _prop_array_iterator { + struct _prop_object_iterator pai_base; + unsigned int pai_index; +}; + +#define EXPAND_STEP 16 + +static _prop_object_free_rv_t +_prop_array_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_array_t pa = *obj; + prop_object_t po; + + _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); + _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) || + (pa->pa_capacity != 0 && pa->pa_array != NULL)); + + /* The easy case is an empty array, just free and return. */ + if (pa->pa_count == 0) { + if (pa->pa_array != NULL) + _PROP_FREE(pa->pa_array, M_PROP_ARRAY); + + _PROP_RWLOCK_DESTROY(pa->pa_rwlock); + + _PROP_POOL_PUT(_prop_array_pool, pa); + + return (_PROP_OBJECT_FREE_DONE); + } + + po = pa->pa_array[pa->pa_count - 1]; + _PROP_ASSERT(po != NULL); + + if (stack == NULL) { + /* + * If we are in emergency release mode, + * just let caller recurse down. + */ + *obj = po; + return (_PROP_OBJECT_FREE_FAILED); + } + + /* Otherwise, try to push the current object on the stack. */ + if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) { + /* Push failed, entering emergency release mode. */ + return (_PROP_OBJECT_FREE_FAILED); + } + /* Object pushed on stack, caller will release it. */ + --pa->pa_count; + *obj = po; + return (_PROP_OBJECT_FREE_RECURSE); +} + +static void +_prop_array_emergency_free(prop_object_t obj) +{ + prop_array_t pa = obj; + + _PROP_ASSERT(pa->pa_count != 0); + --pa->pa_count; +} + +static bool +_prop_array_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_array_t pa = v; + struct _prop_object *po; + prop_object_iterator_t pi; + unsigned int i; + bool rv = false; + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + + if (pa->pa_count == 0) { + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (_prop_object_externalize_empty_tag(ctx, "array")); + } + + /* XXXJRT Hint "count" for the internalize step? */ + if (_prop_object_externalize_start_tag(ctx, "array") == false || + _prop_object_externalize_append_char(ctx, '\n') == false) + goto out; + + pi = _prop_array_iterator_locked(pa); + if (pi == NULL) + goto out; + + ctx->poec_depth++; + _PROP_ASSERT(ctx->poec_depth != 0); + + while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) { + if ((*po->po_type->pot_extern)(ctx, po) == false) { + prop_object_iterator_release(pi); + goto out; + } + } + + prop_object_iterator_release(pi); + + ctx->poec_depth--; + for (i = 0; i < ctx->poec_depth; i++) { + if (_prop_object_externalize_append_char(ctx, '\t') == false) + goto out; + } + if (_prop_object_externalize_end_tag(ctx, "array") == false) + goto out; + + rv = true; + + out: + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (rv); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_array_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_array_t array1 = v1; + prop_array_t array2 = v2; + uintptr_t idx; + _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE; + + if (array1 == array2) + return (_PROP_OBJECT_EQUALS_TRUE); + + _PROP_ASSERT(*stored_pointer1 == *stored_pointer2); + idx = (uintptr_t)*stored_pointer1; + + /* For the first iteration, lock the objects. */ + if (idx == 0) { + if ((uintptr_t)array1 < (uintptr_t)array2) { + _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); + _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); + } else { + _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); + _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); + } + } + + if (array1->pa_count != array2->pa_count) + goto out; + if (idx == array1->pa_count) { + rv = _PROP_OBJECT_EQUALS_TRUE; + goto out; + } + _PROP_ASSERT(idx < array1->pa_count); + + *stored_pointer1 = (void *)(idx + 1); + *stored_pointer2 = (void *)(idx + 1); + + *next_obj1 = array1->pa_array[idx]; + *next_obj2 = array2->pa_array[idx]; + + return (_PROP_OBJECT_EQUALS_RECURSE); + + out: + _PROP_RWLOCK_UNLOCK(array1->pa_rwlock); + _PROP_RWLOCK_UNLOCK(array2->pa_rwlock); + return (rv); +} + +static void +_prop_array_equals_finish(prop_object_t v1, prop_object_t v2) +{ + _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock); + _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock); +} + +static prop_array_t +_prop_array_alloc(unsigned int capacity) +{ + prop_array_t pa; + prop_object_t *array; + + if (capacity != 0) { + array = _PROP_CALLOC(capacity * sizeof(prop_object_t), + M_PROP_ARRAY); + if (array == NULL) + return (NULL); + } else + array = NULL; + + pa = _PROP_POOL_GET(_prop_array_pool); + if (pa != NULL) { + _prop_object_init(&pa->pa_obj, &_prop_object_type_array); + pa->pa_obj.po_type = &_prop_object_type_array; + + _PROP_RWLOCK_INIT(pa->pa_rwlock); + pa->pa_array = array; + pa->pa_capacity = capacity; + pa->pa_count = 0; + pa->pa_flags = 0; + + pa->pa_version = 0; + } else if (array != NULL) + _PROP_FREE(array, M_PROP_ARRAY); + + return (pa); +} + +static bool +_prop_array_expand(prop_array_t pa, unsigned int capacity) +{ + prop_object_t *array, *oarray; + + /* + * Array must be WRITE-LOCKED. + */ + + oarray = pa->pa_array; + + array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY); + if (array == NULL) + return (false); + if (oarray != NULL) + memcpy(array, oarray, pa->pa_capacity * sizeof(*array)); + pa->pa_array = array; + pa->pa_capacity = capacity; + + if (oarray != NULL) + _PROP_FREE(oarray, M_PROP_ARRAY); + + return (true); +} + +static prop_object_t +_prop_array_iterator_next_object_locked(void *v) +{ + struct _prop_array_iterator *pai = v; + prop_array_t pa = pai->pai_base.pi_obj; + prop_object_t po = NULL; + + _PROP_ASSERT(prop_object_is_array(pa)); + + if (pa->pa_version != pai->pai_base.pi_version) + goto out; /* array changed during iteration */ + + _PROP_ASSERT(pai->pai_index <= pa->pa_count); + + if (pai->pai_index == pa->pa_count) + goto out; /* we've iterated all objects */ + + po = pa->pa_array[pai->pai_index]; + pai->pai_index++; + + out: + return (po); +} + +static prop_object_t +_prop_array_iterator_next_object(void *v) +{ + struct _prop_array_iterator *pai = v; + prop_array_t pa = pai->pai_base.pi_obj; + prop_object_t po; + + _PROP_ASSERT(prop_object_is_array(pa)); + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + po = _prop_array_iterator_next_object_locked(pai); + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (po); +} + +static void +_prop_array_iterator_reset_locked(void *v) +{ + struct _prop_array_iterator *pai = v; + prop_array_t pa = pai->pai_base.pi_obj; + + _PROP_ASSERT(prop_object_is_array(pa)); + + pai->pai_index = 0; + pai->pai_base.pi_version = pa->pa_version; +} + +static void +_prop_array_iterator_reset(void *v) +{ + struct _prop_array_iterator *pai = v; + prop_array_t pa = pai->pai_base.pi_obj; + + _PROP_ASSERT(prop_object_is_array(pa)); + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + _prop_array_iterator_reset_locked(pai); + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); +} + +/* + * prop_array_create -- + * Create an empty array. + */ +prop_array_t +prop_array_create(void) +{ + + return (_prop_array_alloc(0)); +} + +/* + * prop_array_create_with_capacity -- + * Create an array with the capacity to store N objects. + */ +prop_array_t +prop_array_create_with_capacity(unsigned int capacity) +{ + + return (_prop_array_alloc(capacity)); +} + +/* + * prop_array_copy -- + * Copy an array. The new array has an initial capacity equal to + * the number of objects stored in the original array. The new + * array contains references to the original array's objects, not + * copies of those objects (i.e. a shallow copy). + */ +prop_array_t +prop_array_copy(prop_array_t opa) +{ + prop_array_t pa; + prop_object_t po; + unsigned int idx; + + if (! prop_object_is_array(opa)) + return (NULL); + + _PROP_RWLOCK_RDLOCK(opa->pa_rwlock); + + pa = _prop_array_alloc(opa->pa_count); + if (pa != NULL) { + for (idx = 0; idx < opa->pa_count; idx++) { + po = opa->pa_array[idx]; + prop_object_retain(po); + pa->pa_array[idx] = po; + } + pa->pa_count = opa->pa_count; + pa->pa_flags = opa->pa_flags; + } + _PROP_RWLOCK_UNLOCK(opa->pa_rwlock); + return (pa); +} + +/* + * prop_array_copy_mutable -- + * Like prop_array_copy(), but the resulting array is mutable. + */ +prop_array_t +prop_array_copy_mutable(prop_array_t opa) +{ + prop_array_t pa; + + pa = prop_array_copy(opa); + if (pa != NULL) + pa->pa_flags &= ~PA_F_IMMUTABLE; + + return (pa); +} + +/* + * prop_array_capacity -- + * Return the capacity of the array. + */ +unsigned int +prop_array_capacity(prop_array_t pa) +{ + unsigned int rv; + + if (! prop_object_is_array(pa)) + return (0); + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + rv = pa->pa_capacity; + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + return (rv); +} + +/* + * prop_array_count -- + * Return the number of objects stored in the array. + */ +unsigned int +prop_array_count(prop_array_t pa) +{ + unsigned int rv; + + if (! prop_object_is_array(pa)) + return (0); + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + rv = pa->pa_count; + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + return (rv); +} + +/* + * prop_array_ensure_capacity -- + * Ensure that the array has the capacity to store the specified + * total number of objects (inluding the objects already stored + * in the array). + */ +bool +prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity) +{ + bool rv; + + if (! prop_object_is_array(pa)) + return (false); + + _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); + if (capacity > pa->pa_capacity) + rv = _prop_array_expand(pa, capacity); + else + rv = true; + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + return (rv); +} + +static prop_object_iterator_t +_prop_array_iterator_locked(prop_array_t pa) +{ + struct _prop_array_iterator *pai; + + if (! prop_object_is_array(pa)) + return (NULL); + + pai = _PROP_CALLOC(sizeof(*pai), M_TEMP); + if (pai == NULL) + return (NULL); + pai->pai_base.pi_next_object = _prop_array_iterator_next_object; + pai->pai_base.pi_reset = _prop_array_iterator_reset; + prop_object_retain(pa); + pai->pai_base.pi_obj = pa; + _prop_array_iterator_reset_locked(pai); + + return (&pai->pai_base); +} + +/* + * prop_array_iterator -- + * Return an iterator for the array. The array is retained by + * the iterator. + */ +prop_object_iterator_t +prop_array_iterator(prop_array_t pa) +{ + prop_object_iterator_t pi; + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + pi = _prop_array_iterator_locked(pa); + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (pi); +} + +/* + * prop_array_make_immutable -- + * Make the array immutable. + */ +void +prop_array_make_immutable(prop_array_t pa) +{ + + _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); + if (prop_array_is_immutable(pa) == false) + pa->pa_flags |= PA_F_IMMUTABLE; + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); +} + +/* + * prop_array_mutable -- + * Returns true if the array is mutable. + */ +bool +prop_array_mutable(prop_array_t pa) +{ + bool rv; + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + rv = prop_array_is_immutable(pa) == false; + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + return (rv); +} + +/* + * prop_array_get -- + * Return the object stored at the specified array index. + */ +prop_object_t +prop_array_get(prop_array_t pa, unsigned int idx) +{ + prop_object_t po = NULL; + + if (! prop_object_is_array(pa)) + return (NULL); + + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); + if (idx >= pa->pa_count) + goto out; + po = pa->pa_array[idx]; + _PROP_ASSERT(po != NULL); + out: + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (po); +} + +static bool +_prop_array_add(prop_array_t pa, prop_object_t po) +{ + + /* + * Array must be WRITE-LOCKED. + */ + + _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); + + if (prop_array_is_immutable(pa) || + (pa->pa_count == pa->pa_capacity && + _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false)) + return (false); + + prop_object_retain(po); + pa->pa_array[pa->pa_count++] = po; + pa->pa_version++; + + return (true); +} + +/* + * prop_array_set -- + * Store a reference to an object at the specified array index. + * This method is not allowed to create holes in the array; the + * caller must either be setting the object just beyond the existing + * count or replacing an already existing object reference. + */ +bool +prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po) +{ + prop_object_t opo; + bool rv = false; + + if (! prop_object_is_array(pa)) + return (false); + + _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); + + if (prop_array_is_immutable(pa)) + goto out; + + if (idx == pa->pa_count) { + rv = _prop_array_add(pa, po); + goto out; + } + + _PROP_ASSERT(idx < pa->pa_count); + + opo = pa->pa_array[idx]; + _PROP_ASSERT(opo != NULL); + + prop_object_retain(po); + pa->pa_array[idx] = po; + pa->pa_version++; + + prop_object_release(opo); + + rv = true; + + out: + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return (rv); +} + +/* + * prop_array_add -- + * Add a reference to an object to the specified array, appending + * to the end and growing the array's capacity, if necessary. + */ +bool +prop_array_add(prop_array_t pa, prop_object_t po) +{ + bool rv; + + if (! prop_object_is_array(pa)) + return (false); + + _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); + rv = _prop_array_add(pa, po); + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + return (rv); +} + +/* + * prop_array_remove -- + * Remove the reference to an object from an array at the specified + * index. The array will be compacted following the removal. + */ +void +prop_array_remove(prop_array_t pa, unsigned int idx) +{ + prop_object_t po; + + if (! prop_object_is_array(pa)) + return; + + _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); + + _PROP_ASSERT(idx < pa->pa_count); + + /* XXX Should this be a _PROP_ASSERT()? */ + if (prop_array_is_immutable(pa)) { + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + return; + } + + po = pa->pa_array[idx]; + _PROP_ASSERT(po != NULL); + + for (++idx; idx < pa->pa_count; idx++) + pa->pa_array[idx - 1] = pa->pa_array[idx]; + pa->pa_count--; + pa->pa_version++; + + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); + + prop_object_release(po); +} + +/* + * prop_array_equals -- + * Return true if the two arrays are equivalent. Note we do a + * by-value comparison of the objects in the array. + */ +bool +prop_array_equals(prop_array_t array1, prop_array_t array2) +{ + if (!prop_object_is_array(array1) || !prop_object_is_array(array2)) + return (false); + + return (prop_object_equals(array1, array2)); +} + +/* + * prop_array_externalize -- + * Externalize an array, return a NUL-terminated buffer + * containing the XML-style representation. The buffer is allocated + * with the M_TEMP memory type. + */ +char * +prop_array_externalize(prop_array_t pa) +{ + struct _prop_object_externalize_context *ctx; + char *cp; + + ctx = _prop_object_externalize_context_alloc(); + if (ctx == NULL) + return (NULL); + + if (_prop_object_externalize_header(ctx) == false || + (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false || + _prop_object_externalize_footer(ctx) == false) { + /* We are responsible for releasing the buffer. */ + _PROP_FREE(ctx->poec_buf, M_TEMP); + _prop_object_externalize_context_free(ctx); + return (NULL); + } + + cp = ctx->poec_buf; + _prop_object_externalize_context_free(ctx); + + return (cp); +} + +/* + * _prop_array_internalize -- + * Parse an ... and return the object created from the + * external representation. + */ +static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *, + struct _prop_object_internalize_context *); + +bool +_prop_array_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + /* We don't currently understand any attributes. */ + if (ctx->poic_tagattr != NULL) + return (true); + + *obj = prop_array_create(); + /* + * We are done if the create failed or no child elements exist. + */ + if (*obj == NULL || ctx->poic_is_empty_element) + return (true); + + /* + * Opening tag is found, now continue to the first element. + */ + return (_prop_array_internalize_body(stack, obj, ctx)); +} + +static bool +_prop_array_internalize_continue(prop_stack_t stack, + prop_object_t *obj, + struct _prop_object_internalize_context *ctx, + void *data, prop_object_t child) +{ + prop_array_t array; + + _PROP_ASSERT(data == NULL); + + if (child == NULL) + goto bad; /* Element could not be parsed. */ + + array = *obj; + + if (prop_array_add(array, child) == false) { + prop_object_release(child); + goto bad; + } + prop_object_release(child); + + /* + * Current element is processed and added, look for next. + */ + return (_prop_array_internalize_body(stack, obj, ctx)); + + bad: + prop_object_release(*obj); + *obj = NULL; + return (true); +} + +static bool +_prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + prop_array_t array = *obj; + + _PROP_ASSERT(array != NULL); + + /* Fetch the next tag. */ + if (_prop_object_internalize_find_tag(ctx, NULL, + _PROP_TAG_TYPE_EITHER) == false) + goto bad; + + /* Check to see if this is the end of the array. */ + if (_PROP_TAG_MATCH(ctx, "array") && + ctx->poic_tag_type == _PROP_TAG_TYPE_END) { + /* It is, so don't iterate any further. */ + return (true); + } + + if (_prop_stack_push(stack, array, + _prop_array_internalize_continue, NULL, NULL)) + return (false); + + bad: + prop_object_release(array); + *obj = NULL; + return (true); +} + +/* + * prop_array_internalize -- + * Create an array by parsing the XML-style representation. + */ +prop_array_t +prop_array_internalize(const char *xml) +{ + return _prop_generic_internalize(xml, "array"); +} + +/* + * prop_array_externalize_to_file -- + * Externalize an array to the specified file. + */ +bool +prop_array_externalize_to_file(prop_array_t array, const char *fname) +{ + char *xml; + bool rv; + int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ + + xml = prop_array_externalize(array); + if (xml == NULL) + return (false); + rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); + if (rv == false) + save_errno = errno; + _PROP_FREE(xml, M_TEMP); + if (rv == false) + errno = save_errno; + + return (rv); +} + +/* + * prop_array_internalize_from_file -- + * Internalize an array from a file. + */ +prop_array_t +prop_array_internalize_from_file(const char *fname) +{ + struct _prop_object_internalize_mapped_file *mf; + prop_array_t array; + + mf = _prop_object_internalize_map_file(fname); + if (mf == NULL) + return (NULL); + array = prop_array_internalize(mf->poimf_xml); + _prop_object_internalize_unmap_file(mf); + + return (array); +} diff --git a/src/prop_array.h b/src/prop_array.h new file mode 100644 index 0000000..00f90d9 --- /dev/null +++ b/src/prop_array.h @@ -0,0 +1,140 @@ +/* $NetBSD: prop_array.h,v 1.8 2008/09/11 13:15:13 haad Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_ARRAY_H_ +#define _PROPLIB_PROP_ARRAY_H_ + +#include +#include "prop_object.h" + +typedef struct _prop_array *prop_array_t; + +__BEGIN_DECLS +prop_array_t prop_array_create(void); +prop_array_t prop_array_create_with_capacity(unsigned int); + +prop_array_t prop_array_copy(prop_array_t); +prop_array_t prop_array_copy_mutable(prop_array_t); + +unsigned int prop_array_capacity(prop_array_t); +unsigned int prop_array_count(prop_array_t); +bool prop_array_ensure_capacity(prop_array_t, unsigned int); + +void prop_array_make_immutable(prop_array_t); +bool prop_array_mutable(prop_array_t); + +prop_object_iterator_t prop_array_iterator(prop_array_t); + +prop_object_t prop_array_get(prop_array_t, unsigned int); +bool prop_array_set(prop_array_t, unsigned int, prop_object_t); +bool prop_array_add(prop_array_t, prop_object_t); +void prop_array_remove(prop_array_t, unsigned int); + +bool prop_array_equals(prop_array_t, prop_array_t); + +char * prop_array_externalize(prop_array_t); +prop_array_t prop_array_internalize(const char *); + +bool prop_array_externalize_to_file(prop_array_t, const char *); +prop_array_t prop_array_internalize_from_file(const char *); + +/* + * Utility routines to make it more convenient to work with values + * stored in dictionaries. + */ +bool prop_array_get_bool(prop_array_t, unsigned int, + bool *); +bool prop_array_set_bool(prop_array_t, unsigned int, + bool); + +bool prop_array_get_int8(prop_array_t, unsigned int, + int8_t *); +bool prop_array_get_uint8(prop_array_t, unsigned int, + uint8_t *); +bool prop_array_set_int8(prop_array_t, unsigned int, + int8_t); +bool prop_array_set_uint8(prop_array_t, unsigned int, + uint8_t); + +bool prop_array_get_int16(prop_array_t, unsigned int, + int16_t *); +bool prop_array_get_uint16(prop_array_t, unsigned int, + uint16_t *); +bool prop_array_set_int16(prop_array_t, unsigned int, + int16_t); +bool prop_array_set_uint16(prop_array_t, unsigned int, + uint16_t); + +bool prop_array_get_int32(prop_array_t, unsigned int, + int32_t *); +bool prop_array_get_uint32(prop_array_t, unsigned int, + uint32_t *); +bool prop_array_set_int32(prop_array_t, unsigned int, + int32_t); +bool prop_array_set_uint32(prop_array_t, unsigned int, + uint32_t); + +bool prop_array_get_int64(prop_array_t, unsigned int, + int64_t *); +bool prop_array_get_uint64(prop_array_t, unsigned int, + uint64_t *); +bool prop_array_set_int64(prop_array_t, unsigned int, + int64_t); +bool prop_array_set_uint64(prop_array_t, unsigned int, + uint64_t); + +bool prop_array_add_int8(prop_array_t, int8_t); +bool prop_array_add_uint8(prop_array_t, uint8_t); + +bool prop_array_add_int16(prop_array_t, int16_t); +bool prop_array_add_uint16(prop_array_t, uint16_t); + +bool prop_array_add_int32(prop_array_t, int32_t); +bool prop_array_add_uint32(prop_array_t, uint32_t); + +bool prop_array_add_int64(prop_array_t, int64_t); +bool prop_array_add_uint64(prop_array_t, uint64_t); + +bool prop_array_get_cstring(prop_array_t, unsigned int, + char **); +bool prop_array_set_cstring(prop_array_t, unsigned int, + const char *); + +bool prop_array_get_cstring_nocopy(prop_array_t, + unsigned int, + const char **); +bool prop_array_set_cstring_nocopy(prop_array_t, + unsigned int, + const char *); + +__END_DECLS + +#endif /* _PROPLIB_PROP_ARRAY_H_ */ diff --git a/src/prop_array_util.3 b/src/prop_array_util.3 new file mode 100644 index 0000000..27561a7 --- /dev/null +++ b/src/prop_array_util.3 @@ -0,0 +1,218 @@ +.\" $NetBSD: prop_array_util.3,v 1.3 2008/09/11 13:15:13 haad Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 2, 2008 +.Dt PROP_ARRAY_UTIL 3 +.Os +.Sh NAME +.Nm prop_array_util , +.Nm prop_array_get_bool , +.Nm prop_array_set_bool , +.Nm prop_array_get_int8 , +.Nm prop_array_get_uint8 , +.Nm prop_array_set_int8 , +.Nm prop_array_set_uint8 , +.Nm prop_array_get_int16 , +.Nm prop_array_get_uint16 , +.Nm prop_array_set_int16 , +.Nm prop_array_set_uint16 , +.Nm prop_array_get_int32 , +.Nm prop_array_get_uint32 , +.Nm prop_array_set_int32 , +.Nm prop_array_set_uint32 , +.Nm prop_array_get_int64 , +.Nm prop_array_get_uint64 , +.Nm prop_array_set_int64 , +.Nm prop_array_set_uint64 , +.Nm prop_array_add_int8 , +.Nm prop_array_add_uint8 , +.Nm prop_array_add_int16 , +.Nm prop_array_add_uint16 , +.Nm prop_array_add_int32 , +.Nm prop_array_add_uint32 , +.Nm prop_array_add_int64 , +.Nm prop_array_add_uint64 , +.Nm prop_array_get_cstring , +.Nm prop_array_set_cstring , +.Nm prop_array_get_cstring_nocopy , +.Nm prop_array_set_cstring_nocopy +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft bool +.Fn prop_array_get_bool "prop_array_t dict" "unsigned int indx" \ + "bool *valp" +.Ft bool +.Fn prop_array_set_bool "prop_array_t dict" "unsigned int indx" \ + "bool val" +.\" +.Ft bool +.Fn prop_array_get_int8 "prop_array_t dict" "unsigned int indx" \ + "int8_t *valp" +.Ft bool +.Fn prop_array_get_uint8 "prop_array_t dict" "unsigned int indx" \ + "uint8_t *valp" +.Ft bool +.Fn prop_array_set_int8 "prop_array_t dict" "unsigned int indx" \ + "int8_t val" +.Ft bool +.Fn prop_array_set_uint8 "prop_array_t dict" "unsigned int indx" \ + "uint8_t val" +.\" +.Ft bool +.Fn prop_array_get_int16 "prop_array_t dict" "unsigned int indx" \ + "int16_t *valp" +.Ft bool +.Fn prop_array_get_uint16 "prop_array_t dict" "unsigned int indx" \ + "uint16_t *valp" +.Ft bool +.Fn prop_array_set_int16 "prop_array_t dict" "unsigned int indx" \ + "int16_t val" +.Ft bool +.Fn prop_array_set_uint16 "prop_array_t dict" "unsigned int indx" \ + "uint16_t val" +.\" +.Ft bool +.Fn prop_array_get_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t *valp" +.Ft bool +.Fn prop_array_get_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t *valp" +.Ft bool +.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t val" +.Ft bool +.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_array_get_int64 "prop_array_t dict" "unsigned int indx" \ + "int64_t *valp" +.Ft bool +.Fn prop_array_get_uint64 "prop_array_t dict" "unsigned int indx" \ + "uint64_t *valp" +.Ft bool +.Fn prop_array_set_int64 "prop_array_t dict" "unsigned int indx" \ + "int64_t val" +.Ft bool +.Fn prop_array_set_uint64 "prop_array_t dict" "unsigned int indx" \ + "uint64_t val" +.\" +.Ft bool +.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \ + "int32_t val" +.Ft bool +.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_array_add_int8 "prop_array_t dict" "int8_t val" +.Ft bool +.Fn prop_array_add_uint8 "prop_array_t dict" "uint8_t val" +.Ft bool +.Fn prop_array_add_int16 "prop_array_t dict" "int16_t val" +.Ft bool +.Fn prop_array_add_uint16 "prop_array_t dict" "uint16_t val" +.Ft bool +.Fn prop_array_add_int32 "prop_array_t dict" "int32_t val" +.Ft bool +.Fn prop_array_add_uint32 "prop_array_t dict" "uint32_t val" +.Ft bool +.Fn prop_array_add_int64 "prop_array_t dict" "int64_t val" +.Ft bool +.Fn prop_array_add_uint64 "prop_array_t dict" "uint64_t val" +.\" +.Ft bool +.Fn prop_array_get_cstring "prop_array_t dict" "unsigned int indx" \ + "char **strp" +.Ft bool +.Fn prop_array_set_cstring "prop_array_t dict" "unsigned int indx" \ + "const char *str" +.\" +.Ft bool +.Fn prop_array_get_cstring_nocopy "prop_array_t dict" \ + "unsigned int indx" "const char **strp" +.Ft bool +.Fn prop_array_set_cstring_nocopy "prop_array_t dict" \ + "unsigned int indx" "const char *strp" +.Sh DESCRIPTION +The +.Nm prop_array_util +family of functions are provided to make getting and setting values in +arrays more convenient in some applications. +.Pp +The getters check the type of the returned object and, in some cases, also +ensure that the returned value is within the range implied by the getter's +value type. +.Pp +The setters handle object creation and release for the caller. +.Pp +The +.Fn prop_array_get_cstring +function returns dynamically allocated memory. +See +.Xr prop_string 3 +for more information. +.Pp +The +.Fn prop_array_get_cstring_nocopy +and +.Fn prop_array_set_cstring_nocopy +functions do not copy the string that is set or returned. +See +.Xr prop_string 3 +for more information. +.Sh RETURN VALUES +The +.Nm prop_array_util +getter functions return +.Dv true +if the object exists in the array and the value is in-range, or +.Dv false +otherwise. +.Pp +The +.Nm prop_array_util +setter functions return +.Dv true +if creating the object and storing it in the array is successful, or +.Dv false +otherwise. +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_number 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_array_util.c b/src/prop_array_util.c new file mode 100644 index 0000000..3d4a979 --- /dev/null +++ b/src/prop_array_util.c @@ -0,0 +1,240 @@ +/* $NetBSD: prop_array_util.c,v 1.2 2008/09/11 13:15:13 haad Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Utility routines to make it more convenient to work with values + * stored in array. + * + * Note: There is no special magic going on here. We use the standard + * proplib(3) APIs to do all of this work. Any application could do + * exactly what we're doing here. + */ + +#include "proplib.h" +#include "prop_object_impl.h" + +bool +prop_array_get_bool(prop_array_t array, + unsigned int indx, + bool *valp) +{ + prop_bool_t b; + + b = prop_array_get(array, indx); + if (prop_object_type(b) != PROP_TYPE_BOOL) + return (false); + + *valp = prop_bool_true(b); + + return (true); +} + +bool +prop_array_set_bool(prop_array_t array, + unsigned int indx, + bool val) +{ + prop_bool_t b; + int rv; + + b = prop_bool_create(val); + if (b == NULL) + return (false); + rv = prop_array_set(array, indx, b); + prop_object_release(b); + + return (rv); +} + +#define TEMPLATE(size) \ +bool \ +prop_array_get_int ## size (prop_array_t array, \ + unsigned int indx, \ + int ## size ## _t *valp) \ +{ \ + prop_number_t num; \ + \ + num = prop_array_get(array, indx); \ + if (prop_object_type(num) != PROP_TYPE_NUMBER) \ + return (false); \ + \ + if (prop_number_unsigned(num) && \ + prop_number_unsigned_integer_value(num) > \ + /*CONSTCOND*/((size) == 8 ? INT8_MAX : \ + (size) == 16 ? INT16_MAX : \ + (size) == 32 ? INT32_MAX : INT64_MAX)) { \ + return (false); \ + } \ + \ + if (prop_number_size(num) > (size)) \ + return (false); \ + \ + *valp = (int ## size ## _t) prop_number_integer_value(num); \ + \ + return (true); \ +} \ + \ +bool \ +prop_array_get_uint ## size (prop_array_t array, \ + unsigned int indx, \ + uint ## size ## _t *valp) \ +{ \ + prop_number_t num; \ + \ + num = prop_array_get(array, indx); \ + if (prop_object_type(num) != PROP_TYPE_NUMBER) \ + return (false); \ + \ + if (prop_number_unsigned(num) == false && \ + prop_number_integer_value(num) < 0) { \ + return (false); \ + } \ + \ + if (prop_number_size(num) > (size)) \ + return (false); \ + \ + *valp = (uint ## size ## _t) \ + prop_number_unsigned_integer_value(num); \ + \ + return (true); \ +} \ + \ +bool \ + prop_array_set_int ## size (prop_array_t array, \ + unsigned int indx, \ + int ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_integer((int64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_array_set(array, indx, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} \ + \ +bool \ +prop_array_set_uint ## size (prop_array_t array, \ + unsigned int indx, \ + uint ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_unsigned_integer((uint64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_array_set(array, indx, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} \ + \ +bool \ +prop_array_add_int ## size (prop_array_t array, \ + int ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_integer((int64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_array_add(array, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} \ + \ +bool \ +prop_array_add_uint ## size (prop_array_t array, \ + uint ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_integer((int64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_array_add(array, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} + +TEMPLATE(8) +TEMPLATE(16) +TEMPLATE(32) +TEMPLATE(64) + +#undef TEMPLATE + +#define TEMPLATE(variant, qualifier) \ +bool \ +prop_array_get_cstring ## variant (prop_array_t array, \ + unsigned int indx, \ + qualifier char **cpp) \ +{ \ + prop_string_t str; \ + \ + str = prop_array_get(array, indx); \ + if (prop_object_type(str) != PROP_TYPE_STRING) \ + return (false); \ + \ + *cpp = prop_string_cstring ## variant (str); \ + \ + return (*cpp == NULL ? false : true); \ +} \ + \ +bool \ +prop_array_set_cstring ## variant (prop_array_t array, \ + unsigned int indx, \ + const char *cp) \ +{ \ + prop_string_t str; \ + int rv; \ + \ + str = prop_string_create_cstring ## variant (cp); \ + if (str == NULL) \ + return (false); \ + rv = prop_array_set(array, indx, str); \ + prop_object_release(str); \ + \ + return (rv); \ +} + +TEMPLATE(,) +TEMPLATE(_nocopy,const) + +#undef TEMPLATE diff --git a/src/prop_bool.3 b/src/prop_bool.3 new file mode 100644 index 0000000..f56382d --- /dev/null +++ b/src/prop_bool.3 @@ -0,0 +1,82 @@ +.\" $NetBSD: prop_bool.3,v 1.6 2008/08/03 03:11:28 thorpej Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 22, 2006 +.Dt PROP_BOOL 3 +.Os +.Sh NAME +.Nm prop_bool , +.Nm prop_bool_create , +.Nm prop_bool_copy , +.Nm prop_bool_true +.Nd boolean value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_bool_t +.Fn prop_bool_create "bool val" +.Ft prop_bool_t +.Fn prop_bool_copy "prop_bool_t bool" +.\" +.Ft bool +.Fn prop_bool_true "prop_bool_t bool" +.Sh DESCRIPTION +The +.Nm prop_bool +family of functions operate on a boolean value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_bool_create "bool val" +Create a boolean value object with the value +.Fa val . +.It Fn prop_bool_copy "prop_bool_t bool" +Copy a boolean value object. +If the supplied object isn't a boolean, +.Dv NULL +is returned. +.It Fn prop_bool_true "prop_bool_t bool" +Returns the value of the boolean value object. +If the supplied object isn't a boolean, +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_bool.c b/src/prop_bool.c new file mode 100644 index 0000000..b817413 --- /dev/null +++ b/src/prop_bool.c @@ -0,0 +1,223 @@ +/* $NetBSD: prop_bool.c,v 1.16 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_bool.h" +#include "prop_object_impl.h" + +struct _prop_bool { + struct _prop_object pb_obj; + bool pb_value; +}; + +static struct _prop_bool _prop_bool_true; +static struct _prop_bool _prop_bool_false; + +_PROP_MUTEX_DECL_STATIC(_prop_bool_initialized_mutex) +static bool _prop_bool_initialized; + +static _prop_object_free_rv_t + _prop_bool_free(prop_stack_t, prop_object_t *); +static bool _prop_bool_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_bool_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); + +static const struct _prop_object_type _prop_object_type_bool = { + .pot_type = PROP_TYPE_BOOL, + .pot_free = _prop_bool_free, + .pot_extern = _prop_bool_externalize, + .pot_equals = _prop_bool_equals, +}; + +#define prop_object_is_bool(x) \ + ((x) != NULL && (x)->pb_obj.po_type == &_prop_object_type_bool) + +/* ARGSUSED */ +static _prop_object_free_rv_t +_prop_bool_free(prop_stack_t stack, prop_object_t *obj) +{ + /* + * This should never happen as we "leak" our initial reference + * count. + */ + + /* XXX forced assertion failure? */ + return (_PROP_OBJECT_FREE_DONE); +} + +static bool +_prop_bool_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_bool_t pb = v; + + return (_prop_object_externalize_empty_tag(ctx, + pb->pb_value ? "true" : "false")); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_bool_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_bool_t b1 = v1; + prop_bool_t b2 = v2; + + if (! (prop_object_is_bool(b1) && + prop_object_is_bool(b2))) + return (_PROP_OBJECT_EQUALS_FALSE); + + /* + * Since we only ever allocate one true and one false, + * save ourselves a couple of memory operations. + */ + if (b1 == b2) + return (_PROP_OBJECT_EQUALS_TRUE); + else + return (_PROP_OBJECT_EQUALS_FALSE); +} + +static prop_bool_t +_prop_bool_alloc(bool val) +{ + prop_bool_t pb; + + if (! _prop_bool_initialized) { + _PROP_MUTEX_LOCK(_prop_bool_initialized_mutex); + if (! _prop_bool_initialized) { + _prop_object_init(&_prop_bool_true.pb_obj, + &_prop_object_type_bool); + _prop_bool_true.pb_value = true; + + _prop_object_init(&_prop_bool_false.pb_obj, + &_prop_object_type_bool); + _prop_bool_false.pb_value = false; + + _prop_bool_initialized = true; + } + _PROP_MUTEX_UNLOCK(_prop_bool_initialized_mutex); + } + + pb = val ? &_prop_bool_true : &_prop_bool_false; + prop_object_retain(pb); + + return (pb); +} + +/* + * prop_bool_create -- + * Create a prop_bool_t and initialize it with the + * provided boolean value. + */ +prop_bool_t +prop_bool_create(bool val) +{ + + return (_prop_bool_alloc(val)); +} + +/* + * prop_bool_copy -- + * Copy a prop_bool_t. + */ +prop_bool_t +prop_bool_copy(prop_bool_t opb) +{ + + if (! prop_object_is_bool(opb)) + return (NULL); + + /* + * Because we only ever allocate one true and one false, this + * can be reduced to a simple retain operation. + */ + prop_object_retain(opb); + return (opb); +} + +/* + * prop_bool_true -- + * Get the value of a prop_bool_t. + */ +bool +prop_bool_true(prop_bool_t pb) +{ + + if (! prop_object_is_bool(pb)) + return (false); + + return (pb->pb_value); +} + +/* + * prop_bool_equals -- + * Return true if the boolean values are equivalent. + */ +bool +prop_bool_equals(prop_bool_t b1, prop_bool_t b2) +{ + if (!prop_object_is_bool(b1) || !prop_object_is_bool(b2)) + return (false); + + return (prop_object_equals(b1, b2)); +} + +/* + * _prop_bool_internalize -- + * Parse a or and return the object created from + * the external representation. + */ + +/* ARGSUSED */ +bool +_prop_bool_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + bool val; + + /* No attributes, and it must be an empty element. */ + if (ctx->poic_tagattr != NULL || + ctx->poic_is_empty_element == false) + return (true); + + if (_PROP_TAG_MATCH(ctx, "true")) + val = true; + else { + _PROP_ASSERT(_PROP_TAG_MATCH(ctx, "false")); + val = false; + } + *obj = prop_bool_create(val); + return (true); +} diff --git a/src/prop_bool.h b/src/prop_bool.h new file mode 100644 index 0000000..939ecc6 --- /dev/null +++ b/src/prop_bool.h @@ -0,0 +1,48 @@ +/* $NetBSD: prop_bool.h,v 1.4 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_BOOL_H_ +#define _PROPLIB_PROP_BOOL_H_ + +#include "prop_object.h" + +typedef struct _prop_bool *prop_bool_t; + +__BEGIN_DECLS +prop_bool_t prop_bool_create(bool); +prop_bool_t prop_bool_copy(prop_bool_t); + +bool prop_bool_true(prop_bool_t); + +bool prop_bool_equals(prop_bool_t, prop_bool_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_BOOL_H_ */ diff --git a/src/prop_data.3 b/src/prop_data.3 new file mode 100644 index 0000000..16e2f6a --- /dev/null +++ b/src/prop_data.3 @@ -0,0 +1,148 @@ +.\" $NetBSD: prop_data.3,v 1.6 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 22, 2006 +.Dt PROP_DATA 3 +.Os +.Sh NAME +.Nm prop_data , +.Nm prop_data_create_data , +.Nm prop_data_create_data_nocopy , +.Nm prop_data_copy , +.Nm prop_data_size , +.Nm prop_data_data , +.Nm prop_data_data_nocopy , +.Nm prop_data_equals , +.Nm prop_data_equals_data +.Nd opaque data value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_data_t +.Fn prop_data_create_data "const void *blob" "size_t len" +.Ft prop_data_t +.Fn prop_data_create_data_nocopy "const void *blob" "size_t len" +.\" +.Ft prop_data_t +.Fn prop_data_copy "prop_data_t data" +.\" +.Ft void * +.Fn prop_data_data "prop_data_t data" +.Ft size_t +.Fn prop_data_size "prop_data_t data" +.Ft const void * +.Fn prop_data_data_nocopy "prop_data_t data" +.\" +.Ft bool +.Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2" +.Ft bool +.Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len" +.Sh DESCRIPTION +The +.Nm prop_data +family of functions operate on an opaque data value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_data_create_data "const void *blob" "size_t len" +Create a data object that contains a copy of +.Fa blob +with size +.Fa len . +Returns +.Dv NULL +on failure. +.It Fn prop_data_create_data_nocopy "const void *blob" "size_t len" +Create a data object that contains a reference to +.Fa blob +with size +.Fa len . +Returns +.Dv NULL +on failure. +.It Fn prop_data_copy "prop_data_t data" +Copy a data object. +If the data object being copied is an external data reference, +then the copy also references the same external data. +Returns +.Dv NULL +on failure. +.It Fn prop_data_size "prop_data_t data" +Returns the size of the data object. +If the supplied object isn't a data object, zero is returned. +.It Fn prop_data_data "prop_data_t data" +Returns a copy of the data object's contents. +The caller is responsible for freeing the returned buffer. +If the supplied object isn't a data object or +if the data container is empty, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_data_data_nocopy "prop_data_t data" +Returns an immutable reference to the contents of the data object. +If the supplied object isn't a data object, +.Dv NULL +is returned. +.It Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2" +Returns +.Dv true +if the two data objects are equivalent. +If at least one of the supplied objects isn't a data object, +.Dv false +is returned. +.It Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len" +Returns +.Dv true +if the data object's value is equivalent to +.Fa blob +with size +.Fa len . +If the supplied object isn't a data object, +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_data.c b/src/prop_data.c new file mode 100644 index 0000000..f967578 --- /dev/null +++ b/src/prop_data.c @@ -0,0 +1,603 @@ +/* $NetBSD: prop_data.c,v 1.13 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_data.h" +#include "prop_object_impl.h" + +#include +#include +#include + +struct _prop_data { + struct _prop_object pd_obj; + union { + void * pdu_mutable; + const void * pdu_immutable; + } pd_un; +#define pd_mutable pd_un.pdu_mutable +#define pd_immutable pd_un.pdu_immutable + size_t pd_size; + int pd_flags; +}; + +#define PD_F_NOCOPY 0x01 + +_PROP_POOL_INIT(_prop_data_pool, sizeof(struct _prop_data), "propdata") + +_PROP_MALLOC_DEFINE(M_PROP_DATA, "prop data", + "property data container object") + +static _prop_object_free_rv_t + _prop_data_free(prop_stack_t, prop_object_t *); +static bool _prop_data_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_data_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); + +static const struct _prop_object_type _prop_object_type_data = { + .pot_type = PROP_TYPE_DATA, + .pot_free = _prop_data_free, + .pot_extern = _prop_data_externalize, + .pot_equals = _prop_data_equals, +}; + +#define prop_object_is_data(x) \ + ((x) != NULL && (x)->pd_obj.po_type == &_prop_object_type_data) + +/* ARGSUSED */ +static _prop_object_free_rv_t +_prop_data_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_data_t pd = *obj; + + if ((pd->pd_flags & PD_F_NOCOPY) == 0 && pd->pd_mutable != NULL) + _PROP_FREE(pd->pd_mutable, M_PROP_DATA); + _PROP_POOL_PUT(_prop_data_pool, pd); + + return (_PROP_OBJECT_FREE_DONE); +} + +static const char _prop_data_base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char _prop_data_pad64 = '='; + +static bool +_prop_data_externalize(struct _prop_object_externalize_context *ctx, void *v) +{ + prop_data_t pd = v; + size_t i, srclen; + const uint8_t *src; + uint8_t output[4]; + uint8_t input[3]; + + if (pd->pd_size == 0) + return (_prop_object_externalize_empty_tag(ctx, "data")); + + if (_prop_object_externalize_start_tag(ctx, "data") == false) + return (false); + + for (src = pd->pd_immutable, srclen = pd->pd_size; + srclen > 2; srclen -= 3) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + + output[0] = (uint32_t)input[0] >> 2; + output[1] = ((uint32_t)(input[0] & 0x03) << 4) + + ((uint32_t)input[1] >> 4); + output[2] = ((uint32_t)(input[1] & 0x0f) << 2) + + ((uint32_t)input[2] >> 6); + output[3] = input[2] & 0x3f; + _PROP_ASSERT(output[0] < 64); + _PROP_ASSERT(output[1] < 64); + _PROP_ASSERT(output[2] < 64); + _PROP_ASSERT(output[3] < 64); + + if (_prop_object_externalize_append_char(ctx, + _prop_data_base64[output[0]]) == false || + _prop_object_externalize_append_char(ctx, + _prop_data_base64[output[1]]) == false || + _prop_object_externalize_append_char(ctx, + _prop_data_base64[output[2]]) == false || + _prop_object_externalize_append_char(ctx, + _prop_data_base64[output[3]]) == false) + return (false); + } + + if (srclen != 0) { + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclen; i++) + input[i] = *src++; + + output[0] = (uint32_t)input[0] >> 2; + output[1] = ((uint32_t)(input[0] & 0x03) << 4) + + ((uint32_t)input[1] >> 4); + output[2] = ((uint32_t)(input[1] & 0x0f) << 2) + + ((uint32_t)input[2] >> 6); + _PROP_ASSERT(output[0] < 64); + _PROP_ASSERT(output[1] < 64); + _PROP_ASSERT(output[2] < 64); + + if (_prop_object_externalize_append_char(ctx, + _prop_data_base64[output[0]]) == false || + _prop_object_externalize_append_char(ctx, + _prop_data_base64[output[1]]) == false || + _prop_object_externalize_append_char(ctx, + srclen == 1 ? _prop_data_pad64 + : _prop_data_base64[output[2]]) == false || + _prop_object_externalize_append_char(ctx, + _prop_data_pad64) == false) + return (false); + } + + if (_prop_object_externalize_end_tag(ctx, "data") == false) + return (false); + + return (true); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_data_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_data_t pd1 = v1; + prop_data_t pd2 = v2; + + if (pd1 == pd2) + return (_PROP_OBJECT_EQUALS_TRUE); + if (pd1->pd_size != pd2->pd_size) + return (_PROP_OBJECT_EQUALS_FALSE); + if (pd1->pd_size == 0) { + _PROP_ASSERT(pd1->pd_immutable == NULL); + _PROP_ASSERT(pd2->pd_immutable == NULL); + return (_PROP_OBJECT_EQUALS_TRUE); + } + if (memcmp(pd1->pd_immutable, pd2->pd_immutable, pd1->pd_size) == 0) + return _PROP_OBJECT_EQUALS_TRUE; + else + return _PROP_OBJECT_EQUALS_FALSE; +} + +static prop_data_t +_prop_data_alloc(void) +{ + prop_data_t pd; + + pd = _PROP_POOL_GET(_prop_data_pool); + if (pd != NULL) { + _prop_object_init(&pd->pd_obj, &_prop_object_type_data); + + pd->pd_mutable = NULL; + pd->pd_size = 0; + pd->pd_flags = 0; + } + + return (pd); +} + +/* + * prop_data_create_data -- + * Create a data container that contains a copy of the data. + */ +prop_data_t +prop_data_create_data(const void *v, size_t size) +{ + prop_data_t pd; + void *nv; + + pd = _prop_data_alloc(); + if (pd != NULL && size != 0) { + nv = _PROP_MALLOC(size, M_PROP_DATA); + if (nv == NULL) { + prop_object_release(pd); + return (NULL); + } + memcpy(nv, v, size); + pd->pd_mutable = nv; + pd->pd_size = size; + } + return (pd); +} + +/* + * prop_data_create_data_nocopy -- + * Create an immutable data container that contains a refrence to the + * provided external data. + */ +prop_data_t +prop_data_create_data_nocopy(const void *v, size_t size) +{ + prop_data_t pd; + + pd = _prop_data_alloc(); + if (pd != NULL) { + pd->pd_immutable = v; + pd->pd_size = size; + pd->pd_flags |= PD_F_NOCOPY; + } + return (pd); +} + +/* + * prop_data_copy -- + * Copy a data container. If the original data is external, then + * the copy is also references the same external data. + */ +prop_data_t +prop_data_copy(prop_data_t opd) +{ + prop_data_t pd; + + if (! prop_object_is_data(opd)) + return (NULL); + + pd = _prop_data_alloc(); + if (pd != NULL) { + pd->pd_size = opd->pd_size; + pd->pd_flags = opd->pd_flags; + if (opd->pd_flags & PD_F_NOCOPY) + pd->pd_immutable = opd->pd_immutable; + else if (opd->pd_size != 0) { + void *nv = _PROP_MALLOC(pd->pd_size, M_PROP_DATA); + if (nv == NULL) { + prop_object_release(pd); + return (NULL); + } + memcpy(nv, opd->pd_immutable, opd->pd_size); + pd->pd_mutable = nv; + } + } + return (pd); +} + +/* + * prop_data_size -- + * Return the size of the data. + */ +size_t +prop_data_size(prop_data_t pd) +{ + + if (! prop_object_is_data(pd)) + return (0); + + return (pd->pd_size); +} + +/* + * prop_data_data -- + * Return a copy of the contents of the data container. + * The data is allocated with the M_TEMP malloc type. + * If the data container is empty, NULL is returned. + */ +void * +prop_data_data(prop_data_t pd) +{ + void *v; + + if (! prop_object_is_data(pd)) + return (NULL); + + if (pd->pd_size == 0) { + _PROP_ASSERT(pd->pd_immutable == NULL); + return (NULL); + } + + _PROP_ASSERT(pd->pd_immutable != NULL); + + v = _PROP_MALLOC(pd->pd_size, M_TEMP); + if (v != NULL) + memcpy(v, pd->pd_immutable, pd->pd_size); + + return (v); +} + +/* + * prop_data_data_nocopy -- + * Return an immutable reference to the contents of the data + * container. + */ +const void * +prop_data_data_nocopy(prop_data_t pd) +{ + + if (! prop_object_is_data(pd)) + return (NULL); + + _PROP_ASSERT((pd->pd_size == 0 && pd->pd_immutable == NULL) || + (pd->pd_size != 0 && pd->pd_immutable != NULL)); + + return (pd->pd_immutable); +} + +/* + * prop_data_equals -- + * Return true if two strings are equivalent. + */ +bool +prop_data_equals(prop_data_t pd1, prop_data_t pd2) +{ + if (!prop_object_is_data(pd1) || !prop_object_is_data(pd2)) + return (false); + + return (prop_object_equals(pd1, pd2)); +} + +/* + * prop_data_equals_data -- + * Return true if the contained data is equivalent to the specified + * external data. + */ +bool +prop_data_equals_data(prop_data_t pd, const void *v, size_t size) +{ + + if (! prop_object_is_data(pd)) + return (false); + + if (pd->pd_size != size) + return (false); + return (memcmp(pd->pd_immutable, v, size) == 0); +} + +static bool +_prop_data_internalize_decode(struct _prop_object_internalize_context *ctx, + uint8_t *target, size_t targsize, size_t *sizep, + const char **cpp) +{ + const char *src; + size_t tarindex; + int state, ch; + const char *pos; + + state = 0; + tarindex = 0; + src = ctx->poic_cp; + + for (;;) { + ch = (unsigned char) *src++; + if (_PROP_EOF(ch)) + return (false); + if (_PROP_ISSPACE(ch)) + continue; + if (ch == '<') { + src--; + break; + } + if (ch == _prop_data_pad64) + break; + + pos = strchr(_prop_data_base64, ch); + if (pos == NULL) + return (false); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (false); + target[tarindex] = + (uint8_t)((pos - _prop_data_base64) << 2); + } + state = 1; + break; + + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (false); + target[tarindex] |= + (uint32_t)(pos - _prop_data_base64) >> 4; + target[tarindex + 1] = + (uint8_t)(((pos - _prop_data_base64) & 0xf) + << 4); + } + tarindex++; + state = 2; + break; + + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (false); + target[tarindex] |= + (uint32_t)(pos - _prop_data_base64) >> 2; + target[tarindex + 1] = + (uint8_t)(((pos - _prop_data_base64) + & 0x3) << 6); + } + tarindex++; + state = 3; + break; + + case 3: + if (target) { + if (tarindex >= targsize) + return (false); + target[tarindex] |= (uint8_t) + (pos - _prop_data_base64); + } + tarindex++; + state = 0; + break; + + default: + _PROP_ASSERT(/*CONSTCOND*/0); + } + } + + /* + * We are done decoding the Base64 characters. Let's see if we + * ended up on a byte boundary and/or with unrecognized trailing + * characters. + */ + if (ch == _prop_data_pad64) { + ch = (unsigned char) *src; /* src already advanced */ + if (_PROP_EOF(ch)) + return (false); + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (false); + + case 2: /* Valid, one byte of info */ + /* Skip whitespace */ + for (ch = (unsigned char) *src++; + ch != '<'; ch = (unsigned char) *src++) { + if (_PROP_EOF(ch)) + return (false); + if (!_PROP_ISSPACE(ch)) + break; + } + /* Make sure there is another trailing = */ + if (ch != _prop_data_pad64) + return (false); + ch = (unsigned char) *src; + /* FALLTHROUGH */ + + case 3: /* Valid, two bytes of info */ + /* + * We know this char is a =. Is there anything but + * whitespace after it? + */ + for (ch = (unsigned char) *src++; + ch != '<'; ch = (unsigned char) *src++) { + if (_PROP_EOF(ch)) + return (false); + if (!_PROP_ISSPACE(ch)) + return (false); + } + /* back up to '<' */ + src--; + } + } else { + /* + * We ended by seeing the end of the Base64 string. Make + * sure there are no partial bytes lying around. + */ + if (state != 0) + return (false); + } + + _PROP_ASSERT(*src == '<'); + if (sizep != NULL) + *sizep = tarindex; + if (cpp != NULL) + *cpp = src; + + return (true); +} + +/* + * _prop_data_internalize -- + * Parse a ... and return the object created from the + * external representation. + */ + +/* strtoul is used for parsing, enforce. */ +typedef int PROP_DATA_ASSERT[/* CONSTCOND */sizeof(size_t) == sizeof(unsigned long) ? 1 : -1]; + +/* ARGSUSED */ +bool +_prop_data_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + prop_data_t data; + uint8_t *buf; + size_t len, alen; + + /* We don't accept empty elements. */ + if (ctx->poic_is_empty_element) + return (true); + + /* + * If we got a "size" attribute, get the size of the data blob + * from that. Otherwise, we have to figure it out from the base64. + */ + if (ctx->poic_tagattr != NULL) { + char *cp; + + if (!_PROP_TAGATTR_MATCH(ctx, "size") || + ctx->poic_tagattrval_len == 0) + return (true); + + errno = 0; + len = strtoul(ctx->poic_tagattrval, &cp, 0); + if (len == ULONG_MAX && errno == ERANGE) + return (true); + if (cp != ctx->poic_tagattrval + ctx->poic_tagattrval_len) + return (true); + _PROP_ASSERT(*cp == '\"'); + } else if (_prop_data_internalize_decode(ctx, NULL, 0, &len, + NULL) == false) + return (true); + + /* + * Always allocate one extra in case we don't land on an even byte + * boundary during the decode. + */ + buf = _PROP_MALLOC(len + 1, M_PROP_DATA); + if (buf == NULL) + return (true); + + if (_prop_data_internalize_decode(ctx, buf, len + 1, &alen, + &ctx->poic_cp) == false) { + _PROP_FREE(buf, M_PROP_DATA); + return (true); + } + if (alen != len) { + _PROP_FREE(buf, M_PROP_DATA); + return (true); + } + + if (_prop_object_internalize_find_tag(ctx, "data", + _PROP_TAG_TYPE_END) == false) { + _PROP_FREE(buf, M_PROP_DATA); + return (true); + } + + data = _prop_data_alloc(); + if (data == NULL) { + _PROP_FREE(buf, M_PROP_DATA); + return (true); + } + + data->pd_mutable = buf; + data->pd_size = len; + + *obj = data; + return (true); +} diff --git a/src/prop_data.h b/src/prop_data.h new file mode 100644 index 0000000..79a04b1 --- /dev/null +++ b/src/prop_data.h @@ -0,0 +1,54 @@ +/* $NetBSD: prop_data.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_DATA_H_ +#define _PROPLIB_PROP_DATA_H_ + +#include "prop_object.h" + +typedef struct _prop_data *prop_data_t; + +__BEGIN_DECLS +prop_data_t prop_data_create_data(const void *, size_t); +prop_data_t prop_data_create_data_nocopy(const void *, size_t); + +prop_data_t prop_data_copy(prop_data_t); + +size_t prop_data_size(prop_data_t); + +void * prop_data_data(prop_data_t); +const void * prop_data_data_nocopy(prop_data_t); + +bool prop_data_equals(prop_data_t, prop_data_t); +bool prop_data_equals_data(prop_data_t, const void *, size_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_DATA_H_ */ diff --git a/src/prop_dictionary.3 b/src/prop_dictionary.3 new file mode 100644 index 0000000..77a6b7e --- /dev/null +++ b/src/prop_dictionary.3 @@ -0,0 +1,328 @@ +.\" $NetBSD: prop_dictionary.3,v 1.13 2008/05/06 17:23:38 xtraeme Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 6, 2008 +.Dt PROP_DICTIONARY 3 +.Os +.Sh NAME +.Nm prop_dictionary , +.Nm prop_dictionary_create , +.Nm prop_dictionary_create_with_capacity , +.Nm prop_dictionary_copy , +.Nm prop_dictionary_copy_mutable , +.Nm prop_dictionary_count , +.Nm prop_dictionary_ensure_capacity , +.Nm prop_dictionary_iterator , +.Nm prop_dictionary_all_keys , +.Nm prop_dictionary_make_immutable , +.Nm prop_dictionary_mutable , +.Nm prop_dictionary_get , +.Nm prop_dictionary_set , +.Nm prop_dictionary_remove , +.Nm prop_dictionary_get_keysym , +.Nm prop_dictionary_set_keysym , +.Nm prop_dictionary_remove_keysym , +.Nm prop_dictionary_externalize , +.Nm prop_dictionary_internalize , +.Nm prop_dictionary_externalize_to_file , +.Nm prop_dictionary_internalize_from_file , +.Nm prop_dictionary_equals , +.Nm prop_dictionary_keysym_cstring_nocopy , +.Nm prop_dictionary_keysym_equals +.Nd dictionary property collection object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_dictionary_t +.Fn prop_dictionary_create "void" +.Ft prop_dictionary_t +.Fn prop_dictionary_create_with_capacity "unsigned int capacity" +.\" +.Ft prop_dictionary_t +.Fn prop_dictionary_copy "prop_dictionary_t dict" +.Ft prop_dictionary_t +.Fn prop_dictionary_copy_mutable "prop_dictionary_t dict" +.\" +.Ft unsigned int +.Fn prop_dictionary_count "prop_dictionary_t dict" +.Ft bool +.Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" \ + "unsigned int capacity" +.\" +.Ft prop_object_iterator_t +.Fn prop_dictionary_iterator "prop_dictionary_t dict" +.Ft prop_array_t +.Fn prop_dictionary_all_keys "prop_dictionary_t dict" +.\" +.Ft void +.Fn prop_dictionary_make_immutable "prop_dictionary_t dict" +.Ft bool +.Fn prop_dictionary_mutable "prop_dictionary_t dict" +.\" +.Ft prop_object_t +.Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key" +.Ft bool +.Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \ + "prop_object_t obj" +.Ft void +.Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key" +.\" +.Ft prop_object_t +.Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" +.Ft bool +.Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" "prop_object_t obj" +.Ft void +.Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t keysym" +.\" +.Ft bool +.Fn prop_dictionary_equals "prop_dictionary_t dict1" "prop_dictionary_t dict2" +.\" +.Ft const char * +.Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t sym" +.\" +.Ft bool +.Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \ + "prop_dictionary_keysym_t keysym2" +.\" +.Ft char * +.Fn prop_dictionary_externalize "prop_dictionary_t dict" +.Ft prop_dictionary_t +.Fn prop_dictionary_internalize "const char *xml" +.\" +.Ft bool +.Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \ + "const char *path" +.Ft prop_dictionary_t +.Fn prop_dictionary_internalize_from_file "const char *path" +.\" +.Sh DESCRIPTION +The +.Nm prop_dictionary +family of functions operate on the dictionary property collection object type. +A dictionary is an unordered set of objects stored as key-value pairs. +.Bl -tag -width "xxxxx" +.It Fn prop_dictionary_create "void" +Create an empty dictionary. +The dictionary initially has no capacity. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_create_with_capacity "unsigned int capacity" +Create a dictionary with the capacity to store +.Fa capacity +objects. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_copy "prop_dictionary_t dict" +Copy a dictionary. +The new dictionary has an initial capacity equal to the number of objects +stored in the dictionary being copied. +The new dictionary contains references to the original dictionary's objects, +not copies of those objects +.Pq i.e. a shallow copy is made . +If the original dictionary is immutable, the resulting dictionary is also +immutable. +.It Fn prop_dictionary_copy_mutable "prop_dictionary_t dict" +Like +.Fn prop_dictionary_copy , +except the resulting dictionary is always mutable. +.It Fn prop_dictionary_count "prop_dictionary_t dict" +Returns the number of objects stored in the dictionary. +.It Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" +Ensure that the dictionary has a total capacity of +.Fa capacity , +including objects already stored in the dictionary. +Returns +.Dv true +if the capacity of the dictionary is greater or equal to +.Fa capacity +or if the expansion of the dictionary's capacity was successful +and +.Dv false +otherwise. +If the supplied object isn't a dictionary, +.Dv false +is returned. +.It Fn prop_dictionary_iterator "prop_dictionary_t dict" +Create an iterator for the dictionary. +The dictionary is retained by the iterator. +A dictionary iterator returns the key symbols used to look up objects stored +in the dictionary; to get the object itself, a dictionary lookup using this +key symbol must be performed. +Storing to or removing from the dictionary invalidates any active iterators for +the dictionary. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_all_keys "prop_dictionary_t dict" +Return an array of all of the dictionary key symbols +.Pq prop_dictionary_keysym_t +in the dictionary. +This provides a way to iterate over the items in the dictionary while +retaining the ability to mutate the dictionary; instead of iterating +over the dictionary itself, iterate over the array of keys. +The caller is responsible for releasing the array. +Returns +.Dv NULL +on failure. +.It Fn prop_dictionary_make_immutable "prop_dictionary_t dict" +Make +.Fa dict +immutable. +.It Fn prop_dictionary_mutable "prop_dictionary_t dict" +Returns +.Dv true +if the dictionary is mutable. +.It Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key" +Return the object stored in the dictionary with the key +.Fa key . +If no object is stored with the specified key, +.Dv NULL +is returned. +.It Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \ + "prop_object_t obj" +Store a reference to the object +.Fa obj +with the key +.Fa key . +The object will be retained by the dictionary. +If the key already exists in the dictionary, the object associated with +that key will be released and replaced with the new object. +Returns +.Dv true +if storing the object was successful and +.Dv false +otherwise. +.It Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key" +Remove the reference to the object stored in the dictionary with the key +.Fa key . +The object will be released. +.It Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" +Like +.Fn prop_dictionary_get , +but the lookup is performed using a key symbol returned by a dictionary +iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" "prop_object_t obj" +Like +.Fn prop_dictionary_set , +but the lookup of the object to replace is performed using a key symbol +returned by a dictionary iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \ + "prop_dictionary_keysym_t sym" +Like +.Fn prop_dictionary_remove , +but the lookup of the object to remove is performed using a key symbol +returned by a dictionary iterator. +The results are undefined if the iterator used to obtain the key symbol +is not associated with +.Fa dict . +.It Fn prop_dictionary_equals "prop_dictionary_t dict1" \ + "prop_dictionary_t dict2" +Returns +.Dv true +if the two dictionaries are equivalent. +Note: Objects contained in the dictionary are compared by value, not by +reference. +.It Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t keysym" +Returns an immutable reference to the dictionary key symbol's string value. +.It Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \ + "prop_dictionary_keysym_t keysym2" +Returns +.Dv true +if the two dictionary key symbols are equivalent. +.It Fn prop_dictionary_externalize "prop_dictionary_t dict" +Externalizes a dictionary, returning a NUL-terminated buffer containing +the XML representation of the dictionary. +The caller is responsible for freeing the returned buffer. +If converting to the external representation fails for any reason, +.Dv NULL +is returned. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.It Fn prop_dictionary_internalize "const char *xml" +Parse the XML representation of a property list in the NUL-terminated +buffer +.Fa xml +and return the corresponding dictionary. +Returns +.Dv NULL +if parsing fails for any reason. +.It Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \ + "const char *path" +Externalizes a dictionary and writes it to the file specified by +.Fa path . +The file is saved with the mode +.Dv 0666 +as modified by the process's file creation mask +.Pq see Xr umask 3 +and is written atomically. +Returns +.Dv false +if externalizing or writing the dictionary fails for any reason. +.It Fn prop_dictionary_internalize_from_file "const char *path" +Reads the XML property list contained in the file specified by +.Fa path , +internalizes it, and returns the corresponding array. +Returns +.Dv NULL +on failure. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary_util 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_dictionary.c b/src/prop_dictionary.c new file mode 100644 index 0000000..7815086 --- /dev/null +++ b/src/prop_dictionary.c @@ -0,0 +1,1387 @@ +/* $NetBSD: prop_dictionary.c,v 1.32 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "proplib.h" +#include "prop_object_impl.h" +#include "prop_rb_impl.h" + +#include + +/* + * We implement these like arrays, but we keep them sorted by key. + * This allows us to binary-search as well as keep externalized output + * sane-looking for human eyes. + */ + +#define EXPAND_STEP 16 + +/* + * prop_dictionary_keysym_t is allocated with space at the end to hold the + * key. This must be a regular object so that we can maintain sane iterator + * semantics -- we don't want to require that the caller release the result + * of prop_object_iterator_next(). + * + * We'd like to have some small'ish keysym objects for up-to-16 characters + * in a key, some for up-to-32 characters in a key, and then a final bucket + * for up-to-128 characters in a key (not including NUL). Keys longer than + * 128 characters are not allowed. + */ +struct _prop_dictionary_keysym { + struct _prop_object pdk_obj; + size_t pdk_size; + struct rb_node pdk_link; + char pdk_key[1]; + /* actually variable length */ +}; + +#define RBNODE_TO_PDK(n) \ + ((struct _prop_dictionary_keysym *) \ + ((uintptr_t)n - offsetof(struct _prop_dictionary_keysym, pdk_link))) + + /* pdk_key[1] takes care of the NUL */ +#define PDK_SIZE_16 (sizeof(struct _prop_dictionary_keysym) + 16) +#define PDK_SIZE_32 (sizeof(struct _prop_dictionary_keysym) + 32) +#define PDK_SIZE_128 (sizeof(struct _prop_dictionary_keysym) + 128) + +#define PDK_MAXKEY 128 + +_PROP_POOL_INIT(_prop_dictionary_keysym16_pool, PDK_SIZE_16, "pdict16") +_PROP_POOL_INIT(_prop_dictionary_keysym32_pool, PDK_SIZE_32, "pdict32") +_PROP_POOL_INIT(_prop_dictionary_keysym128_pool, PDK_SIZE_128, "pdict128") + +struct _prop_dict_entry { + prop_dictionary_keysym_t pde_key; + prop_object_t pde_objref; +}; + +struct _prop_dictionary { + struct _prop_object pd_obj; + _PROP_RWLOCK_DECL(pd_rwlock) + struct _prop_dict_entry *pd_array; + unsigned int pd_capacity; + unsigned int pd_count; + int pd_flags; + + uint32_t pd_version; +}; + +#define PD_F_IMMUTABLE 0x01 /* dictionary is immutable */ + +_PROP_POOL_INIT(_prop_dictionary_pool, sizeof(struct _prop_dictionary), + "propdict") +_PROP_MALLOC_DEFINE(M_PROP_DICT, "prop dictionary", + "property dictionary container object") + +static _prop_object_free_rv_t + _prop_dictionary_free(prop_stack_t, prop_object_t *); +static void _prop_dictionary_emergency_free(prop_object_t); +static bool _prop_dictionary_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_dictionary_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); +static void _prop_dictionary_equals_finish(prop_object_t, prop_object_t); +static prop_object_iterator_t + _prop_dictionary_iterator_locked(prop_dictionary_t); +static prop_object_t + _prop_dictionary_iterator_next_object_locked(void *); +static prop_object_t + _prop_dictionary_get_keysym(prop_dictionary_t, + prop_dictionary_keysym_t, bool); +static prop_object_t + _prop_dictionary_get(prop_dictionary_t, const char *, bool); + +static const struct _prop_object_type _prop_object_type_dictionary = { + .pot_type = PROP_TYPE_DICTIONARY, + .pot_free = _prop_dictionary_free, + .pot_emergency_free = _prop_dictionary_emergency_free, + .pot_extern = _prop_dictionary_externalize, + .pot_equals = _prop_dictionary_equals, + .pot_equals_finish = _prop_dictionary_equals_finish, +}; + +static _prop_object_free_rv_t + _prop_dict_keysym_free(prop_stack_t, prop_object_t *); +static bool _prop_dict_keysym_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_dict_keysym_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); + +static const struct _prop_object_type _prop_object_type_dict_keysym = { + .pot_type = PROP_TYPE_DICT_KEYSYM, + .pot_free = _prop_dict_keysym_free, + .pot_extern = _prop_dict_keysym_externalize, + .pot_equals = _prop_dict_keysym_equals, +}; + +#define prop_object_is_dictionary(x) \ + ((x) != NULL && (x)->pd_obj.po_type == &_prop_object_type_dictionary) +#define prop_object_is_dictionary_keysym(x) \ + ((x) != NULL && (x)->pdk_obj.po_type == &_prop_object_type_dict_keysym) + +#define prop_dictionary_is_immutable(x) \ + (((x)->pd_flags & PD_F_IMMUTABLE) != 0) + +struct _prop_dictionary_iterator { + struct _prop_object_iterator pdi_base; + unsigned int pdi_index; +}; + +/* + * Dictionary key symbols are immutable, and we are likely to have many + * duplicated key symbols. So, to save memory, we unique'ify key symbols + * so we only have to have one copy of each string. + */ + +static int +_prop_dict_keysym_rb_compare_nodes(const struct rb_node *n1, + const struct rb_node *n2) +{ + const prop_dictionary_keysym_t pdk1 = RBNODE_TO_PDK(n1); + const prop_dictionary_keysym_t pdk2 = RBNODE_TO_PDK(n2); + + return (strcmp(pdk1->pdk_key, pdk2->pdk_key)); +} + +static int +_prop_dict_keysym_rb_compare_key(const struct rb_node *n, + const void *v) +{ + const prop_dictionary_keysym_t pdk = RBNODE_TO_PDK(n); + const char *cp = v; + + return (strcmp(pdk->pdk_key, cp)); +} + +static const struct rb_tree_ops _prop_dict_keysym_rb_tree_ops = { + .rbto_compare_nodes = _prop_dict_keysym_rb_compare_nodes, + .rbto_compare_key = _prop_dict_keysym_rb_compare_key, +}; + +static struct rb_tree _prop_dict_keysym_tree; +static bool _prop_dict_keysym_tree_initialized; + +_PROP_MUTEX_DECL_STATIC(_prop_dict_keysym_tree_mutex) + +static void +_prop_dict_keysym_put(prop_dictionary_keysym_t pdk) +{ + + if (pdk->pdk_size <= PDK_SIZE_16) + _PROP_POOL_PUT(_prop_dictionary_keysym16_pool, pdk); + else if (pdk->pdk_size <= PDK_SIZE_32) + _PROP_POOL_PUT(_prop_dictionary_keysym32_pool, pdk); + else { + _PROP_ASSERT(pdk->pdk_size <= PDK_SIZE_128); + _PROP_POOL_PUT(_prop_dictionary_keysym128_pool, pdk); + } +} + +/* ARGSUSED */ +static _prop_object_free_rv_t +_prop_dict_keysym_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_dictionary_keysym_t pdk = *obj; + + _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex); + _prop_rb_tree_remove_node(&_prop_dict_keysym_tree, &pdk->pdk_link); + _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex); + + _prop_dict_keysym_put(pdk); + + return _PROP_OBJECT_FREE_DONE; +} + +static bool +_prop_dict_keysym_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_dictionary_keysym_t pdk = v; + + /* We externalize these as strings, and they're never empty. */ + + _PROP_ASSERT(pdk->pdk_key[0] != '\0'); + + if (_prop_object_externalize_start_tag(ctx, "string") == false || + _prop_object_externalize_append_encoded_cstring(ctx, + pdk->pdk_key) == false || + _prop_object_externalize_end_tag(ctx, "string") == false) + return (false); + + return (true); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_dict_keysym_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_dictionary_keysym_t pdk1 = v1; + prop_dictionary_keysym_t pdk2 = v2; + + /* + * There is only ever one copy of a keysym at any given time, + * so we can reduce this to a simple pointer equality check. + */ + if (pdk1 == pdk2) + return _PROP_OBJECT_EQUALS_TRUE; + else + return _PROP_OBJECT_EQUALS_FALSE; +} + +static prop_dictionary_keysym_t +_prop_dict_keysym_alloc(const char *key) +{ + prop_dictionary_keysym_t opdk, pdk; + const struct rb_node *n; + size_t size; + bool rv; + + /* + * Check to see if this already exists in the tree. If it does, + * we just retain it and return it. + */ + _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex); + if (! _prop_dict_keysym_tree_initialized) { + _prop_rb_tree_init(&_prop_dict_keysym_tree, + &_prop_dict_keysym_rb_tree_ops); + _prop_dict_keysym_tree_initialized = true; + } else { + n = _prop_rb_tree_find(&_prop_dict_keysym_tree, key); + if (n != NULL) { + opdk = RBNODE_TO_PDK(n); + prop_object_retain(opdk); + _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex); + return (opdk); + } + } + _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex); + + /* + * Not in the tree. Create it now. + */ + + size = sizeof(*pdk) + strlen(key) /* pdk_key[1] covers the NUL */; + + if (size <= PDK_SIZE_16) + pdk = _PROP_POOL_GET(_prop_dictionary_keysym16_pool); + else if (size <= PDK_SIZE_32) + pdk = _PROP_POOL_GET(_prop_dictionary_keysym32_pool); + else if (size <= PDK_SIZE_128) + pdk = _PROP_POOL_GET(_prop_dictionary_keysym128_pool); + else + pdk = NULL; /* key too long */ + + if (pdk == NULL) + return (NULL); + + _prop_object_init(&pdk->pdk_obj, &_prop_object_type_dict_keysym); + + strcpy(pdk->pdk_key, key); + pdk->pdk_size = size; + + /* + * We dropped the mutex when we allocated the new object, so + * we have to check again if it is in the tree. + */ + _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex); + n = _prop_rb_tree_find(&_prop_dict_keysym_tree, key); + if (n != NULL) { + opdk = RBNODE_TO_PDK(n); + prop_object_retain(opdk); + _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex); + _prop_dict_keysym_put(pdk); + return (opdk); + } + rv = _prop_rb_tree_insert_node(&_prop_dict_keysym_tree, &pdk->pdk_link); + _PROP_ASSERT(rv == true); + _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex); + return (pdk); +} + +static _prop_object_free_rv_t +_prop_dictionary_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_dictionary_t pd = *obj; + prop_dictionary_keysym_t pdk; + prop_object_t po; + + _PROP_ASSERT(pd->pd_count <= pd->pd_capacity); + _PROP_ASSERT((pd->pd_capacity == 0 && pd->pd_array == NULL) || + (pd->pd_capacity != 0 && pd->pd_array != NULL)); + + /* The empty dictorinary is easy, handle that first. */ + if (pd->pd_count == 0) { + if (pd->pd_array != NULL) + _PROP_FREE(pd->pd_array, M_PROP_DICT); + + _PROP_RWLOCK_DESTROY(pd->pd_rwlock); + + _PROP_POOL_PUT(_prop_dictionary_pool, pd); + + return (_PROP_OBJECT_FREE_DONE); + } + + po = pd->pd_array[pd->pd_count - 1].pde_objref; + _PROP_ASSERT(po != NULL); + + if (stack == NULL) { + /* + * If we are in emergency release mode, + * just let caller recurse down. + */ + *obj = po; + return (_PROP_OBJECT_FREE_FAILED); + } + + /* Otherwise, try to push the current object on the stack. */ + if (!_prop_stack_push(stack, pd, NULL, NULL, NULL)) { + /* Push failed, entering emergency release mode. */ + return (_PROP_OBJECT_FREE_FAILED); + } + /* Object pushed on stack, caller will release it. */ + --pd->pd_count; + pdk = pd->pd_array[pd->pd_count].pde_key; + _PROP_ASSERT(pdk != NULL); + prop_object_release(pdk); + *obj = po; + return (_PROP_OBJECT_FREE_RECURSE); +} + +static void +_prop_dictionary_emergency_free(prop_object_t obj) +{ + prop_dictionary_t pd = obj; + prop_dictionary_keysym_t pdk; + + _PROP_ASSERT(pd->pd_count != 0); + --pd->pd_count; + + pdk = pd->pd_array[pd->pd_count].pde_key; + _PROP_ASSERT(pdk != NULL); + prop_object_release(pdk); +} + +static bool +_prop_dictionary_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_dictionary_t pd = v; + prop_dictionary_keysym_t pdk; + struct _prop_object *po; + prop_object_iterator_t pi; + unsigned int i; + bool rv = false; + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + + if (pd->pd_count == 0) { + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (_prop_object_externalize_empty_tag(ctx, "dict")); + } + + if (_prop_object_externalize_start_tag(ctx, "dict") == false || + _prop_object_externalize_append_char(ctx, '\n') == false) + goto out; + + pi = _prop_dictionary_iterator_locked(pd); + if (pi == NULL) + goto out; + + ctx->poec_depth++; + _PROP_ASSERT(ctx->poec_depth != 0); + + while ((pdk = _prop_dictionary_iterator_next_object_locked(pi)) + != NULL) { + po = _prop_dictionary_get_keysym(pd, pdk, true); + if (po == NULL || + _prop_object_externalize_start_tag(ctx, "key") == false || + _prop_object_externalize_append_encoded_cstring(ctx, + pdk->pdk_key) == false || + _prop_object_externalize_end_tag(ctx, "key") == false || + (*po->po_type->pot_extern)(ctx, po) == false) { + prop_object_iterator_release(pi); + goto out; + } + } + + prop_object_iterator_release(pi); + + ctx->poec_depth--; + for (i = 0; i < ctx->poec_depth; i++) { + if (_prop_object_externalize_append_char(ctx, '\t') == false) + goto out; + } + if (_prop_object_externalize_end_tag(ctx, "dict") == false) + goto out; + + rv = true; + + out: + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (rv); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_dictionary_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_dictionary_t dict1 = v1; + prop_dictionary_t dict2 = v2; + uintptr_t idx; + _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE; + + if (dict1 == dict2) + return (_PROP_OBJECT_EQUALS_TRUE); + + _PROP_ASSERT(*stored_pointer1 == *stored_pointer2); + + idx = (uintptr_t)*stored_pointer1; + + if (idx == 0) { + if ((uintptr_t)dict1 < (uintptr_t)dict2) { + _PROP_RWLOCK_RDLOCK(dict1->pd_rwlock); + _PROP_RWLOCK_RDLOCK(dict2->pd_rwlock); + } else { + _PROP_RWLOCK_RDLOCK(dict2->pd_rwlock); + _PROP_RWLOCK_RDLOCK(dict1->pd_rwlock); + } + } + + if (dict1->pd_count != dict2->pd_count) + goto out; + + if (idx == dict1->pd_count) { + rv = _PROP_OBJECT_EQUALS_TRUE; + goto out; + } + + _PROP_ASSERT(idx < dict1->pd_count); + + *stored_pointer1 = (void *)(idx + 1); + *stored_pointer2 = (void *)(idx + 1); + + *next_obj1 = &dict1->pd_array[idx].pde_objref; + *next_obj2 = &dict2->pd_array[idx].pde_objref; + + if (!prop_dictionary_keysym_equals(dict1->pd_array[idx].pde_key, + dict2->pd_array[idx].pde_key)) + goto out; + + return (_PROP_OBJECT_EQUALS_RECURSE); + + out: + _PROP_RWLOCK_UNLOCK(dict1->pd_rwlock); + _PROP_RWLOCK_UNLOCK(dict2->pd_rwlock); + return (rv); +} + +static void +_prop_dictionary_equals_finish(prop_object_t v1, prop_object_t v2) +{ + _PROP_RWLOCK_UNLOCK(((prop_dictionary_t)v1)->pd_rwlock); + _PROP_RWLOCK_UNLOCK(((prop_dictionary_t)v2)->pd_rwlock); +} + +static prop_dictionary_t +_prop_dictionary_alloc(unsigned int capacity) +{ + prop_dictionary_t pd; + struct _prop_dict_entry *array; + + if (capacity != 0) { + array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_DICT); + if (array == NULL) + return (NULL); + } else + array = NULL; + + pd = _PROP_POOL_GET(_prop_dictionary_pool); + if (pd != NULL) { + _prop_object_init(&pd->pd_obj, &_prop_object_type_dictionary); + + _PROP_RWLOCK_INIT(pd->pd_rwlock); + pd->pd_array = array; + pd->pd_capacity = capacity; + pd->pd_count = 0; + pd->pd_flags = 0; + + pd->pd_version = 0; + } else if (array != NULL) + _PROP_FREE(array, M_PROP_DICT); + + return (pd); +} + +static bool +_prop_dictionary_expand(prop_dictionary_t pd, unsigned int capacity) +{ + struct _prop_dict_entry *array, *oarray; + + /* + * Dictionary must be WRITE-LOCKED. + */ + + oarray = pd->pd_array; + + array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_DICT); + if (array == NULL) + return (false); + if (oarray != NULL) + memcpy(array, oarray, pd->pd_capacity * sizeof(*array)); + pd->pd_array = array; + pd->pd_capacity = capacity; + + if (oarray != NULL) + _PROP_FREE(oarray, M_PROP_DICT); + + return (true); +} + +static prop_object_t +_prop_dictionary_iterator_next_object_locked(void *v) +{ + struct _prop_dictionary_iterator *pdi = v; + prop_dictionary_t pd = pdi->pdi_base.pi_obj; + prop_dictionary_keysym_t pdk = NULL; + + _PROP_ASSERT(prop_object_is_dictionary(pd)); + + if (pd->pd_version != pdi->pdi_base.pi_version) + goto out; /* dictionary changed during iteration */ + + _PROP_ASSERT(pdi->pdi_index <= pd->pd_count); + + if (pdi->pdi_index == pd->pd_count) + goto out; /* we've iterated all objects */ + + pdk = pd->pd_array[pdi->pdi_index].pde_key; + pdi->pdi_index++; + + out: + return (pdk); +} + +static prop_object_t +_prop_dictionary_iterator_next_object(void *v) +{ + struct _prop_dictionary_iterator *pdi = v; + prop_dictionary_t pd = pdi->pdi_base.pi_obj; + prop_dictionary_keysym_t pdk; + + _PROP_ASSERT(prop_object_is_dictionary(pd)); + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + pdk = _prop_dictionary_iterator_next_object_locked(pdi); + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (pdk); +} + +static void +_prop_dictionary_iterator_reset_locked(void *v) +{ + struct _prop_dictionary_iterator *pdi = v; + prop_dictionary_t pd = pdi->pdi_base.pi_obj; + + _PROP_ASSERT(prop_object_is_dictionary(pd)); + + pdi->pdi_index = 0; + pdi->pdi_base.pi_version = pd->pd_version; +} + +static void +_prop_dictionary_iterator_reset(void *v) +{ + struct _prop_dictionary_iterator *pdi = v; + prop_dictionary_t pd = pdi->pdi_base.pi_obj; + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + _prop_dictionary_iterator_reset_locked(pdi); + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); +} + +/* + * prop_dictionary_create -- + * Create a dictionary. + */ +prop_dictionary_t +prop_dictionary_create(void) +{ + + return (_prop_dictionary_alloc(0)); +} + +/* + * prop_dictionary_create_with_capacity -- + * Create a dictionary with the capacity to store N objects. + */ +prop_dictionary_t +prop_dictionary_create_with_capacity(unsigned int capacity) +{ + + return (_prop_dictionary_alloc(capacity)); +} + +/* + * prop_dictionary_copy -- + * Copy a dictionary. The new dictionary has an initial capacity equal + * to the number of objects stored int the original dictionary. The new + * dictionary contains refrences to the original dictionary's objects, + * not copies of those objects (i.e. a shallow copy). + */ +prop_dictionary_t +prop_dictionary_copy(prop_dictionary_t opd) +{ + prop_dictionary_t pd; + prop_dictionary_keysym_t pdk; + prop_object_t po; + unsigned int idx; + + if (! prop_object_is_dictionary(opd)) + return (NULL); + + _PROP_RWLOCK_RDLOCK(opd->pd_rwlock); + + pd = _prop_dictionary_alloc(opd->pd_count); + if (pd != NULL) { + for (idx = 0; idx < opd->pd_count; idx++) { + pdk = opd->pd_array[idx].pde_key; + po = opd->pd_array[idx].pde_objref; + + prop_object_retain(pdk); + prop_object_retain(po); + + pd->pd_array[idx].pde_key = pdk; + pd->pd_array[idx].pde_objref = po; + } + pd->pd_count = opd->pd_count; + pd->pd_flags = opd->pd_flags; + } + _PROP_RWLOCK_UNLOCK(opd->pd_rwlock); + return (pd); +} + +/* + * prop_dictionary_copy_mutable -- + * Like prop_dictionary_copy(), but the resulting dictionary is + * mutable. + */ +prop_dictionary_t +prop_dictionary_copy_mutable(prop_dictionary_t opd) +{ + prop_dictionary_t pd; + + if (! prop_object_is_dictionary(opd)) + return (NULL); + + pd = prop_dictionary_copy(opd); + if (pd != NULL) + pd->pd_flags &= ~PD_F_IMMUTABLE; + + return (pd); +} + +/* + * prop_dictionary_make_immutable -- + * Set the immutable flag on that dictionary. + */ +void +prop_dictionary_make_immutable(prop_dictionary_t pd) +{ + + _PROP_RWLOCK_WRLOCK(pd->pd_rwlock); + if (prop_dictionary_is_immutable(pd) == false) + pd->pd_flags |= PD_F_IMMUTABLE; + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); +} + +/* + * prop_dictionary_count -- + * Return the number of objects stored in the dictionary. + */ +unsigned int +prop_dictionary_count(prop_dictionary_t pd) +{ + unsigned int rv; + + if (! prop_object_is_dictionary(pd)) + return (0); + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + rv = pd->pd_count; + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + + return (rv); +} + +/* + * prop_dictionary_ensure_capacity -- + * Ensure that the dictionary has the capacity to store the specified + * total number of objects (including the objects already stored in + * the dictionary). + */ +bool +prop_dictionary_ensure_capacity(prop_dictionary_t pd, unsigned int capacity) +{ + bool rv; + + if (! prop_object_is_dictionary(pd)) + return (false); + + _PROP_RWLOCK_WRLOCK(pd->pd_rwlock); + if (capacity > pd->pd_capacity) + rv = _prop_dictionary_expand(pd, capacity); + else + rv = true; + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (rv); +} + +static prop_object_iterator_t +_prop_dictionary_iterator_locked(prop_dictionary_t pd) +{ + struct _prop_dictionary_iterator *pdi; + + if (! prop_object_is_dictionary(pd)) + return (NULL); + + pdi = _PROP_CALLOC(sizeof(*pdi), M_TEMP); + if (pdi == NULL) + return (NULL); + pdi->pdi_base.pi_next_object = _prop_dictionary_iterator_next_object; + pdi->pdi_base.pi_reset = _prop_dictionary_iterator_reset; + prop_object_retain(pd); + pdi->pdi_base.pi_obj = pd; + _prop_dictionary_iterator_reset_locked(pdi); + + return (&pdi->pdi_base); +} + +/* + * prop_dictionary_iterator -- + * Return an iterator for the dictionary. The dictionary is retained by + * the iterator. + */ +prop_object_iterator_t +prop_dictionary_iterator(prop_dictionary_t pd) +{ + prop_object_iterator_t pi; + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + pi = _prop_dictionary_iterator_locked(pd); + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (pi); +} + +/* + * prop_dictionary_all_keys -- + * Return an array containing a snapshot of all of the keys + * in the dictionary. + */ +prop_array_t +prop_dictionary_all_keys(prop_dictionary_t pd) +{ + prop_array_t array; + unsigned int idx; + bool rv = true; + + if (! prop_object_is_dictionary(pd)) + return (NULL); + + /* There is no pressing need to lock the dictionary for this. */ + array = prop_array_create_with_capacity(pd->pd_count); + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + + for (idx = 0; idx < pd->pd_count; idx++) { + rv = prop_array_add(array, pd->pd_array[idx].pde_key); + if (rv == false) + break; + } + + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + + if (rv == false) { + prop_object_release(array); + array = NULL; + } + return (array); +} + +static struct _prop_dict_entry * +_prop_dict_lookup(prop_dictionary_t pd, const char *key, + unsigned int *idxp) +{ + struct _prop_dict_entry *pde; + unsigned int base, idx, distance; + int res; + + /* + * Dictionary must be READ-LOCKED or WRITE-LOCKED. + */ + + for (idx = 0, base = 0, distance = pd->pd_count; distance != 0; + distance >>= 1) { + idx = base + (distance >> 1); + pde = &pd->pd_array[idx]; + _PROP_ASSERT(pde->pde_key != NULL); + res = strcmp(key, pde->pde_key->pdk_key); + if (res == 0) { + if (idxp != NULL) + *idxp = idx; + return (pde); + } + if (res > 0) { /* key > pdk_key: move right */ + base = idx + 1; + distance--; + } /* else move left */ + } + + /* idx points to the slot we looked at last. */ + if (idxp != NULL) + *idxp = idx; + return (NULL); +} + +static prop_object_t +_prop_dictionary_get(prop_dictionary_t pd, const char *key, bool locked) +{ + const struct _prop_dict_entry *pde; + prop_object_t po = NULL; + + if (! prop_object_is_dictionary(pd)) + return (NULL); + + if (!locked) + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + pde = _prop_dict_lookup(pd, key, NULL); + if (pde != NULL) { + _PROP_ASSERT(pde->pde_objref != NULL); + po = pde->pde_objref; + } + if (!locked) + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (po); +} +/* + * prop_dictionary_get -- + * Return the object stored with specified key. + */ +prop_object_t +prop_dictionary_get(prop_dictionary_t pd, const char *key) +{ + prop_object_t po; + + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); + po = _prop_dictionary_get(pd, key, true); + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (po); +} + +static prop_object_t +_prop_dictionary_get_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk, + bool locked) +{ + + if (! (prop_object_is_dictionary(pd) && + prop_object_is_dictionary_keysym(pdk))) + return (NULL); + + return (_prop_dictionary_get(pd, pdk->pdk_key, locked)); +} + +/* + * prop_dictionary_get_keysym -- + * Return the object stored at the location encoded by the keysym. + */ +prop_object_t +prop_dictionary_get_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk) +{ + + return (_prop_dictionary_get_keysym(pd, pdk, false)); +} + +/* + * prop_dictionary_set -- + * Store a reference to an object at with the specified key. + * If the key already exisit, the original object is released. + */ +bool +prop_dictionary_set(prop_dictionary_t pd, const char *key, prop_object_t po) +{ + struct _prop_dict_entry *pde; + prop_dictionary_keysym_t pdk; + unsigned int idx; + bool rv = false; + + if (! prop_object_is_dictionary(pd)) + return (false); + + _PROP_ASSERT(pd->pd_count <= pd->pd_capacity); + + if (prop_dictionary_is_immutable(pd)) + return (false); + + _PROP_RWLOCK_WRLOCK(pd->pd_rwlock); + + pde = _prop_dict_lookup(pd, key, &idx); + if (pde != NULL) { + prop_object_t opo = pde->pde_objref; + prop_object_retain(po); + pde->pde_objref = po; + prop_object_release(opo); + rv = true; + goto out; + } + + pdk = _prop_dict_keysym_alloc(key); + if (pdk == NULL) + goto out; + + if (pd->pd_count == pd->pd_capacity && + _prop_dictionary_expand(pd, + pd->pd_capacity + EXPAND_STEP) == false) { + prop_object_release(pdk); + goto out; + } + + /* At this point, the store will succeed. */ + prop_object_retain(po); + + if (pd->pd_count == 0) { + pd->pd_array[0].pde_key = pdk; + pd->pd_array[0].pde_objref = po; + pd->pd_count++; + pd->pd_version++; + rv = true; + goto out; + } + + pde = &pd->pd_array[idx]; + _PROP_ASSERT(pde->pde_key != NULL); + + if (strcmp(key, pde->pde_key->pdk_key) < 0) { + /* + * key < pdk_key: insert to the left. This is the same as + * inserting to the right, except we decrement the current + * index first. + * + * Because we're unsigned, we have to special case 0 + * (grumble). + */ + if (idx == 0) { + memmove(&pd->pd_array[1], &pd->pd_array[0], + pd->pd_count * sizeof(*pde)); + pd->pd_array[0].pde_key = pdk; + pd->pd_array[0].pde_objref = po; + pd->pd_count++; + pd->pd_version++; + rv = true; + goto out; + } + idx--; + } + + memmove(&pd->pd_array[idx + 2], &pd->pd_array[idx + 1], + (pd->pd_count - (idx + 1)) * sizeof(*pde)); + pd->pd_array[idx + 1].pde_key = pdk; + pd->pd_array[idx + 1].pde_objref = po; + pd->pd_count++; + + pd->pd_version++; + + rv = true; + + out: + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); + return (rv); +} + +/* + * prop_dictionary_set_keysym -- + * Replace the object in the dictionary at the location encoded by + * the keysym. + */ +bool +prop_dictionary_set_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk, + prop_object_t po) +{ + + if (! (prop_object_is_dictionary(pd) && + prop_object_is_dictionary_keysym(pdk))) + return (false); + + return (prop_dictionary_set(pd, pdk->pdk_key, po)); +} + +static void +_prop_dictionary_remove(prop_dictionary_t pd, struct _prop_dict_entry *pde, + unsigned int idx) +{ + prop_dictionary_keysym_t pdk = pde->pde_key; + prop_object_t po = pde->pde_objref; + + /* + * Dictionary must be WRITE-LOCKED. + */ + + _PROP_ASSERT(pd->pd_count != 0); + _PROP_ASSERT(idx < pd->pd_count); + _PROP_ASSERT(pde == &pd->pd_array[idx]); + + idx++; + memmove(&pd->pd_array[idx - 1], &pd->pd_array[idx], + (pd->pd_count - idx) * sizeof(*pde)); + pd->pd_count--; + pd->pd_version++; + + prop_object_release(pdk); + prop_object_release(po); +} + +/* + * prop_dictionary_remove -- + * Remove the reference to an object with the specified key from + * the dictionary. + */ +void +prop_dictionary_remove(prop_dictionary_t pd, const char *key) +{ + struct _prop_dict_entry *pde; + unsigned int idx; + + if (! prop_object_is_dictionary(pd)) + return; + + _PROP_RWLOCK_WRLOCK(pd->pd_rwlock); + + /* XXX Should this be a _PROP_ASSERT()? */ + if (prop_dictionary_is_immutable(pd)) + goto out; + + pde = _prop_dict_lookup(pd, key, &idx); + /* XXX Should this be a _PROP_ASSERT()? */ + if (pde == NULL) + goto out; + + _prop_dictionary_remove(pd, pde, idx); + out: + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); +} + +/* + * prop_dictionary_remove_keysym -- + * Remove a reference to an object stored in the dictionary at the + * location encoded by the keysym. + */ +void +prop_dictionary_remove_keysym(prop_dictionary_t pd, + prop_dictionary_keysym_t pdk) +{ + + if (! (prop_object_is_dictionary(pd) && + prop_object_is_dictionary_keysym(pdk))) + return; + + prop_dictionary_remove(pd, pdk->pdk_key); +} + +/* + * prop_dictionary_equals -- + * Return true if the two dictionaries are equivalent. Note we do a + * by-value comparison of the objects in the dictionary. + */ +bool +prop_dictionary_equals(prop_dictionary_t dict1, prop_dictionary_t dict2) +{ + if (!prop_object_is_dictionary(dict1) || + !prop_object_is_dictionary(dict2)) + return (false); + + return (prop_object_equals(dict1, dict2)); +} + +/* + * prop_dictionary_keysym_cstring_nocopy -- + * Return an immutable reference to the keysym's value. + */ +const char * +prop_dictionary_keysym_cstring_nocopy(prop_dictionary_keysym_t pdk) +{ + + if (! prop_object_is_dictionary_keysym(pdk)) + return (NULL); + + return (pdk->pdk_key); +} + +/* + * prop_dictionary_keysym_equals -- + * Return true if the two dictionary key symbols are equivalent. + * Note: We do not compare the object references. + */ +bool +prop_dictionary_keysym_equals(prop_dictionary_keysym_t pdk1, + prop_dictionary_keysym_t pdk2) +{ + if (!prop_object_is_dictionary_keysym(pdk1) || + !prop_object_is_dictionary_keysym(pdk2)) + return (false); + + return (prop_object_equals(pdk1, pdk2)); +} + +/* + * prop_dictionary_externalize -- + * Externalize a dictionary, returning a NUL-terminated buffer + * containing the XML-style representation. The buffer is allocated + * with the M_TEMP memory type. + */ +char * +prop_dictionary_externalize(prop_dictionary_t pd) +{ + struct _prop_object_externalize_context *ctx; + char *cp; + + ctx = _prop_object_externalize_context_alloc(); + if (ctx == NULL) + return (NULL); + + if (_prop_object_externalize_header(ctx) == false || + (*pd->pd_obj.po_type->pot_extern)(ctx, pd) == false || + _prop_object_externalize_footer(ctx) == false) { + /* We are responsible for releasing the buffer. */ + _PROP_FREE(ctx->poec_buf, M_TEMP); + _prop_object_externalize_context_free(ctx); + return (NULL); + } + + cp = ctx->poec_buf; + _prop_object_externalize_context_free(ctx); + + return (cp); +} + +/* + * _prop_dictionary_internalize -- + * Parse a ... and return the object created from the + * external representation. + * + * Internal state in via rec_data is the storage area for the last processed + * key. + * _prop_dictionary_internalize_body is the upper half of the parse loop. + * It is responsible for parsing the key directly and storing it in the area + * referenced by rec_data. + * _prop_dictionary_internalize_cont is the lower half and called with the value + * associated with the key. + */ +static bool _prop_dictionary_internalize_body(prop_stack_t, + prop_object_t *, struct _prop_object_internalize_context *, char *); + +bool +_prop_dictionary_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + prop_dictionary_t dict; + char *tmpkey; + + /* We don't currently understand any attributes. */ + if (ctx->poic_tagattr != NULL) + return (true); + + dict = prop_dictionary_create(); + if (dict == NULL) + return (true); + + if (ctx->poic_is_empty_element) { + *obj = dict; + return (true); + } + + tmpkey = _PROP_MALLOC(PDK_MAXKEY + 1, M_TEMP); + if (tmpkey == NULL) { + prop_object_release(dict); + return (true); + } + + *obj = dict; + /* + * Opening tag is found, storage for key allocated and + * now continue to the first element. + */ + return _prop_dictionary_internalize_body(stack, obj, ctx, tmpkey); +} + +static bool +_prop_dictionary_internalize_continue(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx, void *data, prop_object_t child) +{ + prop_dictionary_t dict = *obj; + char *tmpkey = data; + + _PROP_ASSERT(tmpkey != NULL); + + if (child == NULL || + prop_dictionary_set(dict, tmpkey, child) == false) { + _PROP_FREE(tmpkey, M_TEMP); + if (child != NULL) + prop_object_release(child); + prop_object_release(dict); + *obj = NULL; + return (true); + } + + prop_object_release(child); + + /* + * key, value was added, now continue looking for the next key + * or the closing tag. + */ + return _prop_dictionary_internalize_body(stack, obj, ctx, tmpkey); +} + +static bool +_prop_dictionary_internalize_body(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx, char *tmpkey) +{ + prop_dictionary_t dict = *obj; + size_t keylen; + + /* Fetch the next tag. */ + if (_prop_object_internalize_find_tag(ctx, NULL, _PROP_TAG_TYPE_EITHER) == false) + goto bad; + + /* Check to see if this is the end of the dictionary. */ + if (_PROP_TAG_MATCH(ctx, "dict") && + ctx->poic_tag_type == _PROP_TAG_TYPE_END) { + _PROP_FREE(tmpkey, M_TEMP); + return (true); + } + + /* Ok, it must be a non-empty key start tag. */ + if (!_PROP_TAG_MATCH(ctx, "key") || + ctx->poic_tag_type != _PROP_TAG_TYPE_START || + ctx->poic_is_empty_element) + goto bad; + + if (_prop_object_internalize_decode_string(ctx, + tmpkey, PDK_MAXKEY, &keylen, + &ctx->poic_cp) == false) + goto bad; + + _PROP_ASSERT(keylen <= PDK_MAXKEY); + tmpkey[keylen] = '\0'; + + if (_prop_object_internalize_find_tag(ctx, "key", + _PROP_TAG_TYPE_END) == false) + goto bad; + + /* ..and now the beginning of the value. */ + if (_prop_object_internalize_find_tag(ctx, NULL, + _PROP_TAG_TYPE_START) == false) + goto bad; + + /* + * Key is found, now wait for value to be parsed. + */ + if (_prop_stack_push(stack, *obj, + _prop_dictionary_internalize_continue, + tmpkey, NULL)) + return (false); + + bad: + _PROP_FREE(tmpkey, M_TEMP); + prop_object_release(dict); + *obj = NULL; + return (true); +} + +/* + * prop_dictionary_internalize -- + * Create a dictionary by parsing the NUL-terminated XML-style + * representation. + */ +prop_dictionary_t +prop_dictionary_internalize(const char *xml) +{ + return _prop_generic_internalize(xml, "dict"); +} + +/* + * prop_dictionary_externalize_to_file -- + * Externalize a dictionary to the specified file. + */ +bool +prop_dictionary_externalize_to_file(prop_dictionary_t dict, const char *fname) +{ + char *xml; + bool rv; + int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ + + xml = prop_dictionary_externalize(dict); + if (xml == NULL) + return (false); + rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); + if (rv == false) + save_errno = errno; + _PROP_FREE(xml, M_TEMP); + if (rv == false) + errno = save_errno; + + return (rv); +} + +/* + * prop_dictionary_internalize_from_file -- + * Internalize a dictionary from a file. + */ +prop_dictionary_t +prop_dictionary_internalize_from_file(const char *fname) +{ + struct _prop_object_internalize_mapped_file *mf; + prop_dictionary_t dict; + + mf = _prop_object_internalize_map_file(fname); + if (mf == NULL) + return (NULL); + dict = prop_dictionary_internalize(mf->poimf_xml); + _prop_object_internalize_unmap_file(mf); + + return (dict); +} diff --git a/src/prop_dictionary.h b/src/prop_dictionary.h new file mode 100644 index 0000000..3c41106 --- /dev/null +++ b/src/prop_dictionary.h @@ -0,0 +1,143 @@ +/* $NetBSD: prop_dictionary.h,v 1.9 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_DICTIONARY_H_ +#define _PROPLIB_PROP_DICTIONARY_H_ + +#include "prop_object.h" + +typedef struct _prop_dictionary *prop_dictionary_t; +typedef struct _prop_dictionary_keysym *prop_dictionary_keysym_t; + +__BEGIN_DECLS +prop_dictionary_t prop_dictionary_create(void); +prop_dictionary_t prop_dictionary_create_with_capacity(unsigned int); + +prop_dictionary_t prop_dictionary_copy(prop_dictionary_t); +prop_dictionary_t prop_dictionary_copy_mutable(prop_dictionary_t); + +unsigned int prop_dictionary_count(prop_dictionary_t); +bool prop_dictionary_ensure_capacity(prop_dictionary_t, + unsigned int); + +void prop_dictionary_make_immutable(prop_dictionary_t); +bool prop_dictionary_mutable(prop_dictionary_t); + +prop_object_iterator_t prop_dictionary_iterator(prop_dictionary_t); +prop_array_t prop_dictionary_all_keys(prop_dictionary_t); + +prop_object_t prop_dictionary_get(prop_dictionary_t, const char *); +bool prop_dictionary_set(prop_dictionary_t, const char *, + prop_object_t); +void prop_dictionary_remove(prop_dictionary_t, const char *); + +prop_object_t prop_dictionary_get_keysym(prop_dictionary_t, + prop_dictionary_keysym_t); +bool prop_dictionary_set_keysym(prop_dictionary_t, + prop_dictionary_keysym_t, + prop_object_t); +void prop_dictionary_remove_keysym(prop_dictionary_t, + prop_dictionary_keysym_t); + +bool prop_dictionary_equals(prop_dictionary_t, prop_dictionary_t); + +char * prop_dictionary_externalize(prop_dictionary_t); +prop_dictionary_t prop_dictionary_internalize(const char *); + +bool prop_dictionary_externalize_to_file(prop_dictionary_t, + const char *); +prop_dictionary_t prop_dictionary_internalize_from_file(const char *); + +const char * prop_dictionary_keysym_cstring_nocopy(prop_dictionary_keysym_t); + +bool prop_dictionary_keysym_equals(prop_dictionary_keysym_t, + prop_dictionary_keysym_t); + +/* + * Utility routines to make it more convenient to work with values + * stored in dictionaries. + */ +bool prop_dictionary_get_bool(prop_dictionary_t, const char *, + bool *); +bool prop_dictionary_set_bool(prop_dictionary_t, const char *, + bool); + +bool prop_dictionary_get_int8(prop_dictionary_t, const char *, + int8_t *); +bool prop_dictionary_get_uint8(prop_dictionary_t, const char *, + uint8_t *); +bool prop_dictionary_set_int8(prop_dictionary_t, const char *, + int8_t); +bool prop_dictionary_set_uint8(prop_dictionary_t, const char *, + uint8_t); + +bool prop_dictionary_get_int16(prop_dictionary_t, const char *, + int16_t *); +bool prop_dictionary_get_uint16(prop_dictionary_t, const char *, + uint16_t *); +bool prop_dictionary_set_int16(prop_dictionary_t, const char *, + int16_t); +bool prop_dictionary_set_uint16(prop_dictionary_t, const char *, + uint16_t); + +bool prop_dictionary_get_int32(prop_dictionary_t, const char *, + int32_t *); +bool prop_dictionary_get_uint32(prop_dictionary_t, const char *, + uint32_t *); +bool prop_dictionary_set_int32(prop_dictionary_t, const char *, + int32_t); +bool prop_dictionary_set_uint32(prop_dictionary_t, const char *, + uint32_t); + +bool prop_dictionary_get_int64(prop_dictionary_t, const char *, + int64_t *); +bool prop_dictionary_get_uint64(prop_dictionary_t, const char *, + uint64_t *); +bool prop_dictionary_set_int64(prop_dictionary_t, const char *, + int64_t); +bool prop_dictionary_set_uint64(prop_dictionary_t, const char *, + uint64_t); + +bool prop_dictionary_get_cstring(prop_dictionary_t, const char *, + char **); +bool prop_dictionary_set_cstring(prop_dictionary_t, const char *, + const char *); + +bool prop_dictionary_get_cstring_nocopy(prop_dictionary_t, + const char *, + const char **); +bool prop_dictionary_set_cstring_nocopy(prop_dictionary_t, + const char *, + const char *); + +__END_DECLS + +#endif /* _PROPLIB_PROP_DICTIONARY_H_ */ diff --git a/src/prop_dictionary_util.3 b/src/prop_dictionary_util.3 new file mode 100644 index 0000000..2eb7694 --- /dev/null +++ b/src/prop_dictionary_util.3 @@ -0,0 +1,186 @@ +.\" $NetBSD: prop_dictionary_util.3,v 1.4 2008/06/02 09:27:04 haad Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd October 25, 2006 +.Dt PROP_DICTIONARY_UTIL 3 +.Os +.Sh NAME +.Nm prop_dictionary_util , +.Nm prop_dictionary_get_bool , +.Nm prop_dictionary_set_bool , +.Nm prop_dictionary_get_int8 , +.Nm prop_dictionary_get_uint8 , +.Nm prop_dictionary_set_int8 , +.Nm prop_dictionary_set_uint8 , +.Nm prop_dictionary_get_int16 , +.Nm prop_dictionary_get_uint16 , +.Nm prop_dictionary_set_int16 , +.Nm prop_dictionary_set_uint16 , +.Nm prop_dictionary_get_int32 , +.Nm prop_dictionary_get_uint32 , +.Nm prop_dictionary_set_int32 , +.Nm prop_dictionary_set_uint32 , +.Nm prop_dictionary_get_int64 , +.Nm prop_dictionary_get_uint64 , +.Nm prop_dictionary_set_int64 , +.Nm prop_dictionary_set_uint64 , +.Nm prop_dictionary_get_cstring , +.Nm prop_dictionary_set_cstring , +.Nm prop_dictionary_get_cstring_nocopy , +.Nm prop_dictionary_set_cstring_nocopy +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft bool +.Fn prop_dictionary_get_bool "prop_dictionary_t dict" "const char *key" \ + "bool *valp" +.Ft bool +.Fn prop_dictionary_set_bool "prop_dictionary_t dict" "const char *key" \ + "bool val" +.\" +.Ft bool +.Fn prop_dictionary_get_int8 "prop_dictionary_t dict" "const char *key" \ + "int8_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint8 "prop_dictionary_t dict" "const char *key" \ + "uint8_t *valp" +.Ft bool +.Fn prop_dictionary_set_int8 "prop_dictionary_t dict" "const char *key" \ + "int8_t val" +.Ft bool +.Fn prop_dictionary_set_uint8 "prop_dictionary_t dict" "const char *key" \ + "uint8_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int16 "prop_dictionary_t dict" "const char *key" \ + "int16_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint16 "prop_dictionary_t dict" "const char *key" \ + "uint16_t *valp" +.Ft bool +.Fn prop_dictionary_set_int16 "prop_dictionary_t dict" "const char *key" \ + "int16_t val" +.Ft bool +.Fn prop_dictionary_set_uint16 "prop_dictionary_t dict" "const char *key" \ + "uint16_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int32 "prop_dictionary_t dict" "const char *key" \ + "int32_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint32 "prop_dictionary_t dict" "const char *key" \ + "uint32_t *valp" +.Ft bool +.Fn prop_dictionary_set_int32 "prop_dictionary_t dict" "const char *key" \ + "int32_t val" +.Ft bool +.Fn prop_dictionary_set_uint32 "prop_dictionary_t dict" "const char *key" \ + "uint32_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_int64 "prop_dictionary_t dict" "const char *key" \ + "int64_t *valp" +.Ft bool +.Fn prop_dictionary_get_uint64 "prop_dictionary_t dict" "const char *key" \ + "uint64_t *valp" +.Ft bool +.Fn prop_dictionary_set_int64 "prop_dictionary_t dict" "const char *key" \ + "int64_t val" +.Ft bool +.Fn prop_dictionary_set_uint64 "prop_dictionary_t dict" "const char *key" \ + "uint64_t val" +.\" +.Ft bool +.Fn prop_dictionary_get_cstring "prop_dictionary_t dict" "const char *key" \ + "char **strp" +.Ft bool +.Fn prop_dictionary_set_cstring "prop_dictionary_t dict" "const char *key" \ + "const char *str" +.\" +.Ft bool +.Fn prop_dictionary_get_cstring_nocopy "prop_dictionary_t dict" \ + "const char *key" "const char **strp" +.Ft bool +.Fn prop_dictionary_set_cstring_nocopy "prop_dictionary_t dict" \ + "const char *key" "const char *strp" +.Sh DESCRIPTION +The +.Nm prop_dictionary_util +family of functions are provided to make getting and setting values in +dictionaries more convenient in some applications. +.Pp +The getters check the type of the returned object and, in some cases, also +ensure that the returned value is within the range implied by the getter's +value type. +.Pp +The setters handle object creation and release for the caller. +.Pp +The +.Fn prop_dictionary_get_cstring +function returns dynamically allocated memory. +See +.Xr prop_string 3 +for more information. +.Pp +The +.Fn prop_dictionary_get_cstring_nocopy +and +.Fn prop_dictionary_set_cstring_nocopy +functions do not copy the string that is set or returned. +See +.Xr prop_string 3 +for more information. +.Sh RETURN VALUES +The +.Nm prop_dictionary_util +getter functions return +.Dv true +if the object exists in the dictionary and the value is in-range, or +.Dv false +otherwise. +.Pp +The +.Nm prop_dictionary_util +setter functions return +.Dv true +if creating the object and storing it in the dictionary is successful, or +.Dv false +otherwise. +.Sh SEE ALSO +.Xr prop_bool 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_dictionary_util.c b/src/prop_dictionary_util.c new file mode 100644 index 0000000..d7da778 --- /dev/null +++ b/src/prop_dictionary_util.c @@ -0,0 +1,208 @@ +/* $NetBSD: prop_dictionary_util.c,v 1.3 2008/04/28 20:22:53 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Utility routines to make it more convenient to work with values + * stored in dictionaries. + * + * Note: There is no special magic going on here. We use the standard + * proplib(3) APIs to do all of this work. Any application could do + * exactly what we're doing here. + */ + +#include "proplib.h" +#include "prop_object_impl.h" /* only to hide kernel vs. not-kernel */ + +bool +prop_dictionary_get_bool(prop_dictionary_t dict, + const char *key, + bool *valp) +{ + prop_bool_t b; + + b = prop_dictionary_get(dict, key); + if (prop_object_type(b) != PROP_TYPE_BOOL) + return (false); + + *valp = prop_bool_true(b); + + return (true); +} + +bool +prop_dictionary_set_bool(prop_dictionary_t dict, + const char *key, + bool val) +{ + prop_bool_t b; + int rv; + + b = prop_bool_create(val); + if (b == NULL) + return (false); + rv = prop_dictionary_set(dict, key, b); + prop_object_release(b); + + return (rv); +} + +#define TEMPLATE(size) \ +bool \ +prop_dictionary_get_int ## size (prop_dictionary_t dict, \ + const char *key, \ + int ## size ## _t *valp) \ +{ \ + prop_number_t num; \ + \ + num = prop_dictionary_get(dict, key); \ + if (prop_object_type(num) != PROP_TYPE_NUMBER) \ + return (false); \ + \ + if (prop_number_unsigned(num) && \ + prop_number_unsigned_integer_value(num) > \ + /*CONSTCOND*/((size) == 8 ? INT8_MAX : \ + (size) == 16 ? INT16_MAX : \ + (size) == 32 ? INT32_MAX : INT64_MAX)) { \ + return (false); \ + } \ + \ + if (prop_number_size(num) > (size)) \ + return (false); \ + \ + *valp = (int ## size ## _t) prop_number_integer_value(num); \ + \ + return (true); \ +} \ + \ +bool \ +prop_dictionary_get_uint ## size (prop_dictionary_t dict, \ + const char *key, \ + uint ## size ## _t *valp) \ +{ \ + prop_number_t num; \ + \ + num = prop_dictionary_get(dict, key); \ + if (prop_object_type(num) != PROP_TYPE_NUMBER) \ + return (false); \ + \ + if (prop_number_unsigned(num) == false && \ + prop_number_integer_value(num) < 0) { \ + return (false); \ + } \ + \ + if (prop_number_size(num) > (size)) \ + return (false); \ + \ + *valp = (uint ## size ## _t) \ + prop_number_unsigned_integer_value(num); \ + \ + return (true); \ +} \ + \ +bool \ +prop_dictionary_set_int ## size (prop_dictionary_t dict, \ + const char *key, \ + int ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_integer((int64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_dictionary_set(dict, key, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} \ + \ +bool \ +prop_dictionary_set_uint ## size (prop_dictionary_t dict, \ + const char *key, \ + uint ## size ## _t val) \ +{ \ + prop_number_t num; \ + int rv; \ + \ + num = prop_number_create_unsigned_integer((uint64_t) val); \ + if (num == NULL) \ + return (false); \ + rv = prop_dictionary_set(dict, key, num); \ + prop_object_release(num); \ + \ + return (rv); \ +} + +TEMPLATE(8) +TEMPLATE(16) +TEMPLATE(32) +TEMPLATE(64) + +#undef TEMPLATE + +#define TEMPLATE(variant, qualifier) \ +bool \ +prop_dictionary_get_cstring ## variant (prop_dictionary_t dict, \ + const char *key, \ + qualifier char **cpp) \ +{ \ + prop_string_t str; \ + \ + str = prop_dictionary_get(dict, key); \ + if (prop_object_type(str) != PROP_TYPE_STRING) \ + return (false); \ + \ + *cpp = prop_string_cstring ## variant (str); \ + \ + return (*cpp == NULL ? false : true); \ +} \ + \ +bool \ +prop_dictionary_set_cstring ## variant (prop_dictionary_t dict, \ + const char *key, \ + const char *cp) \ +{ \ + prop_string_t str; \ + int rv; \ + \ + str = prop_string_create_cstring ## variant (cp); \ + if (str == NULL) \ + return (false); \ + rv = prop_dictionary_set(dict, key, str); \ + prop_object_release(str); \ + \ + return (rv); \ +} + +TEMPLATE(,) +TEMPLATE(_nocopy,const) + +#undef TEMPLATE diff --git a/src/prop_ingest.3 b/src/prop_ingest.3 new file mode 100644 index 0000000..307ad8d --- /dev/null +++ b/src/prop_ingest.3 @@ -0,0 +1,181 @@ +.\" $NetBSD: prop_ingest.3,v 1.5 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_INGEST 3 +.Os +.Sh NAME +.Nm prop_ingest_context_alloc , +.Nm prop_ingest_context_free , +.Nm prop_ingest_context_error , +.Nm prop_ingest_context_type , +.Nm prop_ingest_context_key , +.Nm prop_ingest_context_private , +.Nm prop_dictionary_ingest +.Nd Ingest a dictionary into an arbitrary binary format +.Sh SYNOPSIS +.In prop/proplib.h +.Ft prop_ingest_context_t +.Fn prop_ingest_context_alloc "void *private" +.Ft void +.Fn prop_ingest_context_free "prop_ingest_context_t ctx" +.Ft prop_ingest_error_t +.Fn prop_ingest_context_error "prop_ingest_context_t ctx" +.Ft prop_type_t +.Fn prop_ingest_context_type "prop_ingest_context_t ctx" +.Ft const char * +.Fn prop_ingest_context_key "prop_ingest_context_t ctx" +.Ft void * +.Fn prop_ingest_context_private "prop_ingest_context_t ctx" +.Ft bool +.Fn prop_dictionary_ingest "prop_dictionary_t dict" \ + "const prop_ingest_table_entry rules[]" \ + "prop_ingest_context_t ctx" +.Pp +.Ft typedef bool +.Fn (*prop_ingest_handler_t) "prop_ingest_context_t" "prop_object_t" +.Sh DESCRIPTION +The +.Nm prop_dictionary_ingest +function provides a convenient way to convert a property list into +an arbitrary binary format or to extract values from dictionaries in a +way that is convenient to an application +.Pq for configuration files, for example . +.Pp +.Nm prop_dictionary_ingest +is driven by a table of rules provided by the application. +Each rule consists of three items: +.Bl -bullet +.It +A C string containing a key to be looked up in the dictionary. +.It +The expected property type of the object associated with the key +(or +.Dv PROP_TYPE_UNKNOWN +to specify that any type is allowed). +.It +A callback function of type +.Dv prop_ingest_handler_t +that will perform the translation for the application. +.El +.Pp +The table is constructed using a series of macros as follows: +.Bd -literal +static const prop_ingest_table_entry ingest_rules[] = { + PROP_INGEST("file-name", PROP_TYPE_STRING, ingest_filename), + PROP_INGEST("count", PROP_TYPE_NUMBER, ingest_count), + PROP_INGEST_OPTIONAL("required", PROP_TYPE_BOOL, ingest_required), + PROP_INGEST_OPTIONAL("extra", PROP_TYPE_UNKNOWN, ingest_extra), + PROP_INGEST_END +}; +.Ed +.Pp +The +.Dv PROP_INGEST +macro specifies that the key is required to be present in the dictionary. +The +.Dv PROP_INGEST_OPTIONAL +macro specifies that the presence of the key in the dictionary is optional. +The +.Dv PROP_INGEST_END +macro marks the end of the rules table. +.Pp +In each case, +.Nm prop_dictionary_ingest +looks up the rule's key in the dictionary. +If an object is present in the dictionary at that key, its type is checked +against the type specified in the rule. +A type specification of +.Dv PROP_TYPE_UNKNOWN +allows the object to be of any type. +If the object does not exist and the rule is not marked as optional, then +an error is returned. +Otherwise, the handler specified in the rule is invoked with the ingest +context and the object +(or +.Dv NULL +if the key does not exist in the dictionary). +The handler should return +.Dv false +if the value of the object is invalid to indicate failure and +.Dv true +otherwise. +.Pp +The ingest context contains several pieces of information that are +useful during the ingest process. +The context also provides specific error information should the ingest +fail. +.Bl -tag -width "xxxxx" +.It Fn prop_ingest_context_alloc "void *private" +Allocate an ingest context. +The argument +.Fa private +may be used to pass application-specific context to the ingest handlers. +Note that an ingest context can be re-used to perform multiple ingests. +Returns +.Dv NULL +on failure. +.It Fn prop_ingest_context_free "prop_ingest_context_t ctx" +Free an ingest context. +.It Fn prop_ingest_context_error "prop_ingest_context_t ctx" +Returns the code indicating the error encountered during ingest. +The following error codes are defined: +.Pp +.Bl -tag -width "PROP_INGEST_ERROR_HANDLER_FAILED" -compact +.It Dv PROP_INGEST_ERROR_NO_ERROR +No error was encountered during ingest. +.It Dv PROP_INGEST_ERROR_NO_KEY +A non-optional key was not found in the dictionary. +.It Dv PROP_INGEST_ERROR_WRONG_TYPE +An object in the dictionary was not the same type specifed in the rules. +.It Dv PROP_INGEST_ERROR_HANDLER_FAILED +An object's handler returned +.Dv false . +.El +.Pp +.It Fn prop_ingest_context_type "prop_ingest_context_t ctx" +Returns the type of the last object visited during an ingest. +When called by an ingest handler, it returns the type of the object +currently being processed. +.It Fn prop_ingest_context_key "prop_ingest_context_t ctx" +Returns the last dictionary key looked up during an ingest. +When called by an ingest handler, it returns the dictionary key corresponding +to the object currently being processed. +.It Fn prop_ingest_context_private "prop_ingest_context_t ctx" +Returns the private data set when the context was allocated with +.Fn prop_ingest_context_alloc . +.El +.Sh SEE ALSO +.Xr prop_dictionary 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_ingest.c b/src/prop_ingest.c new file mode 100644 index 0000000..0c9bdb3 --- /dev/null +++ b/src/prop_ingest.c @@ -0,0 +1,159 @@ +/* $NetBSD: prop_ingest.c,v 1.3 2008/04/28 20:22:53 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "proplib.h" +#include "prop_object_impl.h" + +struct _prop_ingest_context { + prop_ingest_error_t pic_error; + prop_type_t pic_type; + const char * pic_key; + void * pic_private; +}; + +/* + * prop_ingest_context_alloc -- + * Allocate and initialize an ingest context. + */ +prop_ingest_context_t +prop_ingest_context_alloc(void *private) +{ + prop_ingest_context_t ctx; + + ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP); + if (ctx != NULL) { + ctx->pic_error = PROP_INGEST_ERROR_NO_ERROR; + ctx->pic_type = PROP_TYPE_UNKNOWN; + ctx->pic_key = NULL; + ctx->pic_private = private; + } + return (ctx); +} + +/* + * prop_ingest_context_free -- + * Free an ingest context. + */ +void +prop_ingest_context_free(prop_ingest_context_t ctx) +{ + + _PROP_FREE(ctx, M_TEMP); +} + +/* + * prop_ingest_context_error -- + * Get the error code from an ingest context. + */ +prop_ingest_error_t +prop_ingest_context_error(prop_ingest_context_t ctx) +{ + + return (ctx->pic_error); +} + +/* + * prop_ingest_context_type -- + * Return the type of last object visisted by an ingest context. + */ +prop_type_t +prop_ingest_context_type(prop_ingest_context_t ctx) +{ + + return (ctx->pic_type); +} + +/* + * prop_ingest_context_key -- + * Return the last key looked up by an ingest context. + */ +const char * +prop_ingest_context_key(prop_ingest_context_t ctx) +{ + + return (ctx->pic_key); +} + +/* + * prop_ingest_context_private -- + * Return the caller-private data associated with an ingest context. + */ +void * +prop_ingest_context_private(prop_ingest_context_t ctx) +{ + + return (ctx->pic_private); +} + +/* + * prop_dictionary_ingest -- + * Ingest a dictionary using handlers for each object to translate + * into an arbitrary binary format. + */ +bool +prop_dictionary_ingest(prop_dictionary_t dict, + const prop_ingest_table_entry rules[], + prop_ingest_context_t ctx) +{ + const prop_ingest_table_entry *pite; + prop_object_t obj; + + ctx->pic_error = PROP_INGEST_ERROR_NO_ERROR; + + for (pite = rules; pite->pite_key != NULL; pite++) { + ctx->pic_key = pite->pite_key; + obj = prop_dictionary_get(dict, pite->pite_key); + ctx->pic_type = prop_object_type(obj); + if (obj == NULL) { + if (pite->pite_flags & PROP_INGEST_FLAG_OPTIONAL) { + if ((*pite->pite_handler)(ctx, NULL) == false) { + ctx->pic_error = + PROP_INGEST_ERROR_HANDLER_FAILED; + return (false); + } + continue; + } + ctx->pic_error = PROP_INGEST_ERROR_NO_KEY; + return (false); + } + if (ctx->pic_type != pite->pite_type && + pite->pite_type != PROP_TYPE_UNKNOWN) { + ctx->pic_error = PROP_INGEST_ERROR_WRONG_TYPE; + return (false); + } + if ((*pite->pite_handler)(ctx, obj) == false) { + ctx->pic_error = PROP_INGEST_ERROR_HANDLER_FAILED; + return (false); + } + } + + return (true); +} diff --git a/src/prop_ingest.h b/src/prop_ingest.h new file mode 100644 index 0000000..1c6f5fd --- /dev/null +++ b/src/prop_ingest.h @@ -0,0 +1,90 @@ +/* $NetBSD: prop_ingest.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_INGEST_H_ +#define _PROPLIB_PROP_INGEST_H_ + +#include "prop_dictionary.h" + +typedef enum { + PROP_INGEST_ERROR_NO_ERROR = 0, + PROP_INGEST_ERROR_NO_KEY = 1, + PROP_INGEST_ERROR_WRONG_TYPE = 2, + PROP_INGEST_ERROR_HANDLER_FAILED = 3 +} prop_ingest_error_t; + +typedef enum { + PROP_INGEST_FLAG_OPTIONAL = 0x01 +} prop_ingest_flag_t; + +typedef struct _prop_ingest_context *prop_ingest_context_t; + +typedef bool (*prop_ingest_handler_t)(prop_ingest_context_t, prop_object_t); + +typedef struct { + const char *pite_key; + prop_type_t pite_type; + unsigned int pite_flags; + prop_ingest_handler_t pite_handler; +} prop_ingest_table_entry; + +#define PROP_INGEST(key_, type_, handler_) \ + { .pite_key = key_ , \ + .pite_type = type_ , \ + .pite_flags = 0 , \ + .pite_handler = handler_ } + +#define PROP_INGEST_OPTIONAL(key_, type_, handler_) \ + { .pite_key = key_ , \ + .pite_type = type_ , \ + .pite_flags = PROP_INGEST_FLAG_OPTIONAL , \ + .pite_handler = handler_ } + +#define PROP_INGEST_END \ + { .pite_key = NULL } + +__BEGIN_DECLS +prop_ingest_context_t + prop_ingest_context_alloc(void *); +void prop_ingest_context_free(prop_ingest_context_t); + +prop_ingest_error_t + prop_ingest_context_error(prop_ingest_context_t); +prop_type_t prop_ingest_context_type(prop_ingest_context_t); +const char * prop_ingest_context_key(prop_ingest_context_t); +void * prop_ingest_context_private(prop_ingest_context_t); + +bool prop_dictionary_ingest(prop_dictionary_t, + const prop_ingest_table_entry[], + prop_ingest_context_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_INGEST_H_ */ diff --git a/src/prop_number.3 b/src/prop_number.3 new file mode 100644 index 0000000..5082a1f --- /dev/null +++ b/src/prop_number.3 @@ -0,0 +1,204 @@ +.\" $NetBSD: prop_number.3,v 1.9 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_NUMBER 3 +.Os +.Sh NAME +.Nm prop_number , +.Nm prop_number_create_integer , +.Nm prop_number_create_unsigned_integer , +.Nm prop_number_copy , +.Nm prop_number_size , +.Nm prop_number_unsigned , +.Nm prop_number_integer_value , +.Nm prop_number_unsigned_integer_value , +.Nm prop_number_equals , +.Nm prop_number_equals_integer , +.Nm prop_number_equals_unsigned_integer +.Nd numeric value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_number_t +.Fn prop_number_create_integer "int64_t val" +.Ft prop_number_t +.Fn prop_number_create_unsigned_integer "uint64_t val" +.Ft prop_number_t +.Fn prop_number_copy "prop_number_t number" +.\" +.Ft int +.Fn prop_number_size "prop_number_t number" +.Ft bool +.Fn prop_number_unsigned "prop_number_t number" +.Ft int64_t +.Fn prop_number_integer_value "prop_number_t number" +.Ft uint64_t +.Fn prop_number_unsigned_integer_value "prop_number_t number" +.\" +.Ft bool +.Fn prop_number_equals "prop_number_t num1" "prop_number_t num2" +.Ft bool +.Fn prop_number_equals_integer "prop_number_t number" "int64_t val" +.Ft bool +.Fn prop_number_equals_unsigned_integer "prop_number_t number" "uint64_t val" +.Sh DESCRIPTION +The +.Nm prop_number +family of functions operate on a numeric value property object type. +Values are either signed or unsigned, and promoted to a 64-bit type +.Pq int64_t or uint64_t , respectively . +.Pp +It is possible to compare number objects that differ in sign. +Such comparisons first test to see if each object is within the valid +number range of the other: +.Bl -bullet +.It +Signed numbers that are greater than or equal to 0 can be compared to +unsigned numbers. +.It +Unsigned numbers that are less than or equal to the largest signed 64-bit +value +.Pq Dv INT64_MAX +can be compared to signed numbers. +.El +.Pp +Number objects have a different externalized representation depending +on their sign: +.Bl -bullet +.It +Signed numbers are externalized in base-10 +.Pq decimal . +.It +Unsigned numbers are externalized in base-16 +.Pq hexadecimal . +.El +.Pp +When numbers are internalized, the sign of the resulting number object +.Pq and thus its valid range +is determined by a set of rules evaluated in the following order: +.Bl -bullet +.It +If the first character of the number is a +.Sq - +then the number is signed. +.It +If the first two characters of the number are +.Sq 0x +then the number is unsigned. +.It +If the number value fits into the range of a signed number then the +number is signed. +.It +In all other cases, the number is unsigned. +.El +.Bl -tag -width "xxxxx" +.It Fn prop_number_create_integer "int64_t val" +Create a numeric value object with the signed value +.Fa val . +Returns +.Dv NULL +on failure. +.It Fn prop_number_create_unsigned_integer "uint64_t val" +Create a numeric value object with the unsigned value +.Fa val . +Returns +.Dv NULL +on failure. +.It Fn prop_number_copy "prop_number_t number" +Copy a numeric value object. +If the supplied object isn't a numeric value, +.Dv NULL +is returned. +.It Fn prop_number_size "prop_number_t number" +Returns 8, 16, 32, or 64, representing the number of bits required to +hold the value of the object. +If the supplied object isn't a numeric value, +.Dv NULL +is returned. +.It Fn prop_number_unsigned "prop_number_t number" +Returns +.Dv true +if the numeric value object has an unsigned value. +.It Fn prop_number_integer_value "prop_number_t number" +Returns the signed integer value of the numeric value object. +If the supplied object isn't a numeric value, zero is returned. Thus, +it is not possible to distinguish between ``not a prop_number_t'' +and ``prop_number_t has a value of 0''. +.It Fn prop_number_unsigned_integer_value "prop_number_t number" +Returns the unsigned integer value of the numeric value object. +If the supplied object isn't a numeric value, zero is returned. Thus, +it is not possible to distinguish between ``not a prop_number_t'' +and ``prop_number_t has a value of 0''. +.It Fn prop_number_equals "prop_number_t num1" "prop_number_t num2" +Returns +.Dv true +if the two numeric value objects are equivalent. +If at least one of the supplied objects isn't a numeric value, +.Dv false +is returned. +.It Fn prop_number_equals_integer "prop_number_t number" "int64_t val" +Returns +.Dv true +if the object's value is equivalent to the signed value +.Fa val . +If the supplied object isn't a numerical value or if +.Fa val +exceeds +.Dv INT64_MAX , +.Dv false +is returned. +.It Fn prop_number_equals_unsigned_integer "prop_number_t number" \ + "uint64_t val" +Returns +.Dv true +if the object's value is equivalent to the unsigned value +.Fa val . +If the supplied object isn't a numerical value or if +.Fa val +exceeds +.Dv INT64_MAX , +.Dv false +is returned. +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_object 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_number.c b/src/prop_number.c new file mode 100644 index 0000000..3832c47 --- /dev/null +++ b/src/prop_number.c @@ -0,0 +1,560 @@ +/* $NetBSD: prop_number.c,v 1.19 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_number.h" +#include "prop_object_impl.h" +#include "prop_rb_impl.h" + +#include +#include + +struct _prop_number { + struct _prop_object pn_obj; + struct rb_node pn_link; + struct _prop_number_value { + union { + int64_t pnu_signed; + uint64_t pnu_unsigned; + } pnv_un; +#define pnv_signed pnv_un.pnu_signed +#define pnv_unsigned pnv_un.pnu_unsigned + unsigned int pnv_is_unsigned :1, + :31; + } pn_value; +}; + +#define RBNODE_TO_PN(n) \ + ((struct _prop_number *) \ + ((uintptr_t)n - offsetof(struct _prop_number, pn_link))) + +_PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr") + +static _prop_object_free_rv_t + _prop_number_free(prop_stack_t, prop_object_t *); +static bool _prop_number_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_number_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); + +static const struct _prop_object_type _prop_object_type_number = { + .pot_type = PROP_TYPE_NUMBER, + .pot_free = _prop_number_free, + .pot_extern = _prop_number_externalize, + .pot_equals = _prop_number_equals, +}; + +#define prop_object_is_number(x) \ + ((x) != NULL && (x)->pn_obj.po_type == &_prop_object_type_number) + +/* + * Number objects are immutable, and we are likely to have many number + * objects that have the same value. So, to save memory, we unique'ify + * numbers so we only have one copy of each. + */ + +static int +_prop_number_compare_values(const struct _prop_number_value *pnv1, + const struct _prop_number_value *pnv2) +{ + + /* Signed numbers are sorted before unsigned numbers. */ + + if (pnv1->pnv_is_unsigned) { + if (! pnv2->pnv_is_unsigned) + return (1); + if (pnv1->pnv_unsigned < pnv2->pnv_unsigned) + return (-1); + if (pnv1->pnv_unsigned > pnv2->pnv_unsigned) + return (1); + return (0); + } + + if (pnv2->pnv_is_unsigned) + return (-1); + if (pnv1->pnv_signed < pnv2->pnv_signed) + return (-1); + if (pnv1->pnv_signed > pnv2->pnv_signed) + return (1); + return (0); +} + +static int +_prop_number_rb_compare_nodes(const struct rb_node *n1, + const struct rb_node *n2) +{ + const prop_number_t pn1 = RBNODE_TO_PN(n1); + const prop_number_t pn2 = RBNODE_TO_PN(n2); + + return (_prop_number_compare_values(&pn1->pn_value, &pn2->pn_value)); +} + +static int +_prop_number_rb_compare_key(const struct rb_node *n, + const void *v) +{ + const prop_number_t pn = RBNODE_TO_PN(n); + const struct _prop_number_value *pnv = v; + + return (_prop_number_compare_values(&pn->pn_value, pnv)); +} + +static const struct rb_tree_ops _prop_number_rb_tree_ops = { + .rbto_compare_nodes = _prop_number_rb_compare_nodes, + .rbto_compare_key = _prop_number_rb_compare_key, +}; + +static struct rb_tree _prop_number_tree; +static bool _prop_number_tree_initialized; + +_PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex) + +/* ARGSUSED */ +static _prop_object_free_rv_t +_prop_number_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_number_t pn = *obj; + + _PROP_MUTEX_LOCK(_prop_number_tree_mutex); + _prop_rb_tree_remove_node(&_prop_number_tree, &pn->pn_link); + _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); + + _PROP_POOL_PUT(_prop_number_pool, pn); + + return (_PROP_OBJECT_FREE_DONE); +} + +static bool +_prop_number_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_number_t pn = v; + char tmpstr[32]; + + /* + * For unsigned numbers, we output in hex. For signed numbers, + * we output in decimal. + */ + if (pn->pn_value.pnv_is_unsigned) + sprintf(tmpstr, "0x%" PRIx64, pn->pn_value.pnv_unsigned); + else + sprintf(tmpstr, "%" PRIi64, pn->pn_value.pnv_signed); + + if (_prop_object_externalize_start_tag(ctx, "integer") == false || + _prop_object_externalize_append_cstring(ctx, tmpstr) == false || + _prop_object_externalize_end_tag(ctx, "integer") == false) + return (false); + + return (true); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_number_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_number_t num1 = v1; + prop_number_t num2 = v2; + + /* + * There is only ever one copy of a number object at any given + * time, so we can reduce this to a simple pointer equality check + * in the common case. + */ + if (num1 == num2) + return (_PROP_OBJECT_EQUALS_TRUE); + + /* + * If the numbers are the same signed-ness, then we know they + * cannot be equal because they would have had pointer equality. + */ + if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned) + return (_PROP_OBJECT_EQUALS_FALSE); + + /* + * We now have one signed value and one unsigned value. We can + * compare them iff: + * - The unsigned value is not larger than the signed value + * can represent. + * - The signed value is not smaller than the unsigned value + * can represent. + */ + if (num1->pn_value.pnv_is_unsigned) { + /* + * num1 is unsigned and num2 is signed. + */ + if (num1->pn_value.pnv_unsigned > INT64_MAX) + return (_PROP_OBJECT_EQUALS_FALSE); + if (num2->pn_value.pnv_signed < 0) + return (_PROP_OBJECT_EQUALS_FALSE); + } else { + /* + * num1 is signed and num2 is unsigned. + */ + if (num1->pn_value.pnv_signed < 0) + return (_PROP_OBJECT_EQUALS_FALSE); + if (num2->pn_value.pnv_unsigned > INT64_MAX) + return (_PROP_OBJECT_EQUALS_FALSE); + } + + if (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed) + return _PROP_OBJECT_EQUALS_TRUE; + else + return _PROP_OBJECT_EQUALS_FALSE; +} + +static prop_number_t +_prop_number_alloc(const struct _prop_number_value *pnv) +{ + prop_number_t opn, pn; + struct rb_node *n; + bool rv; + + /* + * Check to see if this already exists in the tree. If it does, + * we just retain it and return it. + */ + _PROP_MUTEX_LOCK(_prop_number_tree_mutex); + if (! _prop_number_tree_initialized) { + _prop_rb_tree_init(&_prop_number_tree, + &_prop_number_rb_tree_ops); + _prop_number_tree_initialized = true; + } else { + n = _prop_rb_tree_find(&_prop_number_tree, pnv); + if (n != NULL) { + opn = RBNODE_TO_PN(n); + prop_object_retain(opn); + _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); + return (opn); + } + } + _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); + + /* + * Not in the tree. Create it now. + */ + + pn = _PROP_POOL_GET(_prop_number_pool); + if (pn == NULL) + return (NULL); + + _prop_object_init(&pn->pn_obj, &_prop_object_type_number); + + pn->pn_value = *pnv; + + /* + * We dropped the mutex when we allocated the new object, so + * we have to check again if it is in the tree. + */ + _PROP_MUTEX_LOCK(_prop_number_tree_mutex); + n = _prop_rb_tree_find(&_prop_number_tree, pnv); + if (n != NULL) { + opn = RBNODE_TO_PN(n); + prop_object_retain(opn); + _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); + _PROP_POOL_PUT(_prop_number_pool, pn); + return (opn); + } + rv = _prop_rb_tree_insert_node(&_prop_number_tree, &pn->pn_link); + _PROP_ASSERT(rv == true); + _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); + return (pn); +} + +/* + * prop_number_create_integer -- + * Create a prop_number_t and initialize it with the + * provided integer value. + */ +prop_number_t +prop_number_create_integer(int64_t val) +{ + struct _prop_number_value pnv; + + memset(&pnv, 0, sizeof(pnv)); + pnv.pnv_signed = val; + pnv.pnv_is_unsigned = false; + + return (_prop_number_alloc(&pnv)); +} + +/* + * prop_number_create_unsigned_integer -- + * Create a prop_number_t and initialize it with the + * provided unsigned integer value. + */ +prop_number_t +prop_number_create_unsigned_integer(uint64_t val) +{ + struct _prop_number_value pnv; + + memset(&pnv, 0, sizeof(pnv)); + pnv.pnv_unsigned = val; + pnv.pnv_is_unsigned = true; + + return (_prop_number_alloc(&pnv)); +} + +/* + * prop_number_copy -- + * Copy a prop_number_t. + */ +prop_number_t +prop_number_copy(prop_number_t opn) +{ + + if (! prop_object_is_number(opn)) + return (NULL); + + /* + * Because we only ever allocate one object for any given + * value, this can be reduced to a simple retain operation. + */ + prop_object_retain(opn); + return (opn); +} + +/* + * prop_number_unsigned -- + * Returns true if the prop_number_t has an unsigned value. + */ +bool +prop_number_unsigned(prop_number_t pn) +{ + + return (pn->pn_value.pnv_is_unsigned); +} + +/* + * prop_number_size -- + * Return the size, in bits, required to hold the value of + * the specified number. + */ +int +prop_number_size(prop_number_t pn) +{ + struct _prop_number_value *pnv; + + if (! prop_object_is_number(pn)) + return (0); + + pnv = &pn->pn_value; + + if (pnv->pnv_is_unsigned) { + if (pnv->pnv_unsigned > UINT32_MAX) + return (64); + if (pnv->pnv_unsigned > UINT16_MAX) + return (32); + if (pnv->pnv_unsigned > UINT8_MAX) + return (16); + return (8); + } + + if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN) + return (64); + if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN) + return (32); + if (pnv->pnv_signed > INT8_MAX || pnv->pnv_signed < INT8_MIN) + return (16); + return (8); +} + +/* + * prop_number_integer_value -- + * Get the integer value of a prop_number_t. + */ +int64_t +prop_number_integer_value(prop_number_t pn) +{ + + /* + * XXX Impossible to distinguish between "not a prop_number_t" + * XXX and "prop_number_t has a value of 0". + */ + if (! prop_object_is_number(pn)) + return (0); + + return (pn->pn_value.pnv_signed); +} + +/* + * prop_number_unsigned_integer_value -- + * Get the unsigned integer value of a prop_number_t. + */ +uint64_t +prop_number_unsigned_integer_value(prop_number_t pn) +{ + + /* + * XXX Impossible to distinguish between "not a prop_number_t" + * XXX and "prop_number_t has a value of 0". + */ + if (! prop_object_is_number(pn)) + return (0); + + return (pn->pn_value.pnv_unsigned); +} + +/* + * prop_number_equals -- + * Return true if two numbers are equivalent. + */ +bool +prop_number_equals(prop_number_t num1, prop_number_t num2) +{ + if (!prop_object_is_number(num1) || !prop_object_is_number(num2)) + return (false); + + return (prop_object_equals(num1, num2)); +} + +/* + * prop_number_equals_integer -- + * Return true if the number is equivalent to the specified integer. + */ +bool +prop_number_equals_integer(prop_number_t pn, int64_t val) +{ + + if (! prop_object_is_number(pn)) + return (false); + + if (pn->pn_value.pnv_is_unsigned && + (pn->pn_value.pnv_unsigned > INT64_MAX || val < 0)) + return (false); + + return (pn->pn_value.pnv_signed == val); +} + +/* + * prop_number_equals_unsigned_integer -- + * Return true if the number is equivalent to the specified + * unsigned integer. + */ +bool +prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val) +{ + + if (! prop_object_is_number(pn)) + return (false); + + if (! pn->pn_value.pnv_is_unsigned && + (pn->pn_value.pnv_signed < 0 || val > INT64_MAX)) + return (false); + + return (pn->pn_value.pnv_unsigned == val); +} + +static bool +_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx, + struct _prop_number_value *pnv) +{ + char *cp; + + _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) == + sizeof(uint64_t)); + + errno = 0; + pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0); + if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE) + return (false); + pnv->pnv_is_unsigned = true; + ctx->poic_cp = cp; + + return (true); +} + +static bool +_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx, + struct _prop_number_value *pnv) +{ + char *cp; + + _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t)); + + errno = 0; + pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0); + if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) && + errno == ERANGE) + return (false); + pnv->pnv_is_unsigned = false; + ctx->poic_cp = cp; + + return (true); +} + +/* + * _prop_number_internalize -- + * Parse a ... and return the object created from + * the external representation. + */ +/* ARGSUSED */ +bool +_prop_number_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + struct _prop_number_value pnv; + + memset(&pnv, 0, sizeof(pnv)); + + /* No attributes, no empty elements. */ + if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element) + return (true); + + /* + * If the first character is '-', then we treat as signed. + * If the first two characters are "0x" (i.e. the number is + * in hex), then we treat as unsigned. Otherwise, we try + * signed first, and if that fails (presumably due to ERANGE), + * then we switch to unsigned. + */ + if (ctx->poic_cp[0] == '-') { + if (_prop_number_internalize_signed(ctx, &pnv) == false) + return (true); + } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') { + if (_prop_number_internalize_unsigned(ctx, &pnv) == false) + return (true); + } else { + if (_prop_number_internalize_signed(ctx, &pnv) == false && + _prop_number_internalize_unsigned(ctx, &pnv) == false) + return (true); + } + + if (_prop_object_internalize_find_tag(ctx, "integer", + _PROP_TAG_TYPE_END) == false) + return (true); + + *obj = _prop_number_alloc(&pnv); + return (true); +} diff --git a/src/prop_number.h b/src/prop_number.h new file mode 100644 index 0000000..d5b9123 --- /dev/null +++ b/src/prop_number.h @@ -0,0 +1,57 @@ +/* $NetBSD: prop_number.h,v 1.6 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_NUMBER_H_ +#define _PROPLIB_PROP_NUMBER_H_ + +#include +#include "prop_object.h" + +typedef struct _prop_number *prop_number_t; + +__BEGIN_DECLS +prop_number_t prop_number_create_integer(int64_t); +prop_number_t prop_number_create_unsigned_integer(uint64_t); + +prop_number_t prop_number_copy(prop_number_t); + +int prop_number_size(prop_number_t); +bool prop_number_unsigned(prop_number_t); + +int64_t prop_number_integer_value(prop_number_t); +uint64_t prop_number_unsigned_integer_value(prop_number_t); + +bool prop_number_equals(prop_number_t, prop_number_t); +bool prop_number_equals_integer(prop_number_t, int64_t); +bool prop_number_equals_unsigned_integer(prop_number_t, uint64_t); +__END_DECLS + +#endif /* _PROPLIB_PROP_NUMBER_H_ */ diff --git a/src/prop_object.3 b/src/prop_object.3 new file mode 100644 index 0000000..bb1a3f1 --- /dev/null +++ b/src/prop_object.3 @@ -0,0 +1,140 @@ +.\" $NetBSD: prop_object.3,v 1.7 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 21, 2006 +.Dt PROP_OBJECT 3 +.Os +.Sh NAME +.Nm prop_object , +.Nm prop_object_retain , +.Nm prop_object_release , +.Nm prop_object_type , +.Nm prop_object_equals , +.Nm prop_object_iterator_next , +.Nm prop_object_iterator_reset , +.Nm prop_object_iterator_release +.Nd general property container object functions +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft void +.Fn prop_object_retain "prop_object_t obj" +.Ft void +.Fn prop_object_release "prop_object_t obj" +.\" +.Ft prop_type_t +.Fn prop_object_type "prop_object_t obj" +.Ft bool +.Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2" +.\" +.Ft prop_object_t +.Fn prop_object_iterator_next "prop_object_iterator_t iter" +.Ft void +.Fn prop_object_iterator_reset "prop_object_iterator_t iter" +.Ft void +.Fn prop_object_iterator_release "prop_object_iterator_t iter" +.Sh DESCRIPTION +The +.Nm prop_object +family of functions operate on all property container object types. +.Bl -tag -width "" +.It Fn prop_object_retain "prop_object_t obj" +Increment the reference count on an object. +.It Fn prop_object_release "prop_object_t obj" +Decrement the reference count on an object. +If the last reference is dropped, the object is freed. +.It Fn prop_object_type "prop_object_t obj" +Determine the type of the object. Objects are one of the following types: +.Pp +.Bl -tag -width "PROP_TYPE_DICT_KEYSYM" -compact +.It Dv PROP_TYPE_BOOL +Boolean value +.Pq prop_bool_t +.It Dv PROP_TYPE_NUMBER +Number +.Pq prop_number_t +.It Dv PROP_TYPE_STRING +String +.Pq prop_string_t +.It Dv PROP_TYPE_DATA +Opaque data +.Pq prop_data_t +.It Dv PROP_TYPE_ARRAY +Array +.Pq prop_array_t +.It Dv PROP_TYPE_DICTIONARY +Dictionary +.Pq prop_dictionary_t +.It Dv PROP_TYPE_DICT_KEYSYM +Dictionary key symbol +.Pq prop_dictionary_keysym_t +.El +.Pp +If +.Fa obj +is +.Dv NULL , +then +.Dv PROP_TYPE_UNKNOWN +is returned. +.It Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2" +Returns +.Dv true +if the two objects are of the same type and are equivalent. +.It Fn prop_object_iterator_next "prop_object_iterator_t iter" +Return the next object in the collection +.Pq array or dictionary +being iterated by the iterator +.Fa iter . +If there are no more objects in the collection, +.Dv NULL +is returned. +.It Fn prop_object_iterator_reset "prop_object_iterator_t iter" +Reset the iterator to the first object in the collection being iterated +by the iterator +.Fa iter . +.It Fn prop_object_iterator_release "prop_object_iterator_t iter" +Release the iterator +.Fa iter . +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_string 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_object.c b/src/prop_object.c new file mode 100644 index 0000000..b4eabca --- /dev/null +++ b/src/prop_object.c @@ -0,0 +1,1184 @@ +/* $NetBSD: prop_object.c,v 1.22 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_object.h" +#include "prop_object_impl.h" + +#include +#include +#include +#include +#include +#include + +/* + * _prop_object_init -- + * Initialize an object. Called when sub-classes create + * an instance. + */ +void +_prop_object_init(struct _prop_object *po, const struct _prop_object_type *pot) +{ + + po->po_type = pot; + po->po_refcnt = 1; +} + +/* + * _prop_object_fini -- + * Finalize an object. Called when sub-classes destroy + * an instance. + */ +/*ARGSUSED*/ +void +_prop_object_fini(struct _prop_object *po _PROP_ARG_UNUSED) +{ + /* Nothing to do, currently. */ +} + +/* + * _prop_object_externalize_start_tag -- + * Append an XML-style start tag to the externalize buffer. + */ +bool +_prop_object_externalize_start_tag( + struct _prop_object_externalize_context *ctx, const char *tag) +{ + unsigned int i; + + for (i = 0; i < ctx->poec_depth; i++) { + if (_prop_object_externalize_append_char(ctx, '\t') == false) + return (false); + } + if (_prop_object_externalize_append_char(ctx, '<') == false || + _prop_object_externalize_append_cstring(ctx, tag) == false || + _prop_object_externalize_append_char(ctx, '>') == false) + return (false); + + return (true); +} + +/* + * _prop_object_externalize_end_tag -- + * Append an XML-style end tag to the externalize buffer. + */ +bool +_prop_object_externalize_end_tag( + struct _prop_object_externalize_context *ctx, const char *tag) +{ + + if (_prop_object_externalize_append_char(ctx, '<') == false || + _prop_object_externalize_append_char(ctx, '/') == false || + _prop_object_externalize_append_cstring(ctx, tag) == false || + _prop_object_externalize_append_char(ctx, '>') == false || + _prop_object_externalize_append_char(ctx, '\n') == false) + return (false); + + return (true); +} + +/* + * _prop_object_externalize_empty_tag -- + * Append an XML-style empty tag to the externalize buffer. + */ +bool +_prop_object_externalize_empty_tag( + struct _prop_object_externalize_context *ctx, const char *tag) +{ + unsigned int i; + + for (i = 0; i < ctx->poec_depth; i++) { + if (_prop_object_externalize_append_char(ctx, '\t') == false) + return (false); + } + + if (_prop_object_externalize_append_char(ctx, '<') == false || + _prop_object_externalize_append_cstring(ctx, tag) == false || + _prop_object_externalize_append_char(ctx, '/') == false || + _prop_object_externalize_append_char(ctx, '>') == false || + _prop_object_externalize_append_char(ctx, '\n') == false) + return (false); + + return (true); +} + +/* + * _prop_object_externalize_append_cstring -- + * Append a C string to the externalize buffer. + */ +bool +_prop_object_externalize_append_cstring( + struct _prop_object_externalize_context *ctx, const char *cp) +{ + + while (*cp != '\0') { + if (_prop_object_externalize_append_char(ctx, + (unsigned char) *cp) == false) + return (false); + cp++; + } + + return (true); +} + +/* + * _prop_object_externalize_append_encoded_cstring -- + * Append an encoded C string to the externalize buffer. + */ +bool +_prop_object_externalize_append_encoded_cstring( + struct _prop_object_externalize_context *ctx, const char *cp) +{ + + while (*cp != '\0') { + switch (*cp) { + case '<': + if (_prop_object_externalize_append_cstring(ctx, + "<") == false) + return (false); + break; + case '>': + if (_prop_object_externalize_append_cstring(ctx, + ">") == false) + return (false); + break; + case '&': + if (_prop_object_externalize_append_cstring(ctx, + "&") == false) + return (false); + break; + default: + if (_prop_object_externalize_append_char(ctx, + (unsigned char) *cp) == false) + return (false); + break; + } + cp++; + } + + return (true); +} + +#define BUF_EXPAND 256 + +/* + * _prop_object_externalize_append_char -- + * Append a single character to the externalize buffer. + */ +bool +_prop_object_externalize_append_char( + struct _prop_object_externalize_context *ctx, unsigned char c) +{ + + _PROP_ASSERT(ctx->poec_capacity != 0); + _PROP_ASSERT(ctx->poec_buf != NULL); + _PROP_ASSERT(ctx->poec_len <= ctx->poec_capacity); + + if (ctx->poec_len == ctx->poec_capacity) { + char *cp = _PROP_REALLOC(ctx->poec_buf, + ctx->poec_capacity + BUF_EXPAND, + M_TEMP); + if (cp == NULL) + return (false); + ctx->poec_capacity = ctx->poec_capacity + BUF_EXPAND; + ctx->poec_buf = cp; + } + + ctx->poec_buf[ctx->poec_len++] = c; + + return (true); +} + +/* + * _prop_object_externalize_header -- + * Append the standard XML header to the externalize buffer. + */ +bool +_prop_object_externalize_header(struct _prop_object_externalize_context *ctx) +{ + static const char _plist_xml_header[] = +"\n" +"\n"; + + if (_prop_object_externalize_append_cstring(ctx, + _plist_xml_header) == false || + _prop_object_externalize_start_tag(ctx, + "plist version=\"1.0\"") == false || + _prop_object_externalize_append_char(ctx, '\n') == false) + return (false); + + return (true); +} + +/* + * _prop_object_externalize_footer -- + * Append the standard XML footer to the externalize buffer. This + * also NUL-terminates the buffer. + */ +bool +_prop_object_externalize_footer(struct _prop_object_externalize_context *ctx) +{ + + if (_prop_object_externalize_end_tag(ctx, "plist") == false || + _prop_object_externalize_append_char(ctx, '\0') == false) + return (false); + + return (true); +} + +/* + * _prop_object_externalize_context_alloc -- + * Allocate an externalize context. + */ +struct _prop_object_externalize_context * +_prop_object_externalize_context_alloc(void) +{ + struct _prop_object_externalize_context *ctx; + + ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP); + if (ctx != NULL) { + ctx->poec_buf = _PROP_MALLOC(BUF_EXPAND, M_TEMP); + if (ctx->poec_buf == NULL) { + _PROP_FREE(ctx, M_TEMP); + return (NULL); + } + ctx->poec_len = 0; + ctx->poec_capacity = BUF_EXPAND; + ctx->poec_depth = 0; + } + return (ctx); +} + +/* + * _prop_object_externalize_context_free -- + * Free an externalize context. + */ +void +_prop_object_externalize_context_free( + struct _prop_object_externalize_context *ctx) +{ + + /* Buffer is always freed by the caller. */ + _PROP_FREE(ctx, M_TEMP); +} + +/* + * _prop_object_internalize_skip_comment -- + * Skip the body and end tag of a comment. + */ +static bool +_prop_object_internalize_skip_comment( + struct _prop_object_internalize_context *ctx) +{ + const char *cp = ctx->poic_cp; + + while (!_PROP_EOF(*cp)) { + if (cp[0] == '-' && + cp[1] == '-' && + cp[2] == '>') { + ctx->poic_cp = cp + 3; + return (true); + } + cp++; + } + + return (false); /* ran out of buffer */ +} + +/* + * _prop_object_internalize_find_tag -- + * Find the next tag in an XML stream. Optionally compare the found + * tag to an expected tag name. State of the context is undefined + * if this routine returns false. Upon success, the context points + * to the first octet after the tag. + */ +bool +_prop_object_internalize_find_tag(struct _prop_object_internalize_context *ctx, + const char *tag, _prop_tag_type_t type) +{ + const char *cp; + size_t taglen; + + if (tag != NULL) + taglen = strlen(tag); + else + taglen = 0; + + start_over: + cp = ctx->poic_cp; + + /* + * Find the start of the tag. + */ + while (_PROP_ISSPACE(*cp)) + cp++; + if (_PROP_EOF(*cp)) + return (false); + + if (*cp != '<') + return (false); + + ctx->poic_tag_start = cp++; + if (_PROP_EOF(*cp)) + return (false); + + if (*cp == '!') { + if (cp[1] != '-' || cp[2] != '-') + return (false); + /* + * Comment block -- only allowed if we are allowed to + * return a start tag. + */ + if (type == _PROP_TAG_TYPE_END) + return (false); + ctx->poic_cp = cp + 3; + if (_prop_object_internalize_skip_comment(ctx) == false) + return (false); + goto start_over; + } + + if (*cp == '/') { + if (type != _PROP_TAG_TYPE_END && + type != _PROP_TAG_TYPE_EITHER) + return (false); + cp++; + if (_PROP_EOF(*cp)) + return (false); + ctx->poic_tag_type = _PROP_TAG_TYPE_END; + } else { + if (type != _PROP_TAG_TYPE_START && + type != _PROP_TAG_TYPE_EITHER) + return (false); + ctx->poic_tag_type = _PROP_TAG_TYPE_START; + } + + ctx->poic_tagname = cp; + + while (!_PROP_ISSPACE(*cp) && *cp != '/' && *cp != '>') + cp++; + if (_PROP_EOF(*cp)) + return (false); + + ctx->poic_tagname_len = cp - ctx->poic_tagname; + + /* Make sure this is the tag we're looking for. */ + if (tag != NULL && + (taglen != ctx->poic_tagname_len || + memcmp(tag, ctx->poic_tagname, taglen) != 0)) + return (false); + + /* Check for empty tag. */ + if (*cp == '/') { + if (ctx->poic_tag_type != _PROP_TAG_TYPE_START) + return(false); /* only valid on start tags */ + ctx->poic_is_empty_element = true; + cp++; + if (_PROP_EOF(*cp) || *cp != '>') + return (false); + } else + ctx->poic_is_empty_element = false; + + /* Easy case of no arguments. */ + if (*cp == '>') { + ctx->poic_tagattr = NULL; + ctx->poic_tagattr_len = 0; + ctx->poic_tagattrval = NULL; + ctx->poic_tagattrval_len = 0; + ctx->poic_cp = cp + 1; + return (true); + } + + _PROP_ASSERT(!_PROP_EOF(*cp)); + cp++; + if (_PROP_EOF(*cp)) + return (false); + + while (_PROP_ISSPACE(*cp)) + cp++; + if (_PROP_EOF(*cp)) + return (false); + + ctx->poic_tagattr = cp; + + while (!_PROP_ISSPACE(*cp) && *cp != '=') + cp++; + if (_PROP_EOF(*cp)) + return (false); + + ctx->poic_tagattr_len = cp - ctx->poic_tagattr; + + cp++; + if (*cp != '\"') + return (false); + cp++; + if (_PROP_EOF(*cp)) + return (false); + + ctx->poic_tagattrval = cp; + while (*cp != '\"') + cp++; + if (_PROP_EOF(*cp)) + return (false); + ctx->poic_tagattrval_len = cp - ctx->poic_tagattrval; + + cp++; + if (*cp != '>') + return (false); + + ctx->poic_cp = cp + 1; + return (true); +} + +/* + * _prop_object_internalize_decode_string -- + * Decode an encoded string. + */ +bool +_prop_object_internalize_decode_string( + struct _prop_object_internalize_context *ctx, + char *target, size_t targsize, size_t *sizep, + const char **cpp) +{ + const char *src; + size_t tarindex; + char c; + + tarindex = 0; + src = ctx->poic_cp; + + for (;;) { + if (_PROP_EOF(*src)) + return (false); + if (*src == '<') { + break; + } + + if ((c = *src) == '&') { + if (src[1] == 'a' && + src[2] == 'm' && + src[3] == 'p' && + src[4] == ';') { + c = '&'; + src += 5; + } else if (src[1] == 'l' && + src[2] == 't' && + src[3] == ';') { + c = '<'; + src += 4; + } else if (src[1] == 'g' && + src[2] == 't' && + src[3] == ';') { + c = '>'; + src += 4; + } else if (src[1] == 'a' && + src[2] == 'p' && + src[3] == 'o' && + src[4] == 's' && + src[5] == ';') { + c = '\''; + src += 6; + } else if (src[1] == 'q' && + src[2] == 'u' && + src[3] == 'o' && + src[4] == 't' && + src[5] == ';') { + c = '\"'; + src += 6; + } else + return (false); + } else + src++; + if (target) { + if (tarindex >= targsize) + return (false); + target[tarindex] = c; + } + tarindex++; + } + + _PROP_ASSERT(*src == '<'); + if (sizep != NULL) + *sizep = tarindex; + if (cpp != NULL) + *cpp = src; + + return (true); +} + +/* + * _prop_object_internalize_match -- + * Returns true if the two character streams match. + */ +bool +_prop_object_internalize_match(const char *str1, size_t len1, + const char *str2, size_t len2) +{ + + return (len1 == len2 && memcmp(str1, str2, len1) == 0); +} + +#define INTERNALIZER(t, f) \ +{ t, sizeof(t) - 1, f } + +static const struct _prop_object_internalizer { + const char *poi_tag; + size_t poi_taglen; + prop_object_internalizer_t poi_intern; +} _prop_object_internalizer_table[] = { + INTERNALIZER("array", _prop_array_internalize), + + INTERNALIZER("true", _prop_bool_internalize), + INTERNALIZER("false", _prop_bool_internalize), + + INTERNALIZER("data", _prop_data_internalize), + + INTERNALIZER("dict", _prop_dictionary_internalize), + + INTERNALIZER("integer", _prop_number_internalize), + + INTERNALIZER("string", _prop_string_internalize), + + { 0, 0, NULL } +}; + +#undef INTERNALIZER + +/* + * _prop_object_internalize_by_tag -- + * Determine the object type from the tag in the context and + * internalize it. + */ +prop_object_t +_prop_object_internalize_by_tag(struct _prop_object_internalize_context *ctx) +{ + const struct _prop_object_internalizer *poi; + prop_object_t obj, parent_obj; + void *data, *iter; + prop_object_internalizer_continue_t iter_func; + struct _prop_stack stack; + + _prop_stack_init(&stack); + +match_start: + for (poi = _prop_object_internalizer_table; + poi->poi_tag != NULL; poi++) { + if (_prop_object_internalize_match(ctx->poic_tagname, + ctx->poic_tagname_len, + poi->poi_tag, + poi->poi_taglen)) + break; + } + if (poi == NULL) { + while (_prop_stack_pop(&stack, &obj, &iter, &data, NULL)) { + iter_func = (prop_object_internalizer_continue_t)iter; + (*iter_func)(&stack, &obj, ctx, data, NULL); + } + + return (NULL); + } + + obj = NULL; + if (!(*poi->poi_intern)(&stack, &obj, ctx)) + goto match_start; + + parent_obj = obj; + while (_prop_stack_pop(&stack, &parent_obj, &iter, &data, NULL)) { + iter_func = (prop_object_internalizer_continue_t)iter; + if (!(*iter_func)(&stack, &parent_obj, ctx, data, obj)) + goto match_start; + obj = parent_obj; + } + + return (parent_obj); +} + +prop_object_t +_prop_generic_internalize(const char *xml, const char *master_tag) +{ + prop_object_t obj = NULL; + struct _prop_object_internalize_context *ctx; + + ctx = _prop_object_internalize_context_alloc(xml); + if (ctx == NULL) + return (NULL); + + /* We start with a tag. */ + if (_prop_object_internalize_find_tag(ctx, "plist", + _PROP_TAG_TYPE_START) == false) + goto out; + + /* Plist elements cannot be empty. */ + if (ctx->poic_is_empty_element) + goto out; + + /* + * We don't understand any plist attributes, but Apple XML + * property lists often have a "version" attribute. If we + * see that one, we simply ignore it. + */ + if (ctx->poic_tagattr != NULL && + !_PROP_TAGATTR_MATCH(ctx, "version")) + goto out; + + /* Next we expect to see opening master_tag. */ + if (_prop_object_internalize_find_tag(ctx, master_tag, + _PROP_TAG_TYPE_START) == false) + goto out; + + obj = _prop_object_internalize_by_tag(ctx); + if (obj == NULL) + goto out; + + /* + * We've advanced past the closing master_tag. + * Now we want . + */ + if (_prop_object_internalize_find_tag(ctx, "plist", + _PROP_TAG_TYPE_END) == false) { + prop_object_release(obj); + obj = NULL; + } + + out: + _prop_object_internalize_context_free(ctx); + return (obj); +} + +/* + * _prop_object_internalize_context_alloc -- + * Allocate an internalize context. + */ +struct _prop_object_internalize_context * +_prop_object_internalize_context_alloc(const char *xml) +{ + struct _prop_object_internalize_context *ctx; + + ctx = _PROP_MALLOC(sizeof(struct _prop_object_internalize_context), + M_TEMP); + if (ctx == NULL) + return (NULL); + + ctx->poic_xml = ctx->poic_cp = xml; + + /* + * Skip any whitespace and XML preamble stuff that we don't + * know about / care about. + */ + for (;;) { + while (_PROP_ISSPACE(*xml)) + xml++; + if (_PROP_EOF(*xml) || *xml != '<') + goto bad; + +#define MATCH(str) (memcmp(&xml[1], str, sizeof(str) - 1) == 0) + + /* + * Skip over the XML preamble that Apple XML property + * lists usually include at the top of the file. + */ + if (MATCH("?xml ") || + MATCH("!DOCTYPE plist")) { + while (*xml != '>' && !_PROP_EOF(*xml)) + xml++; + if (_PROP_EOF(*xml)) + goto bad; + xml++; /* advance past the '>' */ + continue; + } + + if (MATCH(" S | + * | Q S --> Q * | + * | --> | + */ + standin_father = standin; + KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other])); + KASSERT(!RB_SENTINEL_P(self->rb_nodes[standin_other])); + KASSERT(self->rb_nodes[standin_which] == standin); + /* + * Make our brother our son. + */ + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + standin->rb_nodes[standin_other]->rb_parent = standin; + KASSERT(standin->rb_nodes[standin_other]->rb_position == standin_other); + } else { + /* + * | P --> P | + * | S --> Q | + * | Q --> | + */ + standin_father = standin->rb_parent; + standin_father->rb_nodes[standin_which] = + standin->rb_nodes[standin_which]; + standin->rb_left = self->rb_left; + standin->rb_right = self->rb_right; + standin->rb_left->rb_parent = standin; + standin->rb_right->rb_parent = standin; + } + + /* + * Now copy the result of self to standin and then replace + * self with standin in the tree. + */ + standin->rb_parent = self->rb_parent; + standin->rb_properties = self->rb_properties; + standin->rb_parent->rb_nodes[standin->rb_position] = standin; + + /* + * Remove ourselves from the node list and decrement the count. + */ + RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); + RBT_COUNT_DECR(rbt); + + KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); + KASSERT(rb_tree_check_node(rbt, standin_father, NULL, false)); + + if (!rebalance) + return; + + rb_tree_removal_rebalance(rbt, standin_father, standin_which); + KASSERT(rb_tree_check_node(rbt, standin, NULL, true)); +} + +/* + * We could do this by doing + * rb_tree_node_swap(rbt, self, which); + * rb_tree_prune_node(rbt, self, false); + * + * But it's more efficient to just evalate and recolor the child. + */ +/*ARGSUSED*/ +static void +rb_tree_prune_blackred_branch(struct rb_tree *rbt _PROP_ARG_UNUSED, + struct rb_node *self, unsigned int which) +{ + struct rb_node *parent = self->rb_parent; + struct rb_node *child = self->rb_nodes[which]; + + KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT); + KASSERT(RB_BLACK_P(self) && RB_RED_P(child)); + KASSERT(!RB_TWOCHILDREN_P(child)); + KASSERT(RB_CHILDLESS_P(child)); + KASSERT(rb_tree_check_node(rbt, self, NULL, false)); + KASSERT(rb_tree_check_node(rbt, child, NULL, false)); + + /* + * Remove ourselves from the tree and give our former child our + * properties (position, color, root). + */ + parent->rb_nodes[self->rb_position] = child; + child->rb_parent = parent; + child->rb_properties = self->rb_properties; + + /* + * Remove ourselves from the node list and decrement the count. + */ + RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); + RBT_COUNT_DECR(rbt); + + KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, parent, NULL, true)); + KASSERT(rb_tree_check_node(rbt, child, NULL, true)); +} +/* + * + */ +void +_prop_rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self) +{ + struct rb_node *standin; + unsigned int which; + /* + * In the following diagrams, we (the node to be removed) are S. Red + * nodes are lowercase. T could be either red or black. + * + * Remember the major axiom of the red-black tree: the number of + * black nodes from the root to each leaf is constant across all + * leaves, only the number of red nodes varies. + * + * Thus removing a red leaf doesn't require any other changes to a + * red-black tree. So if we must remove a node, attempt to rearrange + * the tree so we can remove a red node. + * + * The simpliest case is a childless red node or a childless root node: + * + * | T --> T | or | R --> * | + * | s --> * | + */ + if (RB_CHILDLESS_P(self)) { + if (RB_RED_P(self) || RB_ROOT_P(self)) { + rb_tree_prune_node(rbt, self, false); + return; + } + rb_tree_prune_node(rbt, self, true); + return; + } + KASSERT(!RB_CHILDLESS_P(self)); + if (!RB_TWOCHILDREN_P(self)) { + /* + * The next simpliest case is the node we are deleting is + * black and has one red child. + * + * | T --> T --> T | + * | S --> R --> R | + * | r --> s --> * | + */ + which = RB_LEFT_SENTINEL_P(self) ? RB_NODE_RIGHT : RB_NODE_LEFT; + KASSERT(RB_BLACK_P(self)); + KASSERT(RB_RED_P(self->rb_nodes[which])); + KASSERT(RB_CHILDLESS_P(self->rb_nodes[which])); + rb_tree_prune_blackred_branch(rbt, self, which); + return; + } + KASSERT(RB_TWOCHILDREN_P(self)); + + /* + * We invert these because we prefer to remove from the inside of + * the tree. + */ + which = self->rb_position ^ RB_NODE_OTHER; + + /* + * Let's find the node closes to us opposite of our parent + * Now swap it with ourself, "prune" it, and rebalance, if needed. + */ + standin = _prop_rb_tree_iterate(rbt, self, which); + rb_tree_swap_prune_and_rebalance(rbt, self, standin); +} + +static void +rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent, + unsigned int which) +{ + KASSERT(!RB_SENTINEL_P(parent)); + KASSERT(RB_SENTINEL_P(parent->rb_nodes[which])); + KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT); + + while (RB_BLACK_P(parent->rb_nodes[which])) { + unsigned int other = which ^ RB_NODE_OTHER; + struct rb_node *brother = parent->rb_nodes[other]; + + KASSERT(!RB_SENTINEL_P(brother)); + /* + * For cases 1, 2a, and 2b, our brother's children must + * be black and our father must be black + */ + if (RB_BLACK_P(parent) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)) { + /* + * Case 1: Our brother is red, swap its position + * (and colors) with our parent. This is now case 2b. + * + * B -> D + * x d -> b E + * C E -> x C + */ + if (RB_RED_P(brother)) { + KASSERT(RB_BLACK_P(parent)); + rb_tree_reparent_nodes(rbt, parent, other); + brother = parent->rb_nodes[other]; + KASSERT(!RB_SENTINEL_P(brother)); + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_RED_P(parent)); + KASSERT(rb_tree_check_node(rbt, brother, NULL, false)); + KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); + } else { + /* + * Both our parent and brother are black. + * Change our brother to red, advance up rank + * and go through the loop again. + * + * B -> B + * A D -> A d + * C E -> C E + */ + RB_MARK_RED(brother); + KASSERT(RB_BLACK_P(brother->rb_left)); + KASSERT(RB_BLACK_P(brother->rb_right)); + if (RB_ROOT_P(parent)) + return; + KASSERT(rb_tree_check_node(rbt, brother, NULL, false)); + KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); + which = parent->rb_position; + parent = parent->rb_parent; + } + } else if (RB_RED_P(parent) + && RB_BLACK_P(brother) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)) { + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_BLACK_P(brother->rb_left)); + KASSERT(RB_BLACK_P(brother->rb_right)); + RB_MARK_BLACK(parent); + RB_MARK_RED(brother); + KASSERT(rb_tree_check_node(rbt, brother, NULL, true)); + break; /* We're done! */ + } else { + KASSERT(RB_BLACK_P(brother)); + KASSERT(!RB_CHILDLESS_P(brother)); + /* + * Case 3: our brother is black, our left nephew is + * red, and our right nephew is black. Swap our + * brother with our left nephew. This result in a + * tree that matches case 4. + * + * B -> D + * A D -> B E + * c e -> A C + */ + if (RB_BLACK_P(brother->rb_nodes[other])) { + KASSERT(RB_RED_P(brother->rb_nodes[which])); + rb_tree_reparent_nodes(rbt, brother, which); + KASSERT(brother->rb_parent == parent->rb_nodes[other]); + brother = parent->rb_nodes[other]; + KASSERT(RB_RED_P(brother->rb_nodes[other])); + } + /* + * Case 4: our brother is black and our right nephew + * is red. Swap our parent and brother locations and + * change our right nephew to black. (these can be + * done in either order so we change the color first). + * The result is a valid red-black tree and is a + * terminal case. + * + * B -> D + * A D -> B E + * c e -> A C + */ + RB_MARK_BLACK(brother->rb_nodes[other]); + rb_tree_reparent_nodes(rbt, parent, other); + break; /* We're done! */ + } + } + KASSERT(rb_tree_check_node(rbt, parent, NULL, true)); +} + +struct rb_node * +_prop_rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self, + unsigned int direction) +{ + const unsigned int other = direction ^ RB_NODE_OTHER; + KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT); + + if (self == NULL) { + self = rbt->rbt_root; + if (RB_SENTINEL_P(self)) + return NULL; + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; + } + KASSERT(!RB_SENTINEL_P(self)); + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(self)) { + if (other == self->rb_position) + return self->rb_parent; + self = self->rb_parent; + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + KASSERT(!RB_SENTINEL_P(self)); + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +} + +#ifdef RBDEBUG +static const struct rb_node * +rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self, + unsigned int direction) +{ + const unsigned int other = direction ^ RB_NODE_OTHER; + KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT); + + if (self == NULL) { + self = rbt->rbt_root; + if (RB_SENTINEL_P(self)) + return NULL; + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; + } + KASSERT(!RB_SENTINEL_P(self)); + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(self)) { + if (other == self->rb_position) + return self->rb_parent; + self = self->rb_parent; + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + KASSERT(!RB_SENTINEL_P(self)); + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +} + +static bool +rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, + const struct rb_node *prev, bool red_check) +{ + KASSERT(!self->rb_sentinel); + KASSERT(self->rb_left); + KASSERT(self->rb_right); + KASSERT(prev == NULL || + (*rbt->rbt_ops->rbto_compare_nodes)(prev, self) > 0); + + /* + * Verify our relationship to our parent. + */ + if (RB_ROOT_P(self)) { + KASSERT(self == rbt->rbt_root); + KASSERT(self->rb_position == RB_NODE_LEFT); + KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self); + KASSERT(self->rb_parent == (const struct rb_node *) &rbt->rbt_root); + } else { + KASSERT(self != rbt->rbt_root); + KASSERT(!RB_PARENT_SENTINEL_P(self)); + if (self->rb_position == RB_NODE_LEFT) { + KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) > 0); + KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self); + } else { + KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) < 0); + KASSERT(self->rb_parent->rb_nodes[RB_NODE_RIGHT] == self); + } + } + + /* + * Verify our position in the linked list against the tree itself. + */ + { + const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT); + const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT); + KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link)); + if (next0 != TAILQ_NEXT(self, rb_link)) + next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT); + KASSERT(next0 == TAILQ_NEXT(self, rb_link)); + } + + /* + * The root must be black. + * There can never be two adjacent red nodes. + */ + if (red_check) { + KASSERT(!RB_ROOT_P(self) || RB_BLACK_P(self)); + if (RB_RED_P(self)) { + const struct rb_node *brother; + KASSERT(!RB_ROOT_P(self)); + brother = self->rb_parent->rb_nodes[self->rb_position ^ RB_NODE_OTHER]; + KASSERT(RB_BLACK_P(self->rb_parent)); + /* + * I'm red and have no children, then I must either + * have no brother or my brother also be red and + * also have no children. (black count == 0) + */ + KASSERT(!RB_CHILDLESS_P(self) + || RB_SENTINEL_P(brother) + || RB_RED_P(brother) + || RB_CHILDLESS_P(brother)); + /* + * If I'm not childless, I must have two children + * and they must be both be black. + */ + KASSERT(RB_CHILDLESS_P(self) + || (RB_TWOCHILDREN_P(self) + && RB_BLACK_P(self->rb_left) + && RB_BLACK_P(self->rb_right))); + /* + * If I'm not childless, thus I have black children, + * then my brother must either be black or have two + * black children. + */ + KASSERT(RB_CHILDLESS_P(self) + || RB_BLACK_P(brother) + || (RB_TWOCHILDREN_P(brother) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right))); + } else { + /* + * If I'm black and have one child, that child must + * be red and childless. + */ + KASSERT(RB_CHILDLESS_P(self) + || RB_TWOCHILDREN_P(self) + || (!RB_LEFT_SENTINEL_P(self) + && RB_RIGHT_SENTINEL_P(self) + && RB_RED_P(self->rb_left) + && RB_CHILDLESS_P(self->rb_left)) + || (!RB_RIGHT_SENTINEL_P(self) + && RB_LEFT_SENTINEL_P(self) + && RB_RED_P(self->rb_right) + && RB_CHILDLESS_P(self->rb_right))); + + /* + * If I'm a childless black node and my parent is + * black, my 2nd closet relative away from my parent + * is either red or has a red parent or red children. + */ + if (!RB_ROOT_P(self) + && RB_CHILDLESS_P(self) + && RB_BLACK_P(self->rb_parent)) { + const unsigned int which = self->rb_position; + const unsigned int other = which ^ RB_NODE_OTHER; + const struct rb_node *relative0, *relative; + + relative0 = rb_tree_iterate_const(rbt, + self, other); + KASSERT(relative0 != NULL); + relative = rb_tree_iterate_const(rbt, + relative0, other); + KASSERT(relative != NULL); + KASSERT(RB_SENTINEL_P(relative->rb_nodes[which])); +#if 0 + KASSERT(RB_RED_P(relative) + || RB_RED_P(relative->rb_left) + || RB_RED_P(relative->rb_right) + || RB_RED_P(relative->rb_parent)); +#endif + } + } + /* + * A grandparent's children must be real nodes and not + * sentinels. First check out grandparent. + */ + KASSERT(RB_ROOT_P(self) + || RB_ROOT_P(self->rb_parent) + || RB_TWOCHILDREN_P(self->rb_parent->rb_parent)); + /* + * If we are have grandchildren on our left, then + * we must have a child on our right. + */ + KASSERT(RB_LEFT_SENTINEL_P(self) + || RB_CHILDLESS_P(self->rb_left) + || !RB_RIGHT_SENTINEL_P(self)); + /* + * If we are have grandchildren on our right, then + * we must have a child on our left. + */ + KASSERT(RB_RIGHT_SENTINEL_P(self) + || RB_CHILDLESS_P(self->rb_right) + || !RB_LEFT_SENTINEL_P(self)); + + /* + * If we have a child on the left and it doesn't have two + * children make sure we don't have great-great-grandchildren on + * the right. + */ + KASSERT(RB_TWOCHILDREN_P(self->rb_left) + || RB_CHILDLESS_P(self->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_right->rb_right)); + + /* + * If we have a child on the right and it doesn't have two + * children make sure we don't have great-great-grandchildren on + * the left. + */ + KASSERT(RB_TWOCHILDREN_P(self->rb_right) + || RB_CHILDLESS_P(self->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_left->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_right->rb_right)); + + /* + * If we are fully interior node, then our predecessors and + * successors must have no children in our direction. + */ + if (RB_TWOCHILDREN_P(self)) { + const struct rb_node *prev0; + const struct rb_node *next0; + + prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT); + KASSERT(prev0 != NULL); + KASSERT(RB_RIGHT_SENTINEL_P(prev0)); + + next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT); + KASSERT(next0 != NULL); + KASSERT(RB_LEFT_SENTINEL_P(next0)); + } + } + + return true; +} + +static unsigned int +rb_tree_count_black(const struct rb_node *self) +{ + unsigned int left, right; + + if (RB_SENTINEL_P(self)) + return 0; + + left = rb_tree_count_black(self->rb_left); + right = rb_tree_count_black(self->rb_right); + + KASSERT(left == right); + + return left + RB_BLACK_P(self); +} + +void +_prop_rb_tree_check(const struct rb_tree *rbt, bool red_check) +{ + const struct rb_node *self; + const struct rb_node *prev; + unsigned int count; + + KASSERT(rbt->rbt_root == NULL || rbt->rbt_root->rb_position == RB_NODE_LEFT); + + prev = NULL; + count = 0; + TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) { + rb_tree_check_node(rbt, self, prev, false); + count++; + } + KASSERT(rbt->rbt_count == count); + KASSERT(RB_SENTINEL_P(rbt->rbt_root) + || rb_tree_count_black(rbt->rbt_root)); + + /* + * The root must be black. + * There can never be two adjacent red nodes. + */ + if (red_check) { + KASSERT(rbt->rbt_root == NULL || RB_BLACK_P(rbt->rbt_root)); + TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) { + rb_tree_check_node(rbt, self, NULL, true); + } + } +} +#endif /* RBDEBUG */ diff --git a/src/prop_rb_impl.h b/src/prop_rb_impl.h new file mode 100644 index 0000000..4dd6801 --- /dev/null +++ b/src/prop_rb_impl.h @@ -0,0 +1,137 @@ +/* $NetBSD: prop_rb_impl.h,v 1.7 2008/06/30 20:14:09 matt Exp $ */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROP_RB_IMPL_H_ +#define _PROP_RB_IMPL_H_ + +#include +#include "queue.h" + +struct rb_node { + struct rb_node *rb_nodes[3]; +#define RB_NODE_LEFT 0 +#define RB_NODE_RIGHT 1 +#define RB_NODE_OTHER 1 +#define RB_NODE_PARENT 2 +#define rb_left rb_nodes[RB_NODE_LEFT] +#define rb_right rb_nodes[RB_NODE_RIGHT] +#define rb_parent rb_nodes[RB_NODE_PARENT] + union { + struct { +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned int : 28; + unsigned int s_root : 1; + unsigned int s_position : 1; + unsigned int s_color : 1; + unsigned int s_sentinel : 1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + unsigned int s_sentinel : 1; + unsigned int s_color : 1; + unsigned int s_position : 1; + unsigned int s_root : 1; + unsigned int : 28; +#endif + } u_s; + unsigned int u_i; + } rb_u; +#define rb_root rb_u.u_s.s_root +#define rb_position rb_u.u_s.s_position +#define rb_color rb_u.u_s.s_color +#define rb_sentinel rb_u.u_s.s_sentinel +#define rb_properties rb_u.u_i +#define RB_SENTINEL_P(rb) ((rb)->rb_sentinel + 0) +#define RB_LEFT_SENTINEL_P(rb) ((rb)->rb_left->rb_sentinel + 0) +#define RB_RIGHT_SENTINEL_P(rb) ((rb)->rb_right->rb_sentinel + 0) +#define RB_PARENT_SENTINEL_P(rb) ((rb)->rb_parent->rb_sentinel + 0) +#define RB_CHILDLESS_P(rb) (RB_LEFT_SENTINEL_P(rb) \ + && RB_RIGHT_SENTINEL_P(rb)) +#define RB_TWOCHILDREN_P(rb) (!RB_LEFT_SENTINEL_P(rb) \ + && !RB_RIGHT_SENTINEL_P(rb)) +#define RB_ROOT_P(rb) ((rb)->rb_root != false) +#define RB_RED_P(rb) ((rb)->rb_color + 0) +#define RB_BLACK_P(rb) (!(rb)->rb_color) +#define RB_MARK_RED(rb) ((void)((rb)->rb_color = 1)) +#define RB_MARK_BLACK(rb) ((void)((rb)->rb_color = 0)) +#define RB_MARK_ROOT(rb) ((void)((rb)->rb_root = 1)) +#ifdef RBDEBUG + TAILQ_ENTRY(rb_node) rb_link; +#endif +}; + +#ifdef RBDEBUG +TAILQ_HEAD(rb_node_qh, rb_node); + +#define RB_TAILQ_REMOVE TAILQ_REMOVE +#define RB_TAILQ_INIT TAILQ_INIT +#define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD +#define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE +#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER +#else +#define RB_TAILQ_REMOVE(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0) +#endif + +typedef int (*rb_compare_nodes_fn)(const struct rb_node *, + const struct rb_node *); +typedef int (*rb_compare_key_fn)(const struct rb_node *, const void *); + +struct rb_tree_ops { + rb_compare_nodes_fn rbto_compare_nodes; + rb_compare_key_fn rbto_compare_key; +}; + +struct rb_tree { + struct rb_node *rbt_root; +#ifdef RBDEBUG + struct rb_node_qh rbt_nodes; +#endif + const struct rb_tree_ops *rbt_ops; +#ifdef RBDEBUG + unsigned int rbt_count; +#endif +}; + +void _prop_rb_tree_init(struct rb_tree *, const struct rb_tree_ops *); +bool _prop_rb_tree_insert_node(struct rb_tree *, struct rb_node *); +struct rb_node * + _prop_rb_tree_find(struct rb_tree *, const void *); +void _prop_rb_tree_remove_node(struct rb_tree *, struct rb_node *); +#ifdef RBDEBUG +void _prop_rb_tree_check(const struct rb_tree *, bool); +#endif +struct rb_node * + _prop_rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int); + +#endif /* _PROP_RB_IMPL_H_*/ diff --git a/src/prop_stack.c b/src/prop_stack.c new file mode 100644 index 0000000..a08118c --- /dev/null +++ b/src/prop_stack.c @@ -0,0 +1,118 @@ +/* $NetBSD: prop_stack.c,v 1.2 2007/08/30 12:23:54 joerg Exp $ */ + +/*- + * Copyright (c) 2007 Joerg Sonnenberger . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "prop_stack.h" +#include "prop_object_impl.h" + +void +_prop_stack_init(prop_stack_t stack) +{ + stack->used_intern_elems = 0; + SLIST_INIT(&stack->extern_elems); +} + +bool +_prop_stack_push(prop_stack_t stack, prop_object_t obj, void *data1, + void *data2, void *data3) +{ + struct _prop_stack_extern_elem *eelem; + struct _prop_stack_intern_elem *ielem; + + if (stack->used_intern_elems == PROP_STACK_INTERN_ELEMS) { + eelem = _PROP_MALLOC(sizeof(*eelem), M_TEMP); + + if (eelem == NULL) + return false; + + eelem->object = obj; + eelem->object_data[0] = data1; + eelem->object_data[1] = data2; + eelem->object_data[2] = data3; + + SLIST_INSERT_HEAD(&stack->extern_elems, eelem, stack_link); + + return true; + } + + _PROP_ASSERT(stack->used_intern_elems < PROP_STACK_INTERN_ELEMS); + _PROP_ASSERT(SLIST_EMPTY(&stack->extern_elems)); + + ielem = &stack->intern_elems[stack->used_intern_elems]; + ielem->object = obj; + ielem->object_data[0] = data1; + ielem->object_data[1] = data2; + ielem->object_data[2] = data3; + + ++stack->used_intern_elems; + + return true; +} + +bool +_prop_stack_pop(prop_stack_t stack, prop_object_t *obj, void **data1, + void **data2, void **data3) +{ + struct _prop_stack_extern_elem *eelem; + struct _prop_stack_intern_elem *ielem; + + if (stack->used_intern_elems == 0) + return false; + + if ((eelem = SLIST_FIRST(&stack->extern_elems)) != NULL) { + _PROP_ASSERT(stack->used_intern_elems == PROP_STACK_INTERN_ELEMS); + + SLIST_REMOVE_HEAD(&stack->extern_elems, stack_link); + if (obj) + *obj = eelem->object; + if (data1) + *data1 = eelem->object_data[0]; + if (data2) + *data2 = eelem->object_data[1]; + if (data3) + *data3 = eelem->object_data[2]; + _PROP_FREE(eelem, M_TEMP); + return true; + } + + --stack->used_intern_elems; + ielem = &stack->intern_elems[stack->used_intern_elems]; + + if (obj) + *obj = ielem->object; + if (data1) + *data1 = ielem->object_data[0]; + if (data2) + *data2 = ielem->object_data[1]; + if (data3) + *data3 = ielem->object_data[2]; + + return true; +} diff --git a/src/prop_stack.h b/src/prop_stack.h new file mode 100644 index 0000000..4cb4509 --- /dev/null +++ b/src/prop_stack.h @@ -0,0 +1,63 @@ +/* $NetBSD: prop_stack.h,v 1.2 2007/08/30 12:23:54 joerg Exp $ */ + +/*- + * Copyright (c) 2007 Joerg Sonnenberger . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PROP_STACK_H +#define _PROP_STACK_H + +#include "queue.h" +#include "prop_object.h" + +struct _prop_stack_intern_elem { + prop_object_t object; + void *object_data[3]; +}; + +struct _prop_stack_extern_elem { + SLIST_ENTRY(_prop_stack_extern_elem) stack_link; + prop_object_t object; + void *object_data[3]; +}; + +#define PROP_STACK_INTERN_ELEMS 16 + +struct _prop_stack { + struct _prop_stack_intern_elem intern_elems[PROP_STACK_INTERN_ELEMS]; + size_t used_intern_elems; + SLIST_HEAD(, _prop_stack_extern_elem) extern_elems; +}; + +typedef struct _prop_stack *prop_stack_t; + +void _prop_stack_init(prop_stack_t); +bool _prop_stack_push(prop_stack_t, prop_object_t, void *, void *, void *); +bool _prop_stack_pop(prop_stack_t, prop_object_t *, void **, void **, void **); + +#endif diff --git a/src/prop_string.3 b/src/prop_string.3 new file mode 100644 index 0000000..5b8542a --- /dev/null +++ b/src/prop_string.3 @@ -0,0 +1,188 @@ +.\" $NetBSD: prop_string.3,v 1.6 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 21, 2008 +.Dt PROP_STRING 3 +.Os +.Sh NAME +.Nm prop_string , +.Nm prop_string_create , +.Nm prop_string_create_cstring , +.Nm prop_string_create_cstring_nocopy , +.Nm prop_string_copy , +.Nm prop_string_copy_mutable , +.Nm prop_string_size , +.Nm prop_string_mutable , +.Nm prop_string_cstring , +.Nm prop_string_cstring_nocopy , +.Nm prop_string_append , +.Nm prop_string_append_cstring , +.Nm prop_string_equals , +.Nm prop_string_equals_cstring +.Nd string value property object +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.\" +.Ft prop_string_t +.Fn prop_string_create "void" +.Ft prop_string_t +.Fn prop_string_create_cstring "const char *cstring" +.Ft prop_string_t +.Fn prop_string_create_cstring_nocopy "const char *cstring" +.\" +.Ft prop_string_t +.Fn prop_string_copy "prop_string_t string" +.Ft prop_string_t +.Fn prop_string_copy_mutable "prop_string_t string" +.\" +.Ft char * +.Fn prop_string_cstring "prop_string_t string" +.Ft const char * +.Fn prop_string_cstring_nocopy "prop_string_t string" +.\" +.Ft bool +.Fn prop_string_append "prop_string_t str1" "prop_string_t str2" +.Ft bool +.Fn prop_string_append_cstring "prop_string_t string" "const char *cstring" +.\" +.Ft bool +.Fn prop_string_equals "prop_string_t str1" "prop_string_t str2" +.Ft bool +.Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring" +.Sh DESCRIPTION +The +.Nm prop_string +family of functions operate on a string value property object type. +.Bl -tag -width "xxxxx" +.It Fn prop_string_create "void" +Create an empty mutable string. +Returns +.Dv NULL +on failure. +.It Fn prop_string_create_cstring "const char *cstring" +Create a mutable string that contains a copy of +.Fa cstring . +Returns +.Dv NULL +on failure. +.It Fn prop_string_create_cstring_nocopy "const char *cstring" +Create an immutable string that contains a reference to +.Fa cstring . +Returns +.Dv NULL +on failure. +.It Fn prop_string_copy "prop_string_t string" +Copy a string. +If the the string being copied is an immutable external C string reference, +then the copy is also immutable and references the same external C string. +Returns +.Dv NULL +on failure. +.It Fn prop_string_copy_mutable "prop_string_t string" +Copy a string, always creating a mutable copy. +Returns +.Dv NULL +on failure. +.It Fn prop_string_size "prop_string_t string" +Returns the size of the string, not including the terminating NUL. +If the supplied object isn't a string, zero is returned. +.It Fn prop_string_mutable "prop_string_t string" +Returns +.Dv true +if the string is mutable. +If the supplied object isn't a string, +.Dv false +is returned. +.It Fn prop_string_cstring "prop_string_t string" +Returns a copy of the string's contents as a C string. +The caller is responsible for freeing the returned buffer. +.Pp +In user space, the buffer is allocated using +.Xr malloc 3 . +In the kernel, the buffer is allocated using +.Xr malloc 9 +using the malloc type +.Dv M_TEMP . +.Pp +Returns +.Dv NULL +on failure. +.It Fn prop_string_cstring_nocopy "prop_string_t string" +Returns an immutable reference to the contents of the string as a +C string. +If the supplied object isn't a string, +.Dv NULL +is returned. +.It Fn prop_string_append "prop_string_t str1" "prop_string_t str2" +Append the contents of +.Fa str2 +to +.Fa str1 , +which must be mutable. +Returns +.Dv true +upon success and +.Dv false +otherwise. +.It Fn prop_string_append_cstring "prop_string_t string" "const char *cstring" +Append the C string +.Fa cstring +to +.Fa string , +which must be mutable. +Returns +.Dv true +upon success and +.Dv false +otherwise. +.It Fn prop_string_equals "prop_string_t str1" "prop_string_t str2" +Returns +.Dv true +if the two string objects are equivalent. +.It Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring" +Returns +.Dv true +if the string's value is equivalent to +.Fa cstring . +.El +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr proplib 3 +.Sh HISTORY +The +.Nm proplib +property container object library first appeared in +.Nx 4.0 . diff --git a/src/prop_string.c b/src/prop_string.c new file mode 100644 index 0000000..6761f93 --- /dev/null +++ b/src/prop_string.c @@ -0,0 +1,471 @@ +/* $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 thorpej Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prop_string.h" +#include "prop_object_impl.h" + +struct _prop_string { + struct _prop_object ps_obj; + union { + char * psu_mutable; + const char * psu_immutable; + } ps_un; +#define ps_mutable ps_un.psu_mutable +#define ps_immutable ps_un.psu_immutable + size_t ps_size; /* not including \0 */ + int ps_flags; +}; + +#define PS_F_NOCOPY 0x01 + +_PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng") + +_PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string", + "property string container object") + +static _prop_object_free_rv_t + _prop_string_free(prop_stack_t, prop_object_t *); +static bool _prop_string_externalize( + struct _prop_object_externalize_context *, + void *); +static _prop_object_equals_rv_t + _prop_string_equals(prop_object_t, prop_object_t, + void **, void **, + prop_object_t *, prop_object_t *); + +static const struct _prop_object_type _prop_object_type_string = { + .pot_type = PROP_TYPE_STRING, + .pot_free = _prop_string_free, + .pot_extern = _prop_string_externalize, + .pot_equals = _prop_string_equals, +}; + +#define prop_object_is_string(x) \ + ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string) +#define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "") + +/* ARGSUSED */ +static _prop_object_free_rv_t +_prop_string_free(prop_stack_t stack, prop_object_t *obj) +{ + prop_string_t ps = *obj; + + if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL) + _PROP_FREE(ps->ps_mutable, M_PROP_STRING); + _PROP_POOL_PUT(_prop_string_pool, ps); + + return (_PROP_OBJECT_FREE_DONE); +} + +static bool +_prop_string_externalize(struct _prop_object_externalize_context *ctx, + void *v) +{ + prop_string_t ps = v; + + if (ps->ps_size == 0) + return (_prop_object_externalize_empty_tag(ctx, "string")); + + if (_prop_object_externalize_start_tag(ctx, "string") == false || + _prop_object_externalize_append_encoded_cstring(ctx, + ps->ps_immutable) == false || + _prop_object_externalize_end_tag(ctx, "string") == false) + return (false); + + return (true); +} + +/* ARGSUSED */ +static _prop_object_equals_rv_t +_prop_string_equals(prop_object_t v1, prop_object_t v2, + void **stored_pointer1, void **stored_pointer2, + prop_object_t *next_obj1, prop_object_t *next_obj2) +{ + prop_string_t str1 = v1; + prop_string_t str2 = v2; + + if (str1 == str2) + return (_PROP_OBJECT_EQUALS_TRUE); + if (str1->ps_size != str2->ps_size) + return (_PROP_OBJECT_EQUALS_FALSE); + if (strcmp(prop_string_contents(str1), prop_string_contents(str2))) + return (_PROP_OBJECT_EQUALS_FALSE); + else + return (_PROP_OBJECT_EQUALS_TRUE); +} + +static prop_string_t +_prop_string_alloc(void) +{ + prop_string_t ps; + + ps = _PROP_POOL_GET(_prop_string_pool); + if (ps != NULL) { + _prop_object_init(&ps->ps_obj, &_prop_object_type_string); + + ps->ps_mutable = NULL; + ps->ps_size = 0; + ps->ps_flags = 0; + } + + return (ps); +} + +/* + * prop_string_create -- + * Create an empty mutable string. + */ +prop_string_t +prop_string_create(void) +{ + + return (_prop_string_alloc()); +} + +/* + * prop_string_create_cstring -- + * Create a string that contains a copy of the provided C string. + */ +prop_string_t +prop_string_create_cstring(const char *str) +{ + prop_string_t ps; + char *cp; + size_t len; + + ps = _prop_string_alloc(); + if (ps != NULL) { + len = strlen(str); + cp = _PROP_MALLOC(len + 1, M_PROP_STRING); + if (cp == NULL) { + prop_object_release(ps); + return (NULL); + } + strcpy(cp, str); + ps->ps_mutable = cp; + ps->ps_size = len; + } + return (ps); +} + +/* + * prop_string_create_cstring_nocopy -- + * Create an immutable string that contains a refrence to the + * provided C string. + */ +prop_string_t +prop_string_create_cstring_nocopy(const char *str) +{ + prop_string_t ps; + + ps = _prop_string_alloc(); + if (ps != NULL) { + ps->ps_immutable = str; + ps->ps_size = strlen(str); + ps->ps_flags |= PS_F_NOCOPY; + } + return (ps); +} + +/* + * prop_string_copy -- + * Copy a string. If the original string is immutable, then the + * copy is also immutable and references the same external data. + */ +prop_string_t +prop_string_copy(prop_string_t ops) +{ + prop_string_t ps; + + if (! prop_object_is_string(ops)) + return (NULL); + + ps = _prop_string_alloc(); + if (ps != NULL) { + ps->ps_size = ops->ps_size; + ps->ps_flags = ops->ps_flags; + if (ops->ps_flags & PS_F_NOCOPY) + ps->ps_immutable = ops->ps_immutable; + else { + char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); + if (cp == NULL) { + prop_object_release(ps); + return (NULL); + } + strcpy(cp, prop_string_contents(ops)); + ps->ps_mutable = cp; + } + } + return (ps); +} + +/* + * prop_string_copy_mutable -- + * Copy a string, always returning a mutable copy. + */ +prop_string_t +prop_string_copy_mutable(prop_string_t ops) +{ + prop_string_t ps; + char *cp; + + if (! prop_object_is_string(ops)) + return (NULL); + + ps = _prop_string_alloc(); + if (ps != NULL) { + ps->ps_size = ops->ps_size; + cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); + if (cp == NULL) { + prop_object_release(ps); + return (NULL); + } + strcpy(cp, prop_string_contents(ops)); + ps->ps_mutable = cp; + } + return (ps); +} + +/* + * prop_string_size -- + * Return the size of the string, not including the terminating NUL. + */ +size_t +prop_string_size(prop_string_t ps) +{ + + if (! prop_object_is_string(ps)) + return (0); + + return (ps->ps_size); +} + +/* + * prop_string_mutable -- + * Return true if the string is a mutable string. + */ +bool +prop_string_mutable(prop_string_t ps) +{ + + if (! prop_object_is_string(ps)) + return (false); + + return ((ps->ps_flags & PS_F_NOCOPY) == 0); +} + +/* + * prop_string_cstring -- + * Return a copy of the contents of the string as a C string. + * The string is allocated with the M_TEMP malloc type. + */ +char * +prop_string_cstring(prop_string_t ps) +{ + char *cp; + + if (! prop_object_is_string(ps)) + return (NULL); + + cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP); + if (cp != NULL) + strcpy(cp, prop_string_contents(ps)); + + return (cp); +} + +/* + * prop_string_cstring_nocopy -- + * Return an immutable reference to the contents of the string + * as a C string. + */ +const char * +prop_string_cstring_nocopy(prop_string_t ps) +{ + + if (! prop_object_is_string(ps)) + return (NULL); + + return (prop_string_contents(ps)); +} + +/* + * prop_string_append -- + * Append the contents of one string to another. Returns true + * upon success. The destination string must be mutable. + */ +bool +prop_string_append(prop_string_t dst, prop_string_t src) +{ + char *ocp, *cp; + size_t len; + + if (! (prop_object_is_string(dst) && + prop_object_is_string(src))) + return (false); + + if (dst->ps_flags & PS_F_NOCOPY) + return (false); + + len = dst->ps_size + src->ps_size; + cp = _PROP_MALLOC(len + 1, M_PROP_STRING); + if (cp == NULL) + return (false); + sprintf(cp, "%s%s", prop_string_contents(dst), + prop_string_contents(src)); + ocp = dst->ps_mutable; + dst->ps_mutable = cp; + dst->ps_size = len; + if (ocp != NULL) + _PROP_FREE(ocp, M_PROP_STRING); + + return (true); +} + +/* + * prop_string_append_cstring -- + * Append a C string to a string. Returns true upon success. + * The destination string must be mutable. + */ +bool +prop_string_append_cstring(prop_string_t dst, const char *src) +{ + char *ocp, *cp; + size_t len; + + if (! prop_object_is_string(dst)) + return (false); + + _PROP_ASSERT(src != NULL); + + if (dst->ps_flags & PS_F_NOCOPY) + return (false); + + len = dst->ps_size + strlen(src); + cp = _PROP_MALLOC(len + 1, M_PROP_STRING); + if (cp == NULL) + return (false); + sprintf(cp, "%s%s", prop_string_contents(dst), src); + ocp = dst->ps_mutable; + dst->ps_mutable = cp; + dst->ps_size = len; + if (ocp != NULL) + _PROP_FREE(ocp, M_PROP_STRING); + + return (true); +} + +/* + * prop_string_equals -- + * Return true if two strings are equivalent. + */ +bool +prop_string_equals(prop_string_t str1, prop_string_t str2) +{ + if (!prop_object_is_string(str1) || !prop_object_is_string(str2)) + return (false); + + return prop_object_equals(str1, str2); +} + +/* + * prop_string_equals_cstring -- + * Return true if the string is equivalent to the specified + * C string. + */ +bool +prop_string_equals_cstring(prop_string_t ps, const char *cp) +{ + + if (! prop_object_is_string(ps)) + return (false); + + return (strcmp(prop_string_contents(ps), cp) == 0); +} + +/* + * _prop_string_internalize -- + * Parse a ... and return the object created from the + * external representation. + */ +/* ARGSUSED */ +bool +_prop_string_internalize(prop_stack_t stack, prop_object_t *obj, + struct _prop_object_internalize_context *ctx) +{ + prop_string_t string; + char *str; + size_t len, alen; + + if (ctx->poic_is_empty_element) { + *obj = prop_string_create(); + return (true); + } + + /* No attributes recognized here. */ + if (ctx->poic_tagattr != NULL) + return (true); + + /* Compute the length of the result. */ + if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len, + NULL) == false) + return (true); + + str = _PROP_MALLOC(len + 1, M_PROP_STRING); + if (str == NULL) + return (true); + + if (_prop_object_internalize_decode_string(ctx, str, len, &alen, + &ctx->poic_cp) == false || + alen != len) { + _PROP_FREE(str, M_PROP_STRING); + return (true); + } + str[len] = '\0'; + + if (_prop_object_internalize_find_tag(ctx, "string", + _PROP_TAG_TYPE_END) == false) { + _PROP_FREE(str, M_PROP_STRING); + return (true); + } + + string = _prop_string_alloc(); + if (string == NULL) { + _PROP_FREE(str, M_PROP_STRING); + return (true); + } + + string->ps_mutable = str; + string->ps_size = len; + *obj = string; + + return (true); +} diff --git a/src/prop_string.h b/src/prop_string.h new file mode 100644 index 0000000..60c1e2a --- /dev/null +++ b/src/prop_string.h @@ -0,0 +1,60 @@ +/* $NetBSD: prop_string.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROP_STRING_H_ +#define _PROPLIB_PROP_STRING_H_ + +#include "prop_object.h" + +typedef struct _prop_string *prop_string_t; + +__BEGIN_DECLS +prop_string_t prop_string_create(void); +prop_string_t prop_string_create_cstring(const char *); +prop_string_t prop_string_create_cstring_nocopy(const char *); + +prop_string_t prop_string_copy(prop_string_t); +prop_string_t prop_string_copy_mutable(prop_string_t); + +size_t prop_string_size(prop_string_t); +bool prop_string_mutable(prop_string_t); + +char * prop_string_cstring(prop_string_t); +const char * prop_string_cstring_nocopy(prop_string_t); + +bool prop_string_append(prop_string_t, prop_string_t); +bool prop_string_append_cstring(prop_string_t, const char *); + +bool prop_string_equals(prop_string_t, prop_string_t); +bool prop_string_equals_cstring(prop_string_t, const char *); +__END_DECLS + +#endif /* _PROPLIB_PROP_STRING_H_ */ diff --git a/src/proplib.3 b/src/proplib.3 new file mode 100644 index 0000000..b0f01fd --- /dev/null +++ b/src/proplib.3 @@ -0,0 +1,137 @@ +.\" $NetBSD: proplib.3,v 1.5 2008/04/30 13:10:46 martin Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 21, 2007 +.Dt PROPLIB 3 +.Os +.Sh NAME +.Nm proplib +.Nd property container object library +.Sh LIBRARY +.Lb libprop +.Sh SYNOPSIS +.In prop/proplib.h +.Sh DESCRIPTION +The +.Nm +library provides an abstract interface for creating and manipulating +property lists. +Property lists have object types for boolean values, opaque data, numbers, +and strings. +Structure is provided by the array and dictionary collection types. +.Pp +Property lists can be passed across protection boundaries by translating +them to an external representation. +This external representation is an XML document whose format is described +by the following DTD: +.Bd -literal -offset indent +http://www.apple.com/DTDs/PropertyList-1.0.dtd +.Ed +.Pp +Property container objects are reference counted. +When an object is created, its reference count is set to 1. +Any code that keeps a reference to an object, including the collection +types +.Pq arrays and dictionaries , +must +.Dq retain +the object +.Pq increment its reference count . +When that reference is dropped, the object must be +.Dq released +.Pq reference count decremented . +When an object's reference count drops to 0, it is automatically freed. +.Pp +The rules for managing reference counts are very simple: +.Bl -bullet +.It +If you create an object and do not explicitly maintain a reference to it, +you must release it. +.It +If you get a reference to an object from other code and wish to maintain +a reference to it, you must retain the object. You are responsible for +releasing the object once you drop that reference. +.It +You must never release an object unless you create it or retain it. +.El +.Pp +Object collections may be iterated by creating a special iterator object. +Iterator objects are special; they may not be retained, and they are +released using an iterator-specific release function. +.Sh SEE ALSO +.Xr prop_array 3 , +.Xr prop_bool 3 , +.Xr prop_data 3 , +.Xr prop_dictionary 3 , +.Xr prop_dictionary_util 3 , +.Xr prop_number 3 , +.Xr prop_object 3 , +.Xr prop_send_ioctl 3 , +.Xr prop_string 3 +.Sh HISTORY +The +.Nm +property container object library first appeared in +.Nx 4.0 . +.Sh CAVEATS +.Nm +does not have a +.Sq date +object type, and thus will not parse +.Sq date +elements from an Apple XML property list. +.Pp +The +.Nm +.Sq number +object type differs from the Apple XML property list format in the following +ways: +.Bl -bullet +.It +The external representation is in base 16, not base 10. +.Nm +is able to parse base 8, base 10, and base 16 +.Sq integer +elements. +.It +Internally, integers are always stored as unsigned numbers +.Pq uint64_t . +Therefore, the external representation will never be negative. +.It +Because floating point numbers are not supported, +.Sq real +elements from an Apple XML property list will not be parsed. +.El +.Pp +In order to facilitate use of +.Nm +in kernel, standalone, and user space environments, the +.Nm +parser is not a real XML parser. +It is hard-coded to parse only the property list external representation. diff --git a/src/proplib.h b/src/proplib.h new file mode 100644 index 0000000..a840d12 --- /dev/null +++ b/src/proplib.h @@ -0,0 +1,43 @@ +/* $NetBSD: proplib.h,v 1.6 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PROPLIB_PROPLIB_H_ +#define _PROPLIB_PROPLIB_H_ + +#include "prop_array.h" +#include "prop_bool.h" +#include "prop_data.h" +#include "prop_dictionary.h" +#include "prop_number.h" +#include "prop_string.h" +#include "prop_ingest.h" + +#endif /* _PROPLIB_PROPLIB_H_ */ diff --git a/src/queue.h b/src/queue.h new file mode 100644 index 0000000..c1aff29 --- /dev/null +++ b/src/queue.h @@ -0,0 +1,697 @@ +/* $NetBSD: queue.h,v 1.49 2008/06/15 16:42:18 christos Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.le_prev != (elm)) \ + panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_AFTER(slistelm, field) do { \ + (slistelm)->field.sle_next = \ + SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ +} while (/*CONSTCOND*/0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->tqh_first); \ + (var) != NULL && ((next) = TAILQ_NEXT(var, field), 1); \ + (var) = (next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ + if ((head)->cqh_first != (void *)(head) && \ + (head)->cqh_first->field.cqe_prev != (void *)(head)) \ + panic("CIRCLEQ head forw %p %s:%d", (head), \ + __FILE__, __LINE__); \ + if ((head)->cqh_last != (void *)(head) && \ + (head)->cqh_last->field.cqe_next != (void *)(head)) \ + panic("CIRCLEQ head back %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ + if ((elm)->field.cqe_next == (void *)(head)) { \ + if ((head)->cqh_last != (elm)) \ + panic("CIRCLEQ elm last %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ + panic("CIRCLEQ elm forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } \ + if ((elm)->field.cqe_prev == (void *)(head)) { \ + if ((head)->cqh_first != (elm)) \ + panic("CIRCLEQ elm first %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ + panic("CIRCLEQ elm prev %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + } +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ + (elm)->field.cqe_next = (void *)1L; \ + (elm)->field.cqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) +#endif + +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* !_SYS_QUEUE_H_ */ -- 2.11.4.GIT