pax_global_header00006660000000000000000000000064146052610670014521gustar00rootroot0000000000000052 comment=7c3e0515c29efce45de6aae29befb2ab4396bd60 dotconf-1.4.1/000077500000000000000000000000001460526106700131605ustar00rootroot00000000000000dotconf-1.4.1/.gitignore000066400000000000000000000002601460526106700151460ustar00rootroot00000000000000*.la *.lo *.o *.swp .deps .libs Makefile Makefile.in aclocal.m4 autom4te.cache configure config.* depcomp dotconf.pc dotconf.spec install-sh libtool ltmain.sh missing stamp-h1 dotconf-1.4.1/AUTHORS000066400000000000000000000002571460526106700142340ustar00rootroot00000000000000lukas schröder - original author William Hubbs - current maintainer and others (see http://git.opentts.org/?p=dotconf.git;a=summary) dotconf-1.4.1/COPYING000066400000000000000000000634721460526106700142270ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! dotconf-1.4.1/INSTALL000066400000000000000000000172271460526106700142220ustar00rootroot00000000000000Basic 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, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). 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 at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' 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. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure 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 supports 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' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM 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 host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. 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. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--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. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. dotconf-1.4.1/Makefile.am000066400000000000000000000001331460526106700152110ustar00rootroot00000000000000SUBDIRS = doc examples src pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dotconf.pc dotconf-1.4.1/README000066400000000000000000000015501460526106700140410ustar00rootroot00000000000000dot.conf v1.4.1 This file lists changes that break backward compatibility with previous versions. Please see the files in the doc directory of the distribution for full details. For examples of how to use this library, see the examples directory. Changes after 1.0.13: - dotconf_register_options now has a return type. This function can now indicate success or failure. - To support the float argument for a config option, the data member of struct command_t gained the dvalue member. This is free software licensed with the GNU Lesser General Public License 2.1. I would like to thank Lukas Schroeder for authoring this project originally. His address is listed in the Authors file if you need to contact him. However, current questions about the project should be directed to me since I am the current maintainer. William Hubbs dotconf-1.4.1/configure.ac000066400000000000000000000033561460526106700154550ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([dotconf], [1.4.1], [w.d.hubbs@gmail.com]) AM_INIT_AUTOMAKE([foreign]) LT_PREREQ([2.2]) LT_INIT([dlopen]) AC_CONFIG_SRCDIR([src/dotconf.c]) AC_CONFIG_HEADERS([config.h]) # libtool version numbers for dotconf library: # # This is taken from the libtool manual. # It is an algorithm, so follow all of the steps. # # 2. Only change this as the last step before a release. # 3. If the library source has changed since the last release, # increment revision. # 4. If any interfaces have been added, removed or changed since the # last release, increment current and set revision to 0. # 5. If any interfaces have been added since the last release, increment age. # 6. If any interfaces have been removed since the last release, set age to 0. # DC_CURRENT=0 DC_REVISION=1 DC_AGE=0 AC_SUBST([DC_CURRENT]) AC_SUBST([DC_REVISION]) AC_SUBST([DC_AGE]) # Checks for programs. AC_PROG_CC AC_PROG_MAKE_SET # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([fcntl.h malloc.h stdlib.h string.h strings.h syslog.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_OFF_T AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC AC_FUNC_STRTOD AC_CHECK_FUNCS([memset strcspn strdup strstr]) # Conditionally set extra compiler flags. if test "$GCC" = yes; then WARNING_CFLAGS="-Wall" else WARNING_CFLAGS="-errwarn=%all -errtags=yes -erroff=E_STATEMENT_NOT_REACHED" fi AC_SUBST(WARNING_CFLAGS) AC_CONFIG_FILES([Makefile dotconf.pc doc/Makefile examples/Makefile src/Makefile]) AC_OUTPUT dotconf-1.4.1/doc/000077500000000000000000000000001460526106700137255ustar00rootroot00000000000000dotconf-1.4.1/doc/Makefile.am000066400000000000000000000000671460526106700157640ustar00rootroot00000000000000 dist_doc_DATA = dotconf-features.txt dotconf-api.txt dotconf-1.4.1/doc/dotconf-api.txt000066400000000000000000000361011460526106700166720ustar00rootroot00000000000000 dot.conf API description ===================================================================== 1. dot.conf types --------------------------------------------------------------------- 1.0. typedefs 1.1. constants 1.2. macros 1.3. structures 1.3.1. configfile_t 1.3.2. configoption_t 1.3.3. command_t The API is built around the main data structures configfile_t configoption_t and command_t Two other types are context_t and info_t, but these are only typedefs from void! configfile_t is the dotconf 'session' structure building the glue between the various API parts. It stores things like the stream, current filename or the line currently read. When using dot.conf the first thing for the programmer to do is to receive a valid configfile_t structure with the ->dotconf_create API call. 1.0. dot.conf's typedefs ============================== typedef void context_t; typedef void info_t; typedef const char *(*dotconf_callback_t)(command_t *, context_t *); ^^^^^^^^^^^^^^^^^^ the type of function called for each encountered command typedef int (*dotconf_errorhandler_t)(configfile_t *, int, ^^^^^^^^^^^^^^^^^^^^^^ unsigned long, const char *); the type of the errorhandler callback typedef const char *(*dotconf_contextchecker_t)(command_t *, unsigned long); ^^^^^^^^^^^^^^^^^^^^^^^^ the type of the contextchecker 1.1. dot.conf's constants ============================== CFG_BUFSIZE 4096 max length of one line CFG_MAX_OPTION 32 max length of an option name CFG_MAX_VALUE 4064 max length of an options value CFG_MAX_FILENAME 256 max length of a filename (used when Include'ing) CFG_VALUES 16 max # of parameters an option can take. if an options gets more than CFG_VALUES parameters, the last one holds the complete remaining unparsed string is passed in list[CFG_VALUES-1]. CFG_INCLUDEPATH_ENV "DC_INCLUDEPATH" the name of the environment variable used to find the search path for Include'ed files. 1.2. dot.conf's macros ============================== DOTCONF_CB(__name) conveniently declare / define a callback function. FUNC_ERRORHANDLER(__name) conveniently declare / define the errorhandler callback 1.3.1. configfile_t ============================== FILE *stream the stream opened by dotconf_create. this field should only be used by dotconf_get_next_line for reading char eof eof is set to one as soon as the END OF FILE has been reached. size_t size this field is only used if there was a here-document to be handled. for here-documents dotconf allocates as much memory as the filesize. The result of the necessary stat() call is cached in this field. Do never rely on the value of this field!! context_t *context the application's pointer to the context memory block. this field is set by dotconf_create, and used to fill in the corresponding field of the command_t when calling a command's callback configoption_t const **config_options a list of configuration options dotconf's dotconf_handle_command can understand. Never write to this field yourself, use dotconf_register_command to handle this for you. int config_option_count the number of modules that registered their options including dotconf's internal options and the core options of the app as given to dotconf_create. char *filename the name of the configuration file unsigned long line the line pointer in the file currently parsed unsigned long flags the run-time flags as passed to dotconf_create. this value can be changed at run-time to have dot.conf act different at different stages of the configuration file (i.e. switch case (in)sensitive matching) char *includepath the include-path for dot.conf's internal 'Include' option. This field is set by dotconf_create to one of these possibilities in order: - If the variable named by CFG_INCLUDEPATH_ENV is set in the environment, includepath is set to the value of that variable. - If the name of the configuration file passed to dotconf_create contains a fully qualified path, includepath is set to that path without the file name. - If the name of the configuration file passed to dotconf_create contains a relative path, includepath is set to the fullly qualified path where the configuration file is stored without the configuration file name. - Otherwise, includepath is not set. dotconf_errorhandler_t errorhandler the errorhandler of the app; after creating your configfile_t set this field to your errorhandler function or leave it as NULL dotconf_contextchecker_t contextchecker the contextchecker is responsible for telling dot.conf whether a command is valid in the current context. this callback is useful if you create several container commands that behave different according to their nesting (see Apache's Files, Directory and VirtualHost). int (*cmp_func)(const char *, const char *, size_t) the function used to compare the first word of a buffer line with all commands registered in config_options. this will be set by the core to be strncmp or strncasecmp depending on the matching type you chose via the flags. again, changing this at any point during the parsing will have an immediate effect. 1.3.2. configoption_t ============================== const char *name the name of the configuration option dot.conf should understand int type the type of the data your app expects. possible values are: ARG_NONE - your app does not expect any args; dot.conf will not parse any args even if some were given. ARG_RAW - unparsed string with whatever was on the line line continuation has been handled, environment variable substitution not. ARG_STR - the first argument (i.e. anything up to the first unquoted, unescaped whitespace character ARG_INT - like ARG_STR, but atoi() is called on the value found ARG_TOGGLE - your app gets 0 for off, and 1 for on; recognized values are On/Off, 1/0, Yes/No ARG_LIST - the application expects several ARG_STRs in a char **list. ARG_NAME - fallback to catch unknown commands. This is for instance especially useful to parse files like Apache's mime.types. If an ARG_NAME is given as the last item of the command table, dot.conf handles the commands as known, and does everything it would have done for an ARG_LIST option. Note: Modules cannot install an ARG_NAME handler. That is the sole right of the core application code. dotconf_callback_t callback the function to be called if the given command name is encountered info_t *info additional info for the callback to operate with unsigned long context the context flag; this will be passed to the apps configchecker 1.3.3. command_t ============================== const char *name the name of the configuration option as in the app's command table. for ARG_NAME type options this is the name of the unmatched/unknown command. configoption_t *option a pointer to the full entry of the command table that corresponds to the current option struct { long value; char *str; char **list; double dvalue; } data the data found when parsing. data.value - this is used for ARG_INT and ARG_TOGGLE options data.str - is only used for ARG_STR type options data.list - list is filled for ARG_LIST and ARG_NAME options data.list is terminated by a NULL entry data.dvalue - this is used for ARG_DOUBLE options int arg_count only set for ARG_LIST items; this is set to the number of items in data.list. the last item of the list is data.list[arg_count-1]. configfile_t *configfile the dot.conf session currently active context_t *context the context pointer you passed to dotconf_create when generating your configfile_t *. 2. Function Reference --------------------------------------------------------------------- 2.1. dotconf_create 2.2. dotconf_cleanup 2.3. dotconf_register_options 2.4. dotconf_command_loop 2.5. dotconf_command_loop_until_error 2.6. dotconf_get_next_line 2.7. dotconf_handle_command 2.8. dotconf_warning 2.1. dotconf_create ============================== configfile_t *dotconf_create(char *filename, const configoption_t *options, context_t *context, unsigned long flags); description: dotconf_create returns a pointer to a configfile_t structure after initializing it. The values you pass are stored in it for future reference. parameters: char *filename the filename of the configuration file you want to parse in this session. The filename is only read by dot.conf. const configoption_t *options this parameter lets dot.conf know about the commands you want it to understand. The configoption_t's tell dot.conf which of your callbacks is responsible for a specific command. context_t *context in context you can pass a pointer to the structure holding anything necessary to keep a context when parsing. This pointer is passed to your command callbacks as a field in command_t, so you can access it at any time. unsigned long flags this parameters sets the runtime flags to consider when parsing. This controls important core functionality. Possible flags are : NONE : no flags (0) CASE_INSENSITIVE : match option names case insensitive DONT_SUBSTITUTE : do not call substitute_env after read_arg NO_INLINE_COMMENTS : do not stop parsing arguments after a #-sign on a line DUPLICATE_OPTION_NAMES : allow for duplicate option names in different contexts The first one without an error from the contextchecker is used. return value: configfile_t * the dot.conf session structure, which is to be used in every call to another dot.conf API function. NULL is returned in case of a failure sideeffects: the returned configfile_t* is malloc()ed, and the field 'stream' is fopen()ed. Do not clean this by hand, but use dotconf_cleanup instead. 2.2. dotconf_cleanup ============================== void dotconf_cleanup(configfile_t *configfile); description: dotconf_cleanup cleans up behind whatever dotconf_create and friends did to and with the configfile_t* that is given as the argument. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create. return value: void 2.3. dotconf_register_options ============================== int dotconf_register_options(configfile_t *configfile, const configoption_t *options); description: this function registers additional known configuration commands at runtime. the next time dot.conf needs to match an option, these newly registered options are taken into account. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create const configoption_t *options this parameter lets dot.conf know about the commands you want it to understand. The configoption_t's tell dot.conf which of your callbacks is responsible for a specific command. return value: int dotconf_register_options returns non-zero on success and zero on failure. The only possible failure condition is the failure to allocate memory. If the function fails, configfile is untouched. 2.4. dotconf_command_loop ============================== int dotconf_command_loop(configfile_t *configfile); description: this function iterates through all lines of the configuration file passing the buffer filled by dotconf_get_next_line to dotconf_handle_command. On error dotconf_command_loop calls dotconf_warning. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create return value: int dotconf_command_loop returns zero on failure and non-zero for success. success means, that the parsing is done now. 2.5. dotconf_command_loop_until_error ============================== const char *dotconf_command_loop_until_error(configfile_t *configfile); description: this function iterates through all lines of the configuration file passing the buffer filled by dotconf_get_next_line to dotconf_handle_command. On error this function exits returning the error. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create return value: const char * dotconf_command_loop_until error returns the first error it stumbles over or NULL if everything went fine 2.6. dotconf_get_next_line ============================== int dotconf_get_next_line(char *buffer, size_t bufsize, configfile_t *configfile); description: this function reads the next line from the configfile, increments line counter, and handles the line continuation. parameters: char *buffer the buffer where the line should be written to size_t bufsize the size of the buffer configfile_t *configfile the dot.conf session structure as returned by dotconf_create return value: int zero indicates success, and non-zero means that some error occurred 2.7. dotconf_handle_command ============================== const char *dotconf_handle_command(configfile_t *configfile, char *buffer); description: handles commands. This function further parses the line buffer and tries to match up the first word found as the command. If the command exists it parses all commands arguments and stuffs them into a command_t structure. Where appropriate here-documents or quotings are handled, and the environment variable substitution is tried on every ARG_STR / ARG_LIST command argument except here-documents. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create char *buffer the buffer as filled by dotconf_get_next_line return value: const char * the error message as returned by the command callbacks for instance; NULL if everything went ok. 2.8. dotconf_warning ============================== int dotconf_warning(configfile_t *configfile, int type, unsigned long errnum, const char *fmt, ...); description: dotconf_warning is responsible for dispatching any messages either through the internal handler (i.e. fprintf) or through the app's errorhandler. parameters: configfile_t *configfile the dot.conf session structure as returned by dotconf_create int type type of the message; analogous to syslog-style types: DCLOG_EMERG, DCLOG_ALERT, DCLOG_CRIT, DCLOG_ERR, DCLOG_WARNING, DCLOG_NOTICE, DCLOG_INFO, DCLOG_DEBUG unsigned long errnum the error number. this is up to the app what values to put here. I suggest using numbers above ERR_USER for own error numbers to not be conflicting with dotconf's internal error numbers. const char *fmt, ... a printf style message format. the message will be prepared via vsnprintf before passing it to your errorhandler. return value: int the value returned here affects how dotconf_command_loop reacts to errors. a value of zero, which is returned by the internal handler, will make the command loop to read on. non-zero tells the loop to immediately exit after printing the error. dotconf-1.4.1/doc/dotconf-features.txt000066400000000000000000000037171460526106700177460ustar00rootroot00000000000000dot.conf feature descriptions ============================= Builtin Commands ================ dot.conf natively has the ability to 'Include' additional configuration files that can be found - relative to a path pointed to by the DC_INCLUDEPATH environment variable if it is set. - relative to a path which can be set using the includepath command in a configuration file. - at a fully qualified position (starting with a / ) - Relative to the directory containing the configuration file. Note that if the name of the configuration file contains no directory components, and none of the above cases apply, included files are relative to the current working directory. Use the Include command in your configuration file to include another file, and use the IncludePath command to specify the directory from which included files are taken. Note that if the user sets DC_INCLUDEPATH in the environment, this setting will override the includepath setting. Here Documents =============== dot.conf also supports so-called 'here-documents' as known from the shell or from PERL. this feature can be used for ARG_STR type options. a here-document is initiated by < the duplicates/ example has been provided by Joost Remijn to show what you can do with his DUPLICATE_OPTION_NAME feature. You need at least dot.conf 1.0.9 to use it. enjoy. dotconf-1.4.1/examples/argdouble/000077500000000000000000000000001460526106700167425ustar00rootroot00000000000000dotconf-1.4.1/examples/argdouble/Makefile000066400000000000000000000003731460526106700204050ustar00rootroot00000000000000TARGET=argdouble OBJS=argdouble.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=-ldotconf CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/argdouble/argdouble.c000066400000000000000000000010631460526106700210520ustar00rootroot00000000000000#include #include /* tabsize: 4 shiftwidth: 4 */ DOTCONF_CB(cb_argdouble); static configoption_t options[] = { {"ArgDouble", ARG_DOUBLE, cb_argdouble, NULL, 0}, LAST_OPTION }; DOTCONF_CB(cb_argdouble) { printf("[ArgDouble] %2.15g\n", cmd->data.dvalue); return NULL; } int main(int argc, char **argv) { configfile_t *configfile; configfile = dotconf_create("argdouble.conf", options, 0, 0); if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading config file\n"); dotconf_cleanup(configfile); return 0; } dotconf-1.4.1/examples/argdouble/argdouble.conf000066400000000000000000000001331460526106700215520ustar00rootroot00000000000000 ArgDouble 0.42 # M_PI as defined in /usr/include/math.h ArgDouble 3.14159265358979323846 dotconf-1.4.1/examples/argdouble/output000066400000000000000000000000561460526106700202260ustar00rootroot00000000000000[ArgDouble] 0.42 [ArgDouble] 3.14159265358979 dotconf-1.4.1/examples/caseinsensitive/000077500000000000000000000000001460526106700201725ustar00rootroot00000000000000dotconf-1.4.1/examples/caseinsensitive/Makefile000066400000000000000000000004071460526106700216330ustar00rootroot00000000000000TARGET=caseinsensitive OBJS=caseinsensitive.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=-ldotconf CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/caseinsensitive/caseinsensitive.c000066400000000000000000000012321460526106700235300ustar00rootroot00000000000000#include #include /* tabsize: 4 shiftwidth: 4 */ DOTCONF_CB(cb_strncasecmp); static configoption_t options[] = { {"StrNCAseCMp", ARG_STR, cb_strncasecmp, NULL, 0}, LAST_OPTION }; DOTCONF_CB(cb_strncasecmp) { printf("[StrNCAseCMp] %s\n", cmd->data.str); return NULL; } int main(int argc, char **argv) { configfile_t *configfile; printf("Reading the configuration with CASE_INSENSITIVE enabled\n"); configfile = dotconf_create("caseinsensitive.conf", options, 0, CASE_INSENSITIVE); if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading config file\n"); dotconf_cleanup(configfile); return 0; } dotconf-1.4.1/examples/caseinsensitive/caseinsensitive.conf000066400000000000000000000001711460526106700242340ustar00rootroot00000000000000StrNCAseCMp 'as registered' sTRncaSecMP 'mixed case' strncasecmp 'lower case' STRNCASECMP 'upper case' # inline comment dotconf-1.4.1/examples/caseinsensitive/output000066400000000000000000000002371460526106700214570ustar00rootroot00000000000000Reading the configuration with CASE_INSENSITIVE enabled [StrNCAseCMp] as registered [StrNCAseCMp] mixed case [StrNCAseCMp] lower case [StrNCAseCMp] upper case dotconf-1.4.1/examples/context/000077500000000000000000000000001460526106700164625ustar00rootroot00000000000000dotconf-1.4.1/examples/context/Makefile000066400000000000000000000004531460526106700201240ustar00rootroot00000000000000TARGET=context OBJS=context.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=`pkg-config dotconf --libs` ../libpool/libpool.a CC=gcc %.o: %.c $(CC) $(CFLAGS) -I../libpool -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/context/context.c000066400000000000000000000124141460526106700203140ustar00rootroot00000000000000#include #include #include /* vim:set ts=4: vim:set shiftwidth=4: */ /* this is a simple sample structure that we use to keep track of the current context in the configfile when reading it. It just has a field for the currently granted permissions. Later, when the option-table is defined, we'll specify the the needed permissions for each option. */ struct mycontext { int permissions; const char *current_end_token; pool_t *pool; }; enum permissions { O_ROOT = 1, O_SOMESECTION = 2, O_OTHERSECTION = 4, O_LAST = 8 }; static DOTCONF_CB(option_SomeSection_open); static DOTCONF_CB(option_OtherSection_open); static DOTCONF_CB(common_section_close); static DOTCONF_CB(common_option); /* the constant Section End tokens. We define these separately to be able to reuse pointers. We need this for our context 'sensitivity' system. */ static const char end_SomeSection[] = ""; static const char end_OtherSection[] = ""; /* the last field is used to specify the permissions needed for each option. These will be checked at runtime by our contextchecker */ static const configoption_t options[] = { {"", ARG_NONE, option_SomeSection_open, NULL, CTX_ALL}, {end_SomeSection, ARG_NONE, common_section_close, NULL, O_SOMESECTION}, {"", ARG_NONE, option_OtherSection_open, NULL, CTX_ALL}, {end_OtherSection, ARG_NONE, common_section_close, NULL, O_OTHERSECTION}, {"RootOption", ARG_NONE, common_option, NULL, CTX_ALL}, {"SomeOption", ARG_NONE, common_option, NULL, O_SOMESECTION}, {"OtherOption", ARG_NONE, common_option, NULL, O_OTHERSECTION}, {"Hybrid", ARG_NONE, common_option, NULL, O_SOMESECTION | O_OTHERSECTION}, LAST_OPTION }; const char *context_checker(command_t * cmd, unsigned long mask) { struct mycontext *context = cmd->context; /* * this test is quite simple: if the permissions needed for the * to-be-called command are not granted, we'll deny service */ /* Root Context granted and Root Context given? */ if (!mask && !context->permissions) return NULL; if (!(context->permissions & mask)) { return pool_strcat(context->pool, "Option '", cmd->name, "' not allowed in <", context->current_end_token ? context-> current_end_token + 2 : "global>", " context", NULL); } return NULL; } FUNC_ERRORHANDLER(error_handler) { fprintf(stderr, "[error] %s\n", msg); /* continue reading the configfile ; return 1 stop after first error found */ return 0; } int main(void) { configfile_t *configfile; struct mycontext context; context.current_end_token = 0; context.permissions = 0; context.pool = pool_new(NULL); configfile = dotconf_create("./context.conf", options, (void *)&context, CASE_INSENSITIVE); if (!configfile) { fprintf(stderr, "Error opening configuration file\n"); return 1; } configfile->errorhandler = (dotconf_errorhandler_t) error_handler; configfile->contextchecker = (dotconf_contextchecker_t) context_checker; if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading configuration file\n"); dotconf_cleanup(configfile); pool_free(context.pool); return 0; } DOTCONF_CB(common_section_close) { struct mycontext *context = (struct mycontext *)ctx; if (!context->current_end_token) return pool_strcat(context->pool, cmd->name, " without matching <", cmd->name + 2, " section", NULL); if (context->current_end_token != cmd->name) return pool_strcat(context->pool, "Expected '", context->current_end_token, "' but saw ", cmd->name, NULL); return context->current_end_token; } DOTCONF_CB(common_option) { printf("Option %s called\n", cmd->name); return NULL; } DOTCONF_CB(option_SomeSection_open) { struct mycontext *context = (struct mycontext *)ctx; const char *old_end_token = context->current_end_token; int old_override = context->permissions; const char *err = 0; if (context->permissions & O_SOMESECTION) return " cannot be nested"; context->permissions |= O_SOMESECTION; context->current_end_token = end_SomeSection; while (!cmd->configfile->eof) { err = dotconf_command_loop_until_error(cmd->configfile); if (!err) { err = " is missing"; break; } if (err == context->current_end_token) break; dotconf_warning(cmd->configfile, DCLOG_ERR, 0, err); } context->current_end_token = old_end_token; context->permissions = old_override; if (err != end_SomeSection) return err; return NULL; } DOTCONF_CB(option_OtherSection_open) { struct mycontext *context = (struct mycontext *)ctx; const char *old_end_token = context->current_end_token; int old_override = context->permissions; const char *err = 0; if (context->permissions & O_OTHERSECTION) return " Cannot be nested"; context->permissions |= O_OTHERSECTION; context->current_end_token = end_OtherSection; while (!cmd->configfile->eof) { err = dotconf_command_loop_until_error(cmd->configfile); if (!err) { err = " is missing"; break; } if (err == context->current_end_token) break; dotconf_warning(cmd->configfile, DCLOG_ERR, 0, err); } context->current_end_token = old_end_token; context->permissions = old_override; if (err != end_OtherSection) return err; return NULL; } dotconf-1.4.1/examples/context/context.conf000066400000000000000000000003031460526106700210110ustar00rootroot00000000000000 SomeOption OtherOption Hybrid RootOption SomeOption OtherOption Hybrid RootOption SomeOption OtherOption Hybrid RootOption dotconf-1.4.1/examples/context/output000066400000000000000000000010561460526106700177470ustar00rootroot00000000000000[error] Option 'SomeOption' not allowed in context [error] Option 'OtherOption' not allowed in context [error] Option 'Hybrid' not allowed in context [error] Option 'OtherOption' not allowed in context [error] Option 'RootOption' not allowed in context [error] Option 'SomeOption' not allowed in context [error] Option 'RootOption' not allowed in context Option RootOption called Option SomeOption called Option Hybrid called Option OtherOption called Option Hybrid called dotconf-1.4.1/examples/duplicates/000077500000000000000000000000001460526106700171335ustar00rootroot00000000000000dotconf-1.4.1/examples/duplicates/Makefile000066400000000000000000000006501460526106700205740ustar00rootroot00000000000000CFLAGS=-Wall -O2 -g LDFLAGS= LIBS=-ldotconf ../libpool/libpool.a -ldl CC=gcc %.o: %.c $(CC) $(CFLAGS) -I../libpool -o $@ -c $< all: duplicate first_module.so second_module.so duplicate: duplicate.o $(CC) -o $@ $< $(LDFLAGS) $(LIBS) first_module.so: first_module.o $(CC) -o $@ $< -rdynamic -shared $(LIBS) second_module.so: second_module.o $(CC) -o $@ $< -rdynamic -shared $(LIBS) clean: rm -f *.so *.o duplicate dotconf-1.4.1/examples/duplicates/duplicate.c000066400000000000000000000204241460526106700212530ustar00rootroot00000000000000 /* You need at least dot.conf 1.0.9 to compile and run this example !! */ #include /* fprintf(), stderr */ #include /* realloc() */ #include /* strcmp() */ /* this example does not work for WIN32 */ #ifndef WIN32 #include /* dlopen(), dlerror(), dlclose() */ #include #endif #include #include struct config_context { long current_context; char current_end_token[1024]; pool_t *pool; }; struct ptr_list { int n_entries; void **entries; }; static DOTCONF_CB(section_open); static DOTCONF_CB(section_close); static DOTCONF_CB(common_option); static DOTCONF_CB(addmodule_option); /* // the last field is used to specify the context needed for // each option. These will be checked at runtime by our contextchecker // */ static const configoption_t options[] = { {"AddModule", ARG_LIST, addmodule_option, NULL, 0}, {"ToggleOption", ARG_TOGGLE, common_option, NULL, 0}, LAST_OPTION }; /* // The pointer list of dynamic options. // This is necessary to be able to free it up later. // */ struct ptr_list memory_junk; #define MAX_MODULES 10 static void *handles[MAX_MODULES]; /* handles of dynamically loaded modules */ const char *context_checker(command_t * cmd, unsigned long option_context) { struct config_context *context = cmd->context; if (context->current_context != option_context) { return pool_strcat(context->pool, "Option '", cmd->name, "' not allowed in <", (strlen(context->current_end_token) > 2) ? context->current_end_token + 2 : "global>", " context", NULL); } return NULL; } FUNC_ERRORHANDLER(error_handler) { fprintf(stderr, "%s:%ld:[error] %s\n", configfile->filename, configfile->line, msg); /* continue reading the configfile ; return 1 stop after first error found */ return 0; } int main(int argc, char *argv[]) { configfile_t *configfile; struct config_context context; if (argc < 2) { fprintf(stderr, "Usage : %s \n", argv[0]); return 1; } context.current_end_token[0] = '\0'; context.current_context = 0; context.pool = pool_new(NULL); memory_junk.n_entries = 0; memory_junk.entries = 0; memset(handles, 0, sizeof(handles)); configfile = dotconf_create(argv[1], options, (void *)&context, CASE_INSENSITIVE | DUPLICATE_OPTION_NAMES); if (!configfile) { fprintf(stderr, "Error opening configuration file\n"); return 1; } configfile->errorhandler = (dotconf_errorhandler_t) error_handler; configfile->contextchecker = (dotconf_contextchecker_t) context_checker; if (dotconf_command_loop(configfile) == 0) { fprintf(stderr, "Error reading configuration file\n"); return 1; } dotconf_cleanup(configfile); pool_free(context.pool); /* clean up the possible memjunk which needed to stay in memory */ if (memory_junk.n_entries) { int idx; for (idx = 0; idx < memory_junk.n_entries; idx++) { free(memory_junk.entries[idx]); } } free(memory_junk.entries); return 0; } DOTCONF_CB(section_open) { struct config_context *context = (struct config_context *)ctx; const char *old_end_token = context->current_end_token; int prev_context = context->current_context; const char *err = 0; context->current_context = (long)cmd->option->info; sprintf(context->current_end_token, "name + 1); while (!cmd->configfile->eof) { err = dotconf_command_loop_until_error(cmd->configfile); if (!err) { err = pool_strcat(context->pool, "name + 1, " is missing", NULL); break; } if (err == context->current_end_token) { break; } dotconf_warning(cmd->configfile, DCLOG_ERR, 0, err); } sprintf(context->current_end_token, "%s", old_end_token); context->current_context = prev_context; if (err != context->current_end_token) { return err; } return NULL; } DOTCONF_CB(section_close) { struct config_context *context = (struct config_context *)ctx; if (!context->current_end_token) { return pool_strcat(context->pool, cmd->name, " without matching <", cmd->name + 2, " section", NULL); } if (strcmp(context->current_end_token, cmd->name) != 0) { return pool_strcat(context->pool, "Expected '", context->current_end_token, "' but saw ", cmd->name, NULL); } return context->current_end_token; } DOTCONF_CB(common_option) { fprintf(stderr, "common_option : Option %s called Not doing anything with it...\n", cmd->name); return NULL; } /* // We expect option name filename // e.g. AddModule first ./plugins/decision-test.so // // So in the list : // 0 -> name // 1 -> so_filename */ DOTCONF_CB(addmodule_option) { struct config_context *context = (struct config_context *)ctx; configoption_t *module_options; const char *error = 0; int handle_idx = -1; char filename[FILENAME_MAX] = ""; void *shared_object = 0; fprintf(stderr, "addmodule_option : Option %s called\n", cmd->name); if (cmd->arg_count < 2) { return pool_strcat(context->pool, "Not enough parameters to option ", cmd->name, " expected 2", NULL); } // load the damn thing for (handle_idx = 0; handle_idx < MAX_MODULES; handle_idx++) { if (handles[handle_idx] == 0) { snprintf(filename, 128, "./%s.so", cmd->data.list[1]); if (access(filename, R_OK) == 0) { /* if file access is permitted */ /* load library */ handles[handle_idx] = dlopen(filename, RTLD_LAZY); if (!handles[handle_idx]) { fprintf(stderr, "Error opening library: %s\n", dlerror()); return "Error opening library"; } shared_object = handles[handle_idx]; break; } else { return pool_strcat(context->pool, "Can't open file ", filename, NULL); } } } if (handle_idx == MAX_MODULES) { return "Out of handle space. Not loading module\n"; } // get the options module_options = dlsym(shared_object, "options"); error = dlerror(); if (error) { fprintf(stderr, "addmodule_option() : Error finding the options variable in %s p=%p (%s)\n", cmd->data.list[1], shared_object, error); dlclose(shared_object); handles[handle_idx] = 0; return NULL; } /* // Scope the options of this module to a block where NAME is // the name that was specified in the configfile. // // The context field holds a unique identifier so we can verify in our // contextchecker that this option belongs to the right scope. // */ { char *begin_context_tag = (char *)malloc(strlen(cmd->data.list[1]) + 2 + 1); char *end_context_tag = (char *)malloc(strlen(cmd->data.list[1]) + 3 + 1); configoption_t *scope_options = 0; int opt_idx = -1; scope_options = (configoption_t *) malloc(3 * sizeof(configoption_t)); if (!scope_options || !begin_context_tag || !end_context_tag) { return "Error allocating memory"; } sprintf(begin_context_tag, "<%s>", cmd->data.list[0]); sprintf(end_context_tag, "", cmd->data.list[0]); // create our two extra options (scope begin/end) and a NULL option to close // the list scope_options[0].name = begin_context_tag; scope_options[0].type = ARG_NONE; scope_options[0].callback = section_open; scope_options[0].info = shared_object; scope_options[0].context = CTX_ALL; scope_options[1].name = end_context_tag; scope_options[1].type = ARG_NONE; scope_options[1].callback = section_close; scope_options[1].info = NULL; scope_options[1].context = (long)shared_object; scope_options[2].name = ""; scope_options[2].type = 0; scope_options[2].callback = NULL; scope_options[2].info = NULL; scope_options[2].context = 0; /* Set the context field of all options from the module to the identifier */ for (opt_idx = 0; strlen(module_options[opt_idx].name); opt_idx++) { module_options[opt_idx].context = (long)shared_object; } memory_junk.entries = realloc(memory_junk.entries, (memory_junk.n_entries + 3) * sizeof(void *)); memory_junk.entries[memory_junk.n_entries++] = begin_context_tag; memory_junk.entries[memory_junk.n_entries++] = end_context_tag; memory_junk.entries[memory_junk.n_entries++] = scope_options; dotconf_register_options(cmd->configfile, scope_options); dotconf_register_options(cmd->configfile, module_options); } fprintf(stderr, "Successfully loaded module %s (%s)\n", cmd->data.list[1], cmd->data.list[1]); return NULL; } dotconf-1.4.1/examples/duplicates/first_module.c000066400000000000000000000004511460526106700217730ustar00rootroot00000000000000#include #include static DOTCONF_CB(cb_newoption) { printf("[FIRST_MODULE] Line %ld: Option=%s str=%s\n", cmd->configfile->line, cmd->name, cmd->data.str); return NULL; } configoption_t options[] = { {"DupOption", ARG_STR, cb_newoption, 0, 0} , LAST_OPTION }; dotconf-1.4.1/examples/duplicates/output000066400000000000000000000004501460526106700204150ustar00rootroot00000000000000addmodule_option : Option AddModule called Successfully loaded module first_module (first_module) addmodule_option : Option AddModule called Successfully loaded module second_module (second_module) [FIRST_MODULE] Line 9: Option=DupOption str=text [SECOND_MODULE] Line 13: Option=DupOption int=16 dotconf-1.4.1/examples/duplicates/sample.conf000066400000000000000000000004721460526106700212660ustar00rootroot00000000000000# Add the modules. # The first parameter is the name and the second the module filename (without # .so). AddModule first first_module AddModule second second_module # The scope is automgically added by duplicate.c and depends on the name DupOption text DupOption 16 dotconf-1.4.1/examples/duplicates/second_module.c000066400000000000000000000005661460526106700221260ustar00rootroot00000000000000#include #include static DOTCONF_CB(cb_newoption) { printf("[SECOND_MODULE] Line %ld: Option=%s int=%ld\n", cmd->configfile->line, cmd->name, cmd->data.value); return NULL; } /* It's important to NOT make this const. That makes duplicate.c SEGV */ configoption_t options[] = { {"DupOption", ARG_INT, cb_newoption, 0, 0} , LAST_OPTION }; dotconf-1.4.1/examples/errorhandler/000077500000000000000000000000001460526106700174655ustar00rootroot00000000000000dotconf-1.4.1/examples/errorhandler/Makefile000066400000000000000000000004011460526106700211200ustar00rootroot00000000000000TARGET=errorhandler OBJS=errorhandler.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=-ldotconf CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/errorhandler/errorhandler.c000066400000000000000000000014011460526106700223140ustar00rootroot00000000000000#include #include /* tabsize: 4 shiftwidth: 4 */ FUNC_ERRORHANDLER(errorhandler); DOTCONF_CB(cb_errorhandler); static configoption_t options[] = { {"ErrorHandler", ARG_STR, cb_errorhandler, NULL, 0}, LAST_OPTION }; FUNC_ERRORHANDLER(errorhandler) { printf("ERROR %s\n", msg); return 0; } DOTCONF_CB(cb_errorhandler) { printf("[ErrorHandler Option] %s\n", cmd->data.str); return NULL; } int main(int argc, char **argv) { configfile_t *configfile; configfile = dotconf_create("errorhandler.conf", options, 0, 0); configfile->errorhandler = (dotconf_errorhandler_t) errorhandler; if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading configfile\n"); dotconf_cleanup(configfile); return 0; } dotconf-1.4.1/examples/errorhandler/errorhandler.conf000066400000000000000000000000441460526106700230210ustar00rootroot00000000000000ErrorHandler argument UnknownOption dotconf-1.4.1/examples/errorhandler/output000066400000000000000000000001141460526106700207440ustar00rootroot00000000000000[ErrorHandler Option] argument ERROR Unknown Config-Option: 'UnknownOption' dotconf-1.4.1/examples/fallback/000077500000000000000000000000001460526106700165355ustar00rootroot00000000000000dotconf-1.4.1/examples/fallback/Makefile000066400000000000000000000003711460526106700201760ustar00rootroot00000000000000TARGET=fallback OBJS=fallback.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=-ldotconf CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/fallback/fallback.c000066400000000000000000000013021460526106700204340ustar00rootroot00000000000000#include #include /* tabsize: 4 shiftwidth: 4 */ DOTCONF_CB(cb_fallback); static configoption_t options[] = { {"", ARG_NAME, cb_fallback, NULL, 0}, LAST_OPTION }; DOTCONF_CB(cb_fallback) { int i; printf("Fallback handler called for \"%s\". Got %d args\n", cmd->name, cmd->arg_count); for (i = 0; i < cmd->arg_count; i++) printf("\tArg #%d: %s\n", i, cmd->data.list[i]); return NULL; } int main(int argc, char **argv) { configfile_t *configfile; configfile = dotconf_create("fallback.conf", options, 0, 0); if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading configfile\n"); dotconf_cleanup(configfile); return 0; } dotconf-1.4.1/examples/fallback/fallback.conf000066400000000000000000000001351460526106700211420ustar00rootroot00000000000000UnknownOption these are handled like ARG_LIST! Foo test test2 Bar abcd efgh Baz lala alal dotconf-1.4.1/examples/fallback/output000066400000000000000000000005451460526106700200240ustar00rootroot00000000000000Fallback handler called for "UnknownOption". Got 5 args Arg #0: these Arg #1: are Arg #2: handled Arg #3: like Arg #4: ARG_LIST! Fallback handler called for "Foo". Got 2 args Arg #0: test Arg #1: test2 Fallback handler called for "Bar". Got 2 args Arg #0: abcd Arg #1: efgh Fallback handler called for "Baz". Got 2 args Arg #0: lala Arg #1: alal dotconf-1.4.1/examples/libpool/000077500000000000000000000000001460526106700164365ustar00rootroot00000000000000dotconf-1.4.1/examples/libpool/Makefile000066400000000000000000000000331460526106700200720ustar00rootroot00000000000000libpool.a(pool.o): pool.c dotconf-1.4.1/examples/libpool/libpool.h000066400000000000000000000025041460526106700202500ustar00rootroot00000000000000#ifndef ST_HAVE_POOL_H #define ST_HAVE_POOL_H #ifdef __cplusplus extern "C" { #endif typedef struct pool pool_t; /* ------ pool_new - create and return a new pool; make a sub-pool of p if p is non-NULL -------- */ struct pool *pool_new(struct pool *p); /* ------ pool_free - destroy a pool and free all memory acquired in this pool and subpools - */ void pool_free(struct pool *pool); /* ------ pool_alloc - allocate memory inside of pool ------------------------------------------- */ void *pool_alloc(struct pool *pool, int size); /* ------ pool_calloc - allocate memory inside of pool and set to 0 ----------------------------- */ void *pool_calloc(struct pool *pool, int size); /* ------ pool_strcat - concatenate the strings in ...; all parts must be char*, last be NULL --- */ char *pool_strcat(struct pool *pool, ...); /* ------ pool_strdup - duplicate the string within pool ---------------------------------------- */ char *pool_strdup(struct pool *pool, const char *str); /* ------ pool_sprintf - sprintf fmt and ... in pool; currently limited to max length of 8192 --- */ char *pool_sprintf(struct pool *pool, const char *fmt, ...); /* duplicate the first n non-null characters beginning at str */ char *pool_strndup(struct pool *pool, const char *str, int n); #ifdef __cplusplus } /* extern "C" */ #endif #endif dotconf-1.4.1/examples/libpool/pool.c000066400000000000000000000134141460526106700175560ustar00rootroot00000000000000/* libpool - simple memory management library * Copyright (C) 2000,2001 Lukas Schroeder * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ #define LIBPOOL_VERSION "0.1.1 - 20 Jun 2001" static const char libpool_version[] = LIBPOOL_VERSION; #include #include #include #include #ifdef WIN32 #define vsnprintf _vsnprintf #else #include #endif #include "libpool.h" /* Things in struct pool at ->pointers get allocated in a manner similar to allocating and updating a singly list list of this type struct { void *next; void *data; }; In fact, pool->pointers is nothing else :-) This is also true for sub_pools, although i created their own type for readability of the code. On malloc, the ptr is prepended to the list for performance. The first pointer added to the list (say, the last item) is the pointer returned when malloc()ing memory for the struct pool itself. That's why we dont need to bother free()ing the structure pointer separately b/c this is done automagically upon list destruction. */ /* memory allocation code */ #undef malloc #undef free typedef struct sub_pool sub_pool; struct pool { /* num of bytes allocated with reference to this pool note: this element is not maintained during free's ! */ unsigned long size; /* list of allocated pointers */ void *pointers; sub_pool *sub_pools; /* sub pools */ struct pool *parent; }; struct sub_pool { void *base; struct pool *pool; }; /* the size needed at the beginning of ->pointers to store the pointer to the next element of the list */ #define ALLOC_HDR_SIZE (sizeof(void *)) /* acquire a new pool */ struct pool *pool_new(struct pool *p) { void *acquired; struct pool *pool; int size = sizeof(struct pool) + ALLOC_HDR_SIZE; acquired = malloc(size); memset(acquired, 0, size); /* a pool is 'acquired' at the beginning of it's own ->pointers */ *(void **)acquired = 0; pool = (struct pool *)((unsigned long)acquired + ALLOC_HDR_SIZE); memset(pool, 0, sizeof(struct pool)); pool->parent = p; pool->sub_pools = 0; pool->pointers = acquired; if (pool->parent) { sub_pool *subpool = pool_calloc(pool->parent, sizeof(sub_pool)); subpool->pool = pool; *(sub_pool **) subpool = pool->parent->sub_pools; pool->parent->sub_pools = subpool; } return pool; } /* free a pool and all subpools */ void pool_free(struct pool *pool) { void *n, *c; /* next and current */ if (!pool) return; /* somebody fucks around */ if (pool->parent && pool->parent->sub_pools) { sub_pool *s_pool, *ps_pool; /* previous and current */ /* find the pointer to pool in the parent's subpool list and it's ancestor */ for (ps_pool = s_pool = pool->parent->sub_pools; s_pool && s_pool->pool != pool; ps_pool = s_pool, s_pool = s_pool->base) ; if (ps_pool == s_pool && !s_pool->base) /* remove last sub_pool */ pool->parent->sub_pools = 0; else if (ps_pool == s_pool && s_pool->base) /* replace root node */ pool->parent->sub_pools = s_pool->base; else if (ps_pool && s_pool) /* remove man-in-the-middle */ ps_pool->base = s_pool->base; } /* free up the sub_pools recursively */ for (c = pool->sub_pools; c; c = n) { n = *(void **)c; pool_free(((sub_pool *) c)->pool); } /* free all pointers listed in ->pointers; * the last pointer free'd is the pool itself */ for (c = pool->pointers; c; c = n) { n = *(void **)c; free(c); } } void *pool_alloc(struct pool *pool, int size) { void *ptr; if (!pool) { fprintf(stderr, "Hey, fuckhead, gimme a pool if you want memory!\n"); exit(1); } size += ALLOC_HDR_SIZE; pool->size += size; ptr = malloc(size); if (!ptr) { fprintf(stderr, "Ouch...out of memory\n"); exit(1); } memset(ptr, 0, size); *(void **)ptr = pool->pointers; pool->pointers = ptr; return (void *)((unsigned long)ptr + ALLOC_HDR_SIZE); } void *pool_calloc(struct pool *pool, int size) { void *acquired; acquired = pool_alloc(pool, size); memset(acquired, 0, size); return acquired; } /* all '...' MUST be char* */ char *pool_strcat(struct pool *pool, ...) { va_list args; int size; char *str, *result, *cp; va_start(args, pool); /* get the length of all string to know how much memory to allocate */ for (size = 0; (str = va_arg(args, char *));) size += strlen(str); va_end(args); result = pool_alloc(pool, size + 1); cp = result; *cp = 0; /* now start copying every string onto the end of result */ va_start(args, pool); while ((str = va_arg(args, char *))) { strcpy(cp, str); cp += strlen(str); } va_end(args); return result; } char *pool_strdup(struct pool *pool, const char *str) { char *res; res = pool_alloc(pool, strlen(str) + 1); strcpy(res, str); return res; } char *pool_strndup(struct pool *pool, const char *str, int n) { char *res; res = pool_alloc(pool, n + 1); strncpy(res, str, n); *(res + n) = 0; return res; } char *pool_sprintf(struct pool *pool, const char *fmt, ...) { /* FIXME: pool_sprintf is limited to 8192 max length */ char buffer[8192]; va_list args; va_start(args, fmt); vsnprintf(buffer, 8192, fmt, args); va_end(args); return pool_strdup(pool, buffer); } dotconf-1.4.1/examples/maketest.sh000077500000000000000000000014751460526106700171610ustar00rootroot00000000000000 function makepool() { cd libpool echo building libpool. make > /dev/null 2>&1 test $? -ne 0 && { echo unable to build libpool!; exit ;} cd .. } function dotest() { d=$1 shift echo -en test: $d "\t\t" cd $d make > /dev/null 2>&1 test "$?" -ne "0" && { echo "make for test {$d} failed!"; failed=1;} a="$@" $a > testoutput 2>&1 cmp -s testoutput output if test "$?" -ne "0"; then echo "test $d failed! output was:"; cat testoutput; echo; failed=1; else echo "success"; fi make clean > /dev/null 2>&1 cd .. } failed=0 dotest caseinsensitive ./caseinsensitive dotest errorhandler ./errorhandler dotest fallback ./fallback dotest modules ./module dotest noinline ./noinline dotest simple ./simple dotest argdouble ./argdouble makepool dotest context ./context dotest duplicates ./duplicate sample.conf dotconf-1.4.1/examples/modules/000077500000000000000000000000001460526106700164465ustar00rootroot00000000000000dotconf-1.4.1/examples/modules/Makefile000066400000000000000000000005301460526106700201040ustar00rootroot00000000000000TARGET=module OBJS=module.o ####################### CFLAGS=-Wall -O2 -g LDFLAGS= LIBS=-ldotconf -ldl CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) my_module.so $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) my_module.so: my_module.o $(CC) -o $@ $< -rdynamic -shared clean: rm -f $(OBJS) $(TARGET) my_module.so *.o dotconf-1.4.1/examples/modules/include.conf000066400000000000000000000001641460526106700207410ustar00rootroot00000000000000ExampleOption 'some included quoted value' ExampleOption "differently quoted string" ExampleOption "some bla'blah'" dotconf-1.4.1/examples/modules/module.c000066400000000000000000000065371460526106700201120ustar00rootroot00000000000000#include #include #include /* this example does not work for WIN32 */ #ifndef WIN32 #include /* for dlopen(), dlerror(), dlclose() */ #include #endif #include /* define our callbacks; */ /* for definition of DOTCONF_CB see dotconf.h */ static DOTCONF_CB(cb_example); static DOTCONF_CB(cb_moreargs); static DOTCONF_CB(cb_addmodule); static DOTCONF_CB(cb_multiline); /* here document test */ static DOTCONF_CB(cb_unknown); /* fallback for unknwon options */ /* define the Option ExampleOption that expects a string * and tell the parser to call the function cb_example */ static const configoption_t options[] = { {"ExampleOption", ARG_STR, cb_example, 0, 0}, {"MoreArgs", ARG_LIST, cb_moreargs, 0, 0}, {"AddModule", ARG_STR, cb_addmodule, 0, 0}, {"MultiLineRaw", ARG_STR, cb_multiline, 0, 0}, {"", ARG_NAME, cb_unknown, 0, 0}, LAST_OPTION }; #define NUM_MODULES 10 static void *handles[NUM_MODULES]; /* handles of dynamically loaded modules */ int main(int argc, char **argv) { int i; configfile_t *configfile; memset(handles, 0, sizeof(handles)); putenv("TESTUSER=lukas"); /* * start reading config, CASE_INSENSITIVE (specify NONE or 0 for the * the default behaviour which matches case sensitive */ configfile = dotconf_create(argv[1] ? argv[1] : "sample.conf", options, 0, CASE_INSENSITIVE); if (!configfile) { fprintf(stderr, "Error opening config file\n"); return 1; } if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading config file\n"); dotconf_cleanup(configfile); for (i = 0; i < NUM_MODULES && handles[i]; i++) dlclose(handles[i]); return 0; } /* the error-handler; a new feature of v0.7.0 to filter out messages issued using config_warning FUNC_ERRORHANDLER(my_errorhandler) { printf("ERROR [type=%d][%d] %s\n", type, dc_errno, msg); } */ /* declare our callback function */ DOTCONF_CB(cb_example) { printf("%s:%ld: ExampleOption: [arg=%s]\n", cmd->configfile->filename, cmd->configfile->line, cmd->data.str); return NULL; } /* * we dont need the userdata, so dont mention it * otherwise we should've appended it as argument 3 */ DOTCONF_CB(cb_moreargs) { int i; for (i = 0; i < cmd->arg_count; i++) printf("%s:%ld: [MoreArgs] Arg #%d '%s'\n", cmd->configfile->filename, cmd->configfile->line, i + 1, cmd->data.list[i]); return 0; } DOTCONF_CB(cb_addmodule) { int i; char filename[128]; /* filename of modules */ for (i = 0; (i < NUM_MODULES) && (handles[i] != 0); i++) ; snprintf(filename, 128, "./%s.so", cmd->data.str); if (!access(filename, R_OK)) { /* if file access is permitted */ /* load library */ handles[i] = dlopen(filename, RTLD_LAZY); if (!handles[i]) printf("Error opening library: %s\n", dlerror()); dotconf_register_options(cmd->configfile, dlsym(handles[i], "new_options")); } printf("Module %s successfully loaded\n", cmd->data.str); return NULL; } DOTCONF_CB(cb_multiline) { printf("%s:%ld: [MultiLine - START] -%s- [MultiLine - END]\n", cmd->configfile->filename, cmd->configfile->line, cmd->data.str); return NULL; } DOTCONF_CB(cb_unknown) { int i = 0; printf("%s:%ld: UNKNOWN [%s]", cmd->configfile->filename, cmd->configfile->line, cmd->name); for (i = 0; cmd->data.list[i]; i++) printf(", %s", cmd->data.list[i]); printf("\n"); return NULL; } dotconf-1.4.1/examples/modules/my_module.c000066400000000000000000000007361460526106700206120ustar00rootroot00000000000000#include #include /* lets get access to the current line inside of the config.file */ /* this only resolves if the executable was link with the -rdynamic flag! */ static DOTCONF_CB(cb_newoption) { printf("[MODULE] Line %ld: NewOption: %s\n", cmd->configfile->line, cmd->data.str); return NULL; } /* example.c loads the symbol 'new_options' */ const configoption_t new_options[] = { {"NewOption", ARG_STR, cb_newoption, 0, 0}, LAST_OPTION }; dotconf-1.4.1/examples/modules/output000066400000000000000000000015611460526106700177340ustar00rootroot00000000000000sample.conf:2: UNKNOWN [BlahBlah] sample.conf:7: ExampleOption: [arg=SomeValue] sample.conf:12: ExampleOption: [arg=/test] sample.conf:14: ExampleOption: [arg=lukas] sample.conf:16: ExampleOption: [arg=case insensitive matching is optional] include.conf:1: ExampleOption: [arg=some included quoted value] include.conf:2: ExampleOption: [arg=differently quoted string] include.conf:3: ExampleOption: [arg=some bla'blah'] sample.conf:23: [MoreArgs] Arg #1 'argument1' sample.conf:23: [MoreArgs] Arg #2 'argument2' sample.conf:25: [MoreArgs] Arg #1 'tabbed' sample.conf:25: [MoreArgs] Arg #2 'spaced' sample.conf:25: [MoreArgs] Arg #3 'and' sample.conf:25: [MoreArgs] Arg #4 'even' sample.conf:25: [MoreArgs] Arg #5 'more' Module my_module successfully loaded sample.conf:35: [MultiLine - START] - some raw multiline data- [MultiLine - END] [MODULE] Line 38: NewOption: hello dotconf-1.4.1/examples/modules/sample.conf000066400000000000000000000020171460526106700205760ustar00rootroot00000000000000# unknown option BlahBlah to test the ARG_NAME option fallback BlahBlah # a comment followed by an empty newline # indented options now work (v0.5) ExampleOption SomeValue # since v0.5.2 simple env-var substitution with defaults is supported # everything between :- and } is taken as the default value in case # BLAH is an undefined environment variable ExampleOption ${BLAH:-/test} ExampleOption ${TESTUSER} # case insensitive matching via run-time flag (v0.7.0) EXAMplEOPtIon 'case insensitive matching is optional' # since v0.5.1 this setting might temporarily be overridden by using # the DC_INCLUDEPATH environment variable #IncludePath /tmp/dotconf Include include.conf MoreArgs argument1 argument2 # the following MoreArgs-Line ends with additional whitespace MoreArgs tabbed spaced and even more # tell example.c to load my_module.so AddModule my_module # support for here documents MultiLineRaw < #include /* tabsize: 4 shiftwidth: 4 */ DOTCONF_CB(cb_noinline) { int i; printf("[NoInline] Have %d args\n", cmd->arg_count); for (i = 0; i < cmd->arg_count; i++) printf("\t[NoInline] Arg #%d: %s\n", i, cmd->data.list[i]); return NULL; } static configoption_t options[] = { {"NoInline", ARG_LIST, cb_noinline, NULL, 0}, LAST_OPTION }; void readit(int flags) { configfile_t *configfile; configfile = dotconf_create("noinline.conf", options, 0, flags); if (!dotconf_command_loop(configfile)) fprintf(stderr, "Error reading config file\n"); dotconf_cleanup(configfile); } int main(int argc, char **argv) { printf("Reading the configuration with NO_INLINE_COMMENTS enabled\n"); readit(NO_INLINE_COMMENTS); printf("\n\n"); printf("Reading the configuration with NO_INLINE_COMMENTS disabled\n"); readit(0); return 0; } dotconf-1.4.1/examples/noinline/noinline.conf000066400000000000000000000004221460526106700212710ustar00rootroot00000000000000# the default behaviour for dot.conf is to stop parsing as # soon as the first unquoted, unescaped #-sign is found # you can override it by giving the flag NO_INLINE_COMMENTS to dotconf_create() NoInline 'upper case' #inline comment NoInline 'upper case' # inline comment dotconf-1.4.1/examples/noinline/output000066400000000000000000000007241460526106700200770ustar00rootroot00000000000000Reading the configuration with NO_INLINE_COMMENTS enabled [NoInline] Have 3 args [NoInline] Arg #0: upper case [NoInline] Arg #1: #inline [NoInline] Arg #2: comment [NoInline] Have 4 args [NoInline] Arg #0: upper case [NoInline] Arg #1: # [NoInline] Arg #2: inline [NoInline] Arg #3: comment Reading the configuration with NO_INLINE_COMMENTS disabled [NoInline] Have 1 args [NoInline] Arg #0: upper case [NoInline] Have 1 args [NoInline] Arg #0: upper case dotconf-1.4.1/examples/simple/000077500000000000000000000000001460526106700162675ustar00rootroot00000000000000dotconf-1.4.1/examples/simple/Makefile000066400000000000000000000003651460526106700177330ustar00rootroot00000000000000TARGET=simple OBJS=simple.o ####################### CFLAGS=-Wall -O2 LDFLAGS= LIBS=-ldotconf CC=gcc %.o: %.c $(CC) $(CFLAGS) -o $@ -c $< all: $(TARGET) $(TARGET): $(OBJS) $(CC) -o $@ $< $(LDFLAGS) $(LIBS) clean: rm -f $(OBJS) $(TARGET) dotconf-1.4.1/examples/simple/included.conf000066400000000000000000000003261460526106700207260ustar00rootroot00000000000000ExampleStr test ExampleList arg0 arg1 arg2 ExampleStr "multiple words here" ExampleStr 'multiple again' ExampleStr 'multi with quote " inside of quote "' ExampleStr "multi with quote \" inside of escaped quote \"" dotconf-1.4.1/examples/simple/linecat.conf000066400000000000000000000002471460526106700205600ustar00rootroot00000000000000# a probably well-known line from httpd.conf :-) CustomLog /usr/local/apache-ssl/logs/ssl_request_log \ "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" dotconf-1.4.1/examples/simple/output000066400000000000000000000006761460526106700175630ustar00rootroot00000000000000simple.conf:2: ExampleList: [ (0) "line1 (1) line2skdfj ] simple.conf:7: ExampleStr: [line 1 line 2] included.conf:1: ExampleStr: [test] included.conf:2: ExampleList: [ (0) arg0 (1) arg1 (2) arg2 ] included.conf:3: ExampleStr: [multiple words here] included.conf:4: ExampleStr: [multiple again] included.conf:5: ExampleStr: [multi with quote " inside of quote "] included.conf:6: ExampleStr: [multi with quote " inside of escaped quote "] dotconf-1.4.1/examples/simple/simple.c000066400000000000000000000021411460526106700177220ustar00rootroot00000000000000#include #include #include static DOTCONF_CB(cb_list); static DOTCONF_CB(cb_str); static const configoption_t options[] = { {"ExampleStr", ARG_STR, cb_str, NULL, CTX_ALL}, {"ExampleList", ARG_LIST, cb_list, NULL, CTX_ALL}, LAST_OPTION }; int main(int argc, char **argv) { configfile_t *configfile; configfile = dotconf_create(argv[1] ? argv[1] : "simple.conf", options, NULL, CASE_INSENSITIVE); if (!configfile) { fprintf(stderr, "Error opening config file\n"); return 1; } if (dotconf_command_loop(configfile) == 0) fprintf(stderr, "Error reading config file\n"); dotconf_cleanup(configfile); return 0; } DOTCONF_CB(cb_list) { int i; printf("%s:%ld: %s: [ ", cmd->configfile->filename, cmd->configfile->line, cmd->name); for (i = 0; i < cmd->arg_count; i++) printf("(%d) %s ", i, cmd->data.list[i]); printf("]\n"); return NULL; } DOTCONF_CB(cb_str) { printf("%s:%ld: %s: [%s]\n", cmd->configfile->filename, cmd->configfile->line, cmd->name, cmd->data.str); return NULL; } /* vim:set ts=4: vim:set shiftwidth=4: */ dotconf-1.4.1/examples/simple/simple.conf000066400000000000000000000001501460526106700204230ustar00rootroot00000000000000ExampleList '"line1'\ line2skdfj ExampleStr <, * and others. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ /* -- dotconf.c - this code is responsible for the input, parsing and dispatching of options */ #include #include #include /* Added by Stephen W. Boyer * for wildcard support in Include file paths */ #include #include #include #include /* -- AIX 4.3 compile time fix * by Eduardo Marcel Macan * * modified by Stephen W. Boyer * for Unixware and OpenServer */ #if defined (_AIX43) || defined(UNIXWARE) || defined(OSR5) #include #endif #include #include #include #ifndef WIN32 #include #include #else /* ndef WIN32 */ #include "readdir.h" /* WIN32 fix by Robert J. Buck */ #define strncasecmp strnicmp typedef unsigned long ulong; #define snprintf _snprintf #define vsnprintf _vsnprintf #endif /* !WIN32 */ #include #include "dotconf.h" #include "dotconf_priv.h" #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif static char name[CFG_MAX_OPTION + 1]; /* option name */ /* * some 'magic' options that are predefined by dot.conf itself for * advanced functionality */ static DOTCONF_CB(dotconf_cb_include); /* internal 'Include' */ static DOTCONF_CB(dotconf_cb_includepath); /* internal 'IncludePath' */ static configoption_t dotconf_options[] = { {"Include", ARG_STR, dotconf_cb_include, NULL, CTX_ALL}, {"IncludePath", ARG_STR, dotconf_cb_includepath, NULL, CTX_ALL}, LAST_CONTEXT_OPTION }; static void skip_whitespace(signed char **cp, int n, char term) { signed char *cp1 = *cp; while (isspace((int)*cp1) && *cp1 != term && n--) cp1++; *cp = cp1; } static void copy_word(signed char **dest, signed char **src, int max, char term) { signed char *cp1 = *src; signed char *cp2 = *dest; while (max-- && !isspace((int)*cp1) && *cp1 != term) *cp2++ = *cp1++; *cp2 = 0; *src = cp1; *dest = cp2; } static const configoption_t *get_argname_fallback(const configoption_t * options) { int i; for (i = 0; (options[i].name && options[i].name[0]); i++) ; if (options[i].type == ARG_NAME && options[i].callback) return &options[i]; return NULL; } char *dotconf_substitute_env(configfile_t * configfile, char *str) { char *cp1, *cp2, *cp3, *eos, *eob; char *env_value; char env_name[CFG_MAX_VALUE + 1]; char env_default[CFG_MAX_VALUE + 1]; char tmp_value[CFG_MAX_VALUE + 1]; memset(env_name, 0, CFG_MAX_VALUE + 1); memset(env_default, 0, CFG_MAX_VALUE + 1); memset(tmp_value, 0, CFG_MAX_VALUE + 1); cp1 = str; eob = cp1 + strlen(str) + 1; cp2 = tmp_value; eos = cp2 + CFG_MAX_VALUE + 1; while ((cp1 < eob) && (cp2 < eos) && (*cp1 != '\0')) { /* substitution needed ?? */ if (*cp1 == '$' && *(cp1 + 1) == '{') { cp1 += 2; /* skip ${ */ cp3 = env_name; while ((cp1 < eob) && !(*cp1 == '}' || *cp1 == ':')) *cp3++ = *cp1++; *cp3 = '\0'; /* terminate */ /* default substitution */ if (*cp1 == ':' && *(cp1 + 1) == '-') { cp1 += 2; /* skip :- */ cp3 = env_default; while ((cp1 < eob) && (*cp1 != '}')) *cp3++ = *cp1++; *cp3 = '\0'; /* terminate */ } else { while ((cp1 < eob) && (*cp1 != '}')) cp1++; } if (*cp1 != '}') { dotconf_warning(configfile, DCLOG_WARNING, ERR_PARSE_ERROR, "Unbalanced '{'"); } else { cp1++; /* skip } */ if ((env_value = getenv(env_name)) != NULL) { strncat(cp2, env_value, eos - cp2); cp2 += strlen(env_value); } else { strncat(cp2, env_default, eos - cp2); cp2 += strlen(env_default); } } } *cp2++ = *cp1++; } *cp2 = '\0'; /* terminate buffer */ free(str); return strdup(tmp_value); } int dotconf_warning(configfile_t * configfile, int type, unsigned long errnum, const char *fmt, ...) { va_list args; int retval = 0; va_start(args, fmt); if (configfile->errorhandler != 0) { /* an errorhandler is registered */ char msg[CFG_BUFSIZE]; vsnprintf(msg, CFG_BUFSIZE, fmt, args); retval = configfile->errorhandler(configfile, type, errnum, msg); } else { /* no errorhandler, do-it-yourself */ retval = 0; fprintf(stderr, "%s:%ld: ", configfile->filename, configfile->line); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } va_end(args); return retval; } int dotconf_register_options(configfile_t * configfile, const configoption_t * options) { int num = configfile->config_option_count; int ret = 0; configoption_t const **temp = configfile->config_options; #define GROW_BY 10 /* resize memoryblock for options blockwise */ if (temp == NULL) temp = malloc(sizeof(configoption_t *) * (GROW_BY + 1)); else { if (!(num % GROW_BY)) temp = realloc(temp, sizeof(configoption_t *) * (num + GROW_BY + 1)); } #undef GROW_BY if (temp != NULL) { /* Allocation or reallocation was successful. */ /* append new options */ temp[configfile->config_option_count] = options; configfile->config_options = temp; configfile->config_options[++configfile->config_option_count] = 0; ret = 1; } return ret; } void dotconf_callback(configfile_t * configfile, callback_types type, dotconf_callback_t callback) { switch (type) { case ERROR_HANDLER: configfile->errorhandler = (dotconf_errorhandler_t) callback; break; case CONTEXT_CHECKER: configfile->contextchecker = (dotconf_contextchecker_t) callback; break; default: break; } } int dotconf_continue_line(char *buffer, size_t length) { /* ------ match [^\\]\\[\r]\n ------------------------------ */ char *cp1 = buffer + length - 1; int backtrack = 0; if (length == 0) /* empty line */ return 0; if (*cp1-- != '\n') /* terminates, no newline */ return 0; backtrack++; if (cp1 < buffer) /* just newline */ return 0; if (*cp1 == '\r') { cp1--; backtrack++; } if (cp1 < buffer) /* just carriage return + newline */ return 0; if (*cp1-- != '\\') return 0; backtrack++; if (cp1 < buffer || *cp1 != '\\') /* maybe empty line with just escape */ return backtrack; return 0; } int dotconf_get_next_line(char *buffer, size_t bufsize, configfile_t * configfile) { char *cp1; int length, backtrack; if (configfile->eof) return 1; cp1 = fgets(buffer, bufsize, configfile->stream); if (!cp1) { configfile->eof = 1; return 1; } configfile->line++; length = strlen(cp1); while (length < (bufsize - 1) && (backtrack = dotconf_continue_line(buffer, length))) { length -= backtrack; cp1 = fgets(buffer + length, bufsize - length, configfile->stream); if (!cp1) { fprintf(stderr, "[dotconf] Parse error. Unexpected end of file at " "line %ld in file %s\n", configfile->line, configfile->filename); configfile->eof = 1; return 1; } configfile->line++; length += strlen(cp1); } return 0; } char *dotconf_get_here_document(configfile_t * configfile, const char *delimit) { /* it's a here-document: yeah, what a cool feature ;) */ unsigned int limit_len; char here_string; char buffer[CFG_BUFSIZE]; char *here_doc = 0; char here_limit[9]; /* max length for here-document delimiter: 8 */ struct stat finfo; int offset = 0; if (configfile->size <= 0) { if (stat(configfile->filename, &finfo)) { dotconf_warning(configfile, DCLOG_EMERG, ERR_NOACCESS, "[emerg] could not stat currently read file (%s)\n", configfile->filename); return NULL; } configfile->size = finfo.st_size; } /* * allocate a buffer of filesize bytes; should be enough to * prevent buffer overflows */ here_doc = malloc(configfile->size); /* allocate buffer memory */ memset(here_doc, 0, configfile->size); here_string = 1; limit_len = snprintf(here_limit, 9, "%s", delimit); while (!dotconf_get_next_line(buffer, CFG_BUFSIZE, configfile)) { if (!strncmp(here_limit, buffer, limit_len - 1)) { here_string = 0; break; } offset += snprintf((here_doc + offset), configfile->size - offset - 1, "%s", buffer); } if (here_string) dotconf_warning(configfile, DCLOG_WARNING, ERR_PARSE_ERROR, "Unterminated here-document!"); here_doc[offset - 1] = '\0'; /* strip newline */ return (char *)realloc(here_doc, offset); } const char *dotconf_invoke_command(configfile_t * configfile, command_t * cmd) { const char *error = 0; error = cmd->option->callback(cmd, configfile->context); return error; } char *dotconf_read_arg(configfile_t * configfile, signed char **line) { int sq = 0, dq = 0; /* single quote, double quote */ int done; signed char *cp1 = *line; char *cp2, *eos; char buf[CFG_MAX_VALUE]; memset(buf, 0, CFG_MAX_VALUE); done = 0; cp2 = buf; eos = cp2 + CFG_MAX_VALUE - 1; if (*cp1 == '#' || !*cp1) return NULL; skip_whitespace(&cp1, CFG_MAX_VALUE, 0); while ((*cp1 != '\0') && (cp2 != eos) && !done) { switch (*cp1) { case '\'': /* single quote */ if (dq) break; /* already double quoting, break out */ if (sq) sq--; /* already single quoting, clear state */ else if (!sq) sq++; /* set state for single quoting */ break; case '"': /* double quote */ if (sq) break; /* already single quoting, break out */ if (dq) dq--; /* already double quoting, clear state */ else if (!dq) dq++; /* set state for double quoting */ break; case '\\': /* protected chars */ if (!cp1[1]) /* dont protect NUL */ break; *cp2++ = *(++cp1); cp1++; /* skip the protected one */ continue; break; default: break; } /* unquoted space: start a new option argument */ if (isspace((int)*cp1) && !dq && !sq) { *cp2 = '\0'; break; } /* unquoted, unescaped comment-hash ; break out, unless NO_INLINE_COMMENTS is set */ else if (*cp1 == '#' && !dq && !sq && !(configfile->flags & NO_INLINE_COMMENTS)) { /* * NOTE: 1.0.8a got the NO_INLINE_COMMENTS feature wrong: it * skipped every argument starting with a #, instead of simply eating it! */ *cp2 = 0; *cp1 = 0; *line = cp1; return NULL; } /* not space or quoted: eat it; dont take quote if quoting */ else if ((!isspace((int)*cp1) && !dq && !sq && *cp1 != '"' && *cp1 != '\'') || (dq && (*cp1 != '"')) || (sq && *cp1 != '\'')) { *cp2++ = *cp1; } cp1++; } *line = cp1; /* FIXME: escaping substitutes does not work Subst ${HOME} \$\{HOME\} BOTH! will be substituted, which is somewhat wrong, ain't it ?? :-( */ if ((configfile->flags & DONT_SUBSTITUTE) == DONT_SUBSTITUTE) return buf[0] ? strdup(buf) : NULL; return buf[0] ? dotconf_substitute_env(configfile, strdup(buf)) : NULL; } /* dotconf_find_command remains here for backwards compatability. it's * internally unused since dot.conf 1.0.9 because it cannot handle the * DUPLICATE_OPTION_NAMES flag */ configoption_t *dotconf_find_command(configfile_t * configfile, const char *command) { configoption_t *option; int i = 0, mod = 0, done = 0; for (option = 0, mod = 0; configfile->config_options[mod] && !done; mod++) for (i = 0; configfile->config_options[mod][i].name[0]; i++) { if (!configfile->cmp_func(name, configfile-> config_options[mod][i].name, CFG_MAX_OPTION)) { option = (configoption_t *) & configfile-> config_options[mod][i]; /* TODO: this could be flagged: option overwriting by modules */ done = 1; break; /* found it; break out */ } } /* handle ARG_NAME fallback */ if ((option && option->name[0] == 0) || configfile->config_options[mod - 1][i].type == ARG_NAME) { option = (configoption_t *) & configfile->config_options[mod - 1][i]; } return option; } void dotconf_set_command(configfile_t * configfile, const configoption_t * option, signed char *args, command_t * cmd) { signed char *eob = args + strlen(args); /* fill in the command_t structure with values we already know */ cmd->name = option->type == ARG_NAME ? name : option->name; cmd->option = (configoption_t *) option; cmd->context = configfile->context; cmd->configfile = configfile; cmd->data.list = (char **)calloc(CFG_VALUES, sizeof(char *)); cmd->data.str = 0; if (option->type == ARG_RAW) { /* if it is an ARG_RAW type, save some time and call the callback now */ cmd->data.str = strdup(args); } else if (option->type == ARG_STR) { signed char *cp = args; /* check if it's a here-document and act accordingly */ skip_whitespace(&cp, eob - cp, 0); if (!strncmp("<<", cp, 2)) { cmd->data.str = dotconf_get_here_document(configfile, cp + 2); cmd->arg_count = 1; } } if (!(option->type == ARG_STR && cmd->data.str != 0)) { /* we only get here for non-heredocument lines */ skip_whitespace(&args, eob - args, 0); cmd->arg_count = 0; while (cmd->arg_count < (CFG_VALUES - 1) && (cmd->data.list[cmd->arg_count] = dotconf_read_arg(configfile, &args))) { cmd->arg_count++; } skip_whitespace(&args, eob - args, 0); if (cmd->arg_count && cmd->data.list[cmd->arg_count - 1] && *args) cmd->data.list[cmd->arg_count++] = strdup(args); /* has an option entry been found before or do we have to use a fallback? */ if ((option->name && option->name[0] > 32) || option->type == ARG_NAME) { /* found it, now check the type of args it wants */ switch (option->type) { case ARG_TOGGLE: /* the value is true if the argument is Yes, On or 1 */ if (cmd->arg_count < 1) { dotconf_warning(configfile, DCLOG_WARNING, ERR_WRONG_ARG_COUNT, "Missing argument to option '%s'", name); return; } cmd->data.value = CFG_TOGGLED(cmd->data.list[0]); break; case ARG_INT: if (cmd->arg_count < 1) { dotconf_warning(configfile, DCLOG_WARNING, ERR_WRONG_ARG_COUNT, "Missing argument to option '%s'", name); return; } sscanf(cmd->data.list[0], "%li", &cmd->data.value); break; case ARG_DOUBLE: if (cmd->arg_count < 1) { dotconf_warning(configfile, DCLOG_WARNING, ERR_WRONG_ARG_COUNT, "Missing argument to option '%s'", name); return; } cmd->data.dvalue = strtod(cmd->data.list[0], 0); break; case ARG_STR: if (cmd->arg_count < 1) { dotconf_warning(configfile, DCLOG_WARNING, ERR_WRONG_ARG_COUNT, "Missing argument to option '%s'", name); return; } cmd->data.str = strdup(cmd->data.list[0]); break; case ARG_NAME: /* fall through */ case ARG_LIST: case ARG_NONE: case ARG_RAW: /* this has been handled before */ default: break; } } } } void dotconf_free_command(command_t * command) { int i; if (command->data.str) free(command->data.str); for (i = 0; i < command->arg_count; i++) free(command->data.list[i]); free(command->data.list); } const char *dotconf_handle_command(configfile_t * configfile, char *buffer) { signed char *cp1; signed char *cp2; /* generic char pointer */ signed char *eob; /* end of buffer; end of string */ const char *error; /* error message we'll return */ const char *context_error; /* error message returned by contextchecker */ command_t command; /* command structure */ int mod = 0; int next_opt_idx = 0; memset(&command, 0, sizeof(command_t)); name[0] = 0; error = 0; context_error = 0; cp1 = buffer; eob = cp1 + strlen(cp1); skip_whitespace(&cp1, eob - cp1, 0); /* ignore comments and empty lines */ if (!cp1 || !*cp1 || *cp1 == '#' || *cp1 == '\n' || *cp1 == EOF) return NULL; /* skip line if it only contains whitespace */ if (cp1 == eob) return NULL; /* get first token: read the name of a possible option */ cp2 = name; copy_word(&cp2, &cp1, MIN(eob - cp1, CFG_MAX_OPTION), 0); while (1) { const configoption_t *option; int done = 0; int opt_idx = 0; for (option = 0; configfile->config_options[mod] && !done; mod++) { for (opt_idx = next_opt_idx; configfile->config_options[mod][opt_idx].name[0]; opt_idx++) { if (!configfile-> cmp_func(name, configfile-> config_options[mod][opt_idx].name, CFG_MAX_OPTION)) { /* TODO: this could be flagged: option overwriting by modules */ option = (configoption_t *) & configfile-> config_options[mod][opt_idx]; done = 1; break; /* found one; break out */ } } } if (!option) option = get_argname_fallback(configfile->config_options[1]); if (!option || !option->callback) { if (error) return error; dotconf_warning(configfile, DCLOG_INFO, ERR_UNKNOWN_OPTION, "Unknown Config-Option: '%s'", name); return NULL; } /* set up the command structure (contextchecker wants this) */ dotconf_set_command(configfile, option, cp1, &command); if (configfile->contextchecker) context_error = configfile->contextchecker(&command, command.option->context); if (!context_error) error = dotconf_invoke_command(configfile, &command); else { if (!error) { /* avoid returning another error then the first. This makes it easier to reproduce problems. */ error = context_error; } } dotconf_free_command(&command); if (!context_error || !(configfile->flags & DUPLICATE_OPTION_NAMES)) { /* don't try more, just quit now. */ break; } } return error; } const char *dotconf_command_loop_until_error(configfile_t * configfile) { char buffer[CFG_BUFSIZE]; while (!(dotconf_get_next_line(buffer, CFG_BUFSIZE, configfile))) { const char *error = dotconf_handle_command(configfile, buffer); if (error) return error; } return NULL; } int dotconf_command_loop(configfile_t * configfile) { /* ------ returns: 0 for failure -- !0 for success ------------------------------------------ */ char buffer[CFG_BUFSIZE]; while (!(dotconf_get_next_line(buffer, CFG_BUFSIZE, configfile))) { const char *error = dotconf_handle_command(configfile, buffer); if (error != NULL) { if (dotconf_warning(configfile, DCLOG_ERR, 0, error)) return 0; } } return 1; } void dotconf_cleanup(configfile_t * configfile) { if (configfile->stream) fclose(configfile->stream); if (configfile->filename) free(configfile->filename); if (configfile->config_options) free(configfile->config_options); if (configfile->includepath) free(configfile->includepath); free(configfile); } configfile_t *dotconf_create(char *fname, const configoption_t * options, context_t * context, unsigned long flags) { char *dc_env = NULL; int registered = 0; configfile_t *new_cfg = calloc(1, sizeof(configfile_t)); char *path = NULL; char *cwd = NULL; if (!new_cfg) return NULL; /* * From here on, we can use dotconf_cleanup to free resources * when errors occur. All of our pointers are NULL, because * we allocated with calloc. When an error occurs, dotconf_cleanup * will free all of the resources that were allocated prior to the * error. */ new_cfg->context = context; new_cfg->flags = flags; if (new_cfg->flags & CASE_INSENSITIVE) new_cfg->cmp_func = strncasecmp; else new_cfg->cmp_func = strncmp; new_cfg->stream = fopen(fname, "r"); if (new_cfg->stream == NULL) { fprintf(stderr, "Error opening configuration file '%s'\n", fname); dotconf_cleanup(new_cfg); return NULL; } registered = dotconf_register_options(new_cfg, dotconf_options); if (!registered) { dotconf_cleanup(new_cfg); return NULL; } registered = dotconf_register_options(new_cfg, options); if (!registered) { dotconf_cleanup(new_cfg); return NULL; } new_cfg->filename = strdup(fname); if (!new_cfg->filename) { dotconf_cleanup(new_cfg); return NULL; } new_cfg->includepath = malloc(CFG_MAX_FILENAME); if (!new_cfg->includepath) { dotconf_cleanup(new_cfg); return NULL; } new_cfg->includepath[0] = 0x00; /* * take default includepath from environment if present * Otherwise, resolve the path of the configuration file and use that * as default includepath. */ dc_env = getenv(CFG_INCLUDEPATH_ENV); if (dc_env != NULL) { snprintf(new_cfg->includepath, CFG_MAX_FILENAME, "%s", dc_env); } else { path = get_path(fname); if (path != NULL) { if (path[0] == '/') { snprintf(new_cfg->includepath, CFG_MAX_FILENAME, "%s", path); } else { cwd = get_cwd(); if (cwd != NULL) { snprintf(new_cfg->includepath, CFG_MAX_FILENAME, "%s/%s", cwd, path); free(cwd); } } free(path); } } return new_cfg; } /* ------ internal utility function that verifies if a character is in the WILDCARDS list -- */ int dotconf_is_wild_card(char value) { int retval = 0; int i; int wildcards_len = strlen(WILDCARDS); for (i = 0; i < wildcards_len; i++) { if (value == WILDCARDS[i]) { retval = 1; break; } } return retval; } /* ------ internal utility function that calls the appropriate routine for the wildcard passed in -- */ int dotconf_handle_wild_card(command_t * cmd, char wild_card, char *path, char *pre, char *ext) { int retval = 0; switch (wild_card) { case '*': retval = dotconf_handle_star(cmd, path, pre, ext); break; case '?': retval = dotconf_handle_question_mark(cmd, path, pre, ext); break; default: retval = -1; } return retval; } /* ------ internal utility function that frees allocated memory from dotcont_find_wild_card -- */ void dotconf_wild_card_cleanup(char *path, char *pre) { if (path != NULL) { free(path); } if (pre != NULL) { free(pre); } } /* ------ internal utility function to check for wild cards in file path -- */ /* ------ path and pre must be freed by the developer ( dotconf_wild_card_cleanup) -- */ int dotconf_find_wild_card(char *filename, char *wildcard, char **path, char **pre, char **ext) { int retval = -1; int prefix_len = 0; int tmp_count = 0; char *tmp = 0; int found_path = 0; int len = strlen(filename); if (wildcard != NULL && len > 0 && path != NULL && pre != NULL && ext != NULL) { prefix_len = strcspn(filename, WILDCARDS); /* find any wildcard in WILDCARDS */ if (prefix_len < len) { /* Wild card found */ tmp = filename + prefix_len; tmp_count = prefix_len + 1; while (tmp != filename && *(tmp) != '/') { tmp--; tmp_count--; } if (*(tmp) == '/') { *path = (char *)malloc(tmp_count + 1); found_path = 1; } else *path = (char *)malloc(1); *pre = (char *) malloc((prefix_len - (tmp_count - (found_path ? 0 : 1))) + 1); if (*path && *pre) { if (found_path) strncpy(*path, filename, tmp_count); (*path)[tmp_count] = '\0'; strncpy(*pre, (tmp + (found_path ? 1 : 0)), (prefix_len - (tmp_count - (found_path ? 0 : 1)))); (*pre)[(prefix_len - (tmp_count - (found_path ? 0 : 1)))] = '\0'; *ext = filename + prefix_len; *wildcard = (**ext); (*ext)++; retval = prefix_len; } } } return retval; } /* ------ internal utility function that compares two stings from back to front -- */ int dotconf_strcmp_from_back(const char *s1, const char *s2) { int retval = 0; int i, j; int len_1 = strlen(s1); int len_2 = strlen(s2); for (i = len_1, j = len_2; (i >= 0 && j >= 0); i--, j--) { if (s1[i] != s2[j]) { retval = -1; break; } } return retval; } /* ------ internal utility function that determins if a string matches the '?' criteria -- */ int dotconf_question_mark_match(char *dir_name, char *pre, char *ext) { int retval = -1; int dir_name_len = strlen(dir_name); int pre_len = strlen(pre); int ext_len = strlen(ext); int w_card_check = strcspn(ext, WILDCARDS); if ((w_card_check < ext_len) && (strncmp(dir_name, pre, pre_len) == 0) && (strcmp(dir_name, ".") != 0) && (strcmp(dir_name, "..") != 0)) { retval = 1; /* Another wildcard found */ } else { if ((dir_name_len >= pre_len) && (strncmp(dir_name, pre, pre_len) == 0) && (strcmp(dir_name, ".") != 0) && (strcmp(dir_name, "..") != 0)) { retval = 0; /* Matches no other wildcards */ } } return retval; } /* ------ internal utility function that determins if a string matches the '*' criteria -- */ int dotconf_star_match(char *dir_name, char *pre, char *ext) { int retval = -1; int dir_name_len = strlen(dir_name); int pre_len = strlen(pre); int ext_len = strlen(ext); int w_card_check = strcspn(ext, WILDCARDS); if ((w_card_check < ext_len) && (strncmp(dir_name, pre, pre_len) == 0) && (strcmp(dir_name, ".") != 0) && (strcmp(dir_name, "..") != 0)) { retval = 1; /* Another wildcard found */ } else { if ((dir_name_len >= (ext_len + pre_len)) && (dotconf_strcmp_from_back(dir_name, ext) == 0) && (strncmp(dir_name, pre, pre_len) == 0) && (strcmp(dir_name, ".") != 0) && (strcmp(dir_name, "..") != 0)) { retval = 0; /* Matches no other wildcards */ } } return retval; } /* ------ internal utility function that determins matches for filenames with -- */ /* ------ a '?' in name and calls the Internal Include function on that filename -- */ int dotconf_handle_question_mark(command_t * cmd, char *path, char *pre, char *ext) { configfile_t *included; DIR *dh = 0; struct dirent *dirptr = 0; int i; char new_pre[CFG_MAX_FILENAME]; char already_matched[CFG_MAX_FILENAME]; char wc = '\0'; char *new_path = 0; char *wc_path = 0; char *wc_pre = 0; char *wc_ext = 0; char *temp = NULL; int pre_len; int new_path_len; int name_len = 0; int alloced = 0; int match_state = 0; pre_len = strlen(pre); if ((dh = opendir(path)) != NULL) { while ((dirptr = readdir(dh)) != NULL) { match_state = dotconf_question_mark_match(dirptr->d_name, pre, ext); if (match_state >= 0) { name_len = strlen(dirptr->d_name); new_path_len = strlen(path) + name_len + strlen(ext) + 1; if (!alloced) { if ((new_path = (char *)malloc(new_path_len)) == NULL) { return -1; } alloced = new_path_len; } else { if (new_path_len > alloced) { temp = realloc(new_path, new_path_len); if (temp == NULL) { free(new_path); return -1; } new_path = temp; alloced = new_path_len; } } if (match_state == 1) { strncpy(new_pre, dirptr->d_name, (name_len > pre_len) ? (pre_len + 1) : pre_len); new_pre[(name_len > pre_len) ? (pre_len + 1) : pre_len] = '\0'; sprintf(new_path, "%s%s%s", path, new_pre, ext); if (strcmp(new_path, already_matched) == 0) { continue; /* Already searched this expression */ } else { strcpy(already_matched, new_path); } if (dotconf_find_wild_card (new_path, &wc, &wc_path, &wc_pre, &wc_ext) >= 0) { if (dotconf_handle_wild_card (cmd, wc, wc_path, wc_pre, wc_ext) < 0) { dotconf_warning(cmd-> configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Error occured while processing wildcard %c\n" "Filename is '%s'\n", wc, new_path); free(new_path); dotconf_wild_card_cleanup (wc_path, wc_pre); return -1; } dotconf_wild_card_cleanup (wc_path, wc_pre); continue; } } sprintf(new_path, "%s%s", path, dirptr->d_name); if (access(new_path, R_OK)) { dotconf_warning(cmd->configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Cannot open %s for inclusion.\n" "IncludePath is '%s'\n", new_path, cmd->configfile-> includepath); return -1; } included = dotconf_create(new_path, cmd->configfile-> config_options[1], cmd->configfile->context, cmd->configfile->flags); if (included) { for (i = 2; cmd->configfile->config_options[i]; i++) dotconf_register_options (included, cmd->configfile-> config_options[i]); included->errorhandler = cmd->configfile->errorhandler; included->contextchecker = cmd->configfile->contextchecker; dotconf_command_loop(included); dotconf_cleanup(included); } } } closedir(dh); free(new_path); } return 0; } /* ------ internal utility function that determins matches for filenames with --- */ /* ------ a '*' in name and calls the Internal Include function on that filename -- */ int dotconf_handle_star(command_t * cmd, char *path, char *pre, char *ext) { configfile_t *included; DIR *dh = 0; struct dirent *dirptr = 0; char new_pre[CFG_MAX_FILENAME]; char new_ext[CFG_MAX_FILENAME]; char already_matched[CFG_MAX_FILENAME]; char wc = '\0'; char *new_path = 0; char *s_ext = 0; char *t_ext = 0; char *sub = 0; char *wc_path = 0; char *wc_pre = 0; char *wc_ext = 0; char *temp = NULL; int pre_len; int new_path_len; int name_len = 0; int alloced = 0; int match_state = 0; int t_ext_count = 0; int sub_count = 0; pre_len = strlen(pre); memset(already_matched, 0, CFG_MAX_FILENAME); s_ext = ext; while (dotconf_is_wild_card(*s_ext)) { /* remove trailing wild-cards proceeded by * */ s_ext++; } t_ext = s_ext; while (t_ext != NULL && !(dotconf_is_wild_card(*t_ext)) && *t_ext != '\0') { t_ext++; /* find non-wild-card string */ t_ext_count++; } strncpy(new_ext, s_ext, t_ext_count); new_ext[t_ext_count] = '\0'; if ((dh = opendir(path)) != NULL) { while ((dirptr = readdir(dh)) != NULL) { sub_count = 0; t_ext_count = 0; match_state = dotconf_star_match(dirptr->d_name, pre, s_ext); if (match_state >= 0) { name_len = strlen(dirptr->d_name); new_path_len = strlen(path) + name_len + strlen(s_ext) + 1; if (!alloced) { if ((new_path = (char *)malloc(new_path_len)) == NULL) { return -1; } alloced = new_path_len; } else { if (new_path_len > alloced) { temp = realloc(new_path, new_path_len); if (temp == NULL) { free(new_path); return -1; } new_path = temp; alloced = new_path_len; } } if (match_state == 1) { if ((sub = strstr((dirptr->d_name + pre_len), new_ext)) == NULL) { continue; } while (sub != dirptr->d_name) { sub--; sub_count++; } if (sub_count + t_ext_count > name_len) { continue; } strncpy(new_pre, dirptr->d_name, (sub_count + t_ext_count)); new_pre[sub_count + t_ext_count] = '\0'; strcat(new_pre, new_ext); sprintf(new_path, "%s%s%s", path, new_pre, t_ext); if (strcmp(new_path, already_matched) == 0) { continue; /* Already searched this expression */ } else { strcpy(already_matched, new_path); } if (dotconf_find_wild_card (new_path, &wc, &wc_path, &wc_pre, &wc_ext) >= 0) { if (dotconf_handle_wild_card (cmd, wc, wc_path, wc_pre, wc_ext) < 0) { dotconf_warning(cmd-> configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Error occured while processing wildcard %c\n" "Filename is '%s'\n", wc, new_path); free(new_path); dotconf_wild_card_cleanup (wc_path, wc_pre); return -1; } dotconf_wild_card_cleanup (wc_path, wc_pre); continue; } } sprintf(new_path, "%s%s", path, dirptr->d_name); if (access(new_path, R_OK)) { dotconf_warning(cmd->configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Cannot open %s for inclusion.\n" "IncludePath is '%s'\n", new_path, cmd->configfile-> includepath); return -1; } included = dotconf_create(new_path, cmd->configfile-> config_options[1], cmd->configfile->context, cmd->configfile->flags); if (included) { included->errorhandler = cmd->configfile->errorhandler; included->contextchecker = cmd->configfile->contextchecker; dotconf_command_loop(included); dotconf_cleanup(included); } } } closedir(dh); free(new_path); } return 0; } char *get_cwd(void) { char *buf = calloc(1, CFG_MAX_FILENAME); if (buf == NULL) return NULL; getcwd(buf, CFG_MAX_FILENAME); return buf; } char *get_path(char *name) { char *tmp; char *buf = NULL; int len = 0; tmp = strrchr(name, '/'); if (tmp == NULL) return NULL; buf = calloc(1, CFG_MAX_FILENAME); if (buf == NULL) return NULL; if (tmp == name) { sprintf(buf, "/"); } else { len = tmp - name + 1; if (len > CFG_MAX_FILENAME) len = CFG_MAX_FILENAME; } snprintf(buf, len, "%s", name); return buf; } /* ------ callbacks of the internal option (Include, IncludePath) ------------------------------- */ DOTCONF_CB(dotconf_cb_include) { char *filename = 0; configfile_t *included; char wild_card; char *path = 0; char *pre = 0; char *ext = 0; if (cmd->configfile->includepath && cmd->data.str[0] != '/' && cmd->configfile->includepath[0] != '\0') { /* relative file AND include path is used */ int len, inclen; char *sl; inclen = strlen(cmd->configfile->includepath); if ((len = (strlen(cmd->data.str) + inclen + 1)) == CFG_MAX_FILENAME) { dotconf_warning(cmd->configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Absolute filename too long (>%d)", CFG_MAX_FILENAME); return NULL; } if (cmd->configfile->includepath[inclen - 1] == '/') sl = ""; else { sl = "/"; len++; } filename = malloc(len); snprintf(filename, len, "%s%s%s", cmd->configfile->includepath, sl, cmd->data.str); } else /* fully qualified, or no includepath */ filename = strdup(cmd->data.str); /* Added wild card support here */ if (dotconf_find_wild_card(filename, &wild_card, &path, &pre, &ext) >= 0) { if (dotconf_handle_wild_card(cmd, wild_card, path, pre, ext) < 0) { dotconf_warning(cmd->configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Error occured while attempting to process %s for inclusion.\n" "IncludePath is '%s'\n", filename, cmd->configfile->includepath); } dotconf_wild_card_cleanup(path, pre); free(filename); return NULL; } if (access(filename, R_OK)) { dotconf_warning(cmd->configfile, DCLOG_WARNING, ERR_INCLUDE_ERROR, "Cannot open %s for inclusion.\n" "IncludePath is '%s'\n", filename, cmd->configfile->includepath); free(filename); return NULL; } included = dotconf_create(filename, cmd->configfile->config_options[1], cmd->configfile->context, cmd->configfile->flags); if (included) { included->contextchecker = (dotconf_contextchecker_t) cmd->configfile->contextchecker; included->errorhandler = (dotconf_errorhandler_t) cmd->configfile->errorhandler; dotconf_command_loop(included); dotconf_cleanup(included); } free(filename); return NULL; } DOTCONF_CB(dotconf_cb_includepath) { char *env = getenv(CFG_INCLUDEPATH_ENV); /* environment overrides configuration file setting */ if (!env) snprintf(cmd->configfile->includepath, CFG_MAX_FILENAME, "%s", cmd->data.str); return NULL; } dotconf-1.4.1/src/dotconf.h000066400000000000000000000230021460526106700155510ustar00rootroot00000000000000#ifndef DOTCONF_H #define DOTCONF_H #ifdef __cplusplus extern "C" { #endif /* stdio.h should be included by the application - as the manual page says */ #ifndef _STDIO_H #include /* needed for FILE* */ #endif #ifdef WIN32 # ifndef R_OK #define R_OK 0 # endif #endif /* some buffersize definitions */ #define CFG_BUFSIZE 4096 /* max length of one line */ #define CFG_MAX_OPTION 32 /* max length of any option name */ #define CFG_MAX_VALUE 4064 /* max length of any options value */ #define CFG_MAX_FILENAME 256 /* max length of a filename */ #define CFG_VALUES 16 /* max # of arguments an option takes */ #define CFG_INCLUDEPATH_ENV "DC_INCLUDEPATH" #define WILDCARDS "*?" /* list of supported wild-card characters */ /* constants for type of option */ #define ARG_TOGGLE 0 /* TOGGLE on,off; yes,no; 1, 0; */ #define ARG_INT 1 /* callback wants an integer */ #define ARG_DOUBLE 7 /* callback wants a float / double */ #define ARG_STR 2 /* callback expects a \0 terminated str */ #define ARG_LIST 3 /* wants list of strings */ #define ARG_NAME 4 /* wants option name plus ARG_LIST stuff */ #define ARG_RAW 5 /* wants raw argument data */ #define ARG_NONE 6 /* does not expect ANY args */ #define CTX_ALL 0 /* context: option can be used anywhere */ /* for convenience of terminating the dotconf_options list */ #define LAST_OPTION { "", 0, NULL, NULL } #define LAST_CONTEXT_OPTION { "", 0, NULL, NULL, 0 } #define DOTCONF_CB(__name) const char *__name(command_t *cmd, \ context_t *ctx) #define FUNC_ERRORHANDLER(_name) int _name(configfile_t * configfile, \ int type, long dc_errno, const char *msg) /* some flags that change the runtime behaviour of dotconf */ #define NONE 0 #define CASE_INSENSITIVE 1<<0 /* match option names case insensitive */ #define DONT_SUBSTITUTE 1<<1 /* do not call substitute_env after read_arg */ #define NO_INLINE_COMMENTS 1<<2 /* do not allow inline comments */ #define DUPLICATE_OPTION_NAMES 1<<3 /* allow for duplicate option names */ /* syslog style errors as suggested by Sander Steffann */ #ifdef HAVE_SYSLOG #include #define DCLOG_EMERG LOG_EMERG /* system is unusable */ #define DCLOG_ALERT LOG_ALERT /* action must be taken immediately */ #define DCLOG_CRIT LOG_CRIT /* critical conditions */ #define DCLOG_ERR LOG_ERR /* error conditions */ #define DCLOG_WARNING LOG_WARNING /* warning conditions */ #define DCLOG_NOTICE LOG_NOTICE /* normal but significant condition */ #define DCLOG_INFO LOG_INFO /* informational */ #define DCLOG_DEBUG LOG_DEBUG /* debug-level messages */ #define DCLOG_LEVELMASK LOG_PRIMASK /* mask off the level value */ #else /* HAVE_SYSLOG */ #define DCLOG_EMERG 0 /* system is unusable */ #define DCLOG_ALERT 1 /* action must be taken immediately */ #define DCLOG_CRIT 2 /* critical conditions */ #define DCLOG_ERR 3 /* error conditions */ #define DCLOG_WARNING 4 /* warning conditions */ #define DCLOG_NOTICE 5 /* normal but significant condition */ #define DCLOG_INFO 6 /* informational */ #define DCLOG_DEBUG 7 /* debug-level messages */ #define DCLOG_LEVELMASK 7 /* mask off the level value */ #endif /* HAVE_SYSLOG */ /* callback types for dotconf_callback */ /* error constants */ #define ERR_NOERROR 0x0000 #define ERR_PARSE_ERROR 0x0001 #define ERR_UNKNOWN_OPTION 0x0002 #define ERR_WRONG_ARG_COUNT 0x0003 #define ERR_INCLUDE_ERROR 0x0004 #define ERR_NOACCESS 0x0005 #define ERR_USER 0x1000 /* base for userdefined errno's */ /* i needed this to check an ARG_LIST entry if it's toggled in one of my apps; maybe you do too */ #define CFG_TOGGLED(_val) ( (_val[0] == 'Y' \ || _val[0] == 'y') \ || (_val[0] == '1') \ || ((_val[0] == 'o' \ || _val[0] == 'O') \ && (_val[1] == 'n' \ || _val[1] == 'N'))) enum callback_types { ERROR_HANDLER = 1, CONTEXT_CHECKER }; typedef enum callback_types callback_types; typedef struct configfile_t configfile_t; typedef struct configoption_t configoption_t; typedef struct configoption_t ConfigOption; typedef struct command_t command_t; typedef void context_t; typedef void info_t; typedef const char *(*dotconf_callback_t) (command_t *, context_t *); typedef int (*dotconf_errorhandler_t) (configfile_t *, int, unsigned long, const char *); typedef const char *(*dotconf_contextchecker_t) (command_t *, unsigned long); struct configfile_t { /* ------ the fields in configfile_t are provided to the app via command_t's ; READ ONLY! --- */ FILE *stream; char eof; /* end of file reached ? */ size_t size; /* file size; cached on-demand for here-documents */ context_t *context; configoption_t const **config_options; int config_option_count; /* ------ misc read-only fields ------------------------------------------------------------- */ char *filename; /* name of file this option was found in */ unsigned long line; /* line number we're currently at */ unsigned long flags; /* runtime flags given to dotconf_open */ char *includepath; /* ------ some callbacks for interactivity -------------------------------------------------- */ dotconf_errorhandler_t errorhandler; dotconf_contextchecker_t contextchecker; int (*cmp_func) (const char *, const char *, size_t); }; struct configoption_t { const char *name; /* name of configuration option */ int type; /* for possible values, see above */ dotconf_callback_t callback; /* callback function */ info_t *info; /* additional info for multi-option callbacks */ unsigned long context; /* context sensitivity flags */ }; struct command_t { const char *name; /* name of the command */ configoption_t *option; /* the option as given in the app; READ ONLY */ /* ------ misc context information ---------------------------------------------------------- */ configfile_t *configfile; context_t *context; /* ------ argument data filled in for each line / command ----------------------------------- */ int arg_count; /* number of arguments (in data.list) */ struct { long value; /* ARG_INT, ARG_TOGGLE */ char *str; /* ARG_STR */ char **list; /* ARG_LIST */ double dvalue; /* ARG_DOUBLE */ } data; }; /* ------ dotconf_create() - create the configfile_t needed for further dot.conf fun ------------ */ configfile_t *dotconf_create(char *, const configoption_t *, context_t *, unsigned long); /* ------ dotconf_cleanup() - tidy up behind dotconf_create and the parser dust ----------------- */ void dotconf_cleanup(configfile_t * configfile); /* ------ dotconf_command_loop() - iterate through each line of file and handle the commands ---- */ int dotconf_command_loop(configfile_t * configfile); /* ------ dotconf_command_loop_until_error() - like continue_line but return on the first error - */ const char *dotconf_command_loop_until_error(configfile_t * configfile); /* ------ dotconf_continue_line() - check if line continuation is to be handled ----------------- */ int dotconf_continue_line(char *buffer, size_t length); /* ------ dotconf_get_next_line() - read in the next line of the configfile_t ------------------- */ int dotconf_get_next_line(char *buffer, size_t bufsize, configfile_t * configfile); /* ------ dotconf_get_here_document() - read the here document until delimit is found ----------- */ char *dotconf_get_here_document(configfile_t * configfile, const char *delimit); /* ------ dotconf_invoke_command() - call the callback for command_t ---------------------------- */ const char *dotconf_invoke_command(configfile_t * configfile, command_t * cmd); /* ------ dotconf_find_command() - iterate through all registered options trying to match ------- */ configoption_t *dotconf_find_command(configfile_t * configfile, const char *command); /* ------ dotconf_read_arg() - read one argument from the line handling quoting and escaping ---- */ /* side effects: the char* returned by dotconf_read_arg is malloc() before, hence that pointer will have to be free()ed later. */ char *dotconf_read_arg(configfile_t * configfile, signed char **line); /* ------ dotconf_handle_command() - parse, substitute, find, invoke the command found in buffer */ const char *dotconf_handle_command(configfile_t * configfile, char *buffer); /* ------ dotconf_register_option() - add a new option table to the list of commands ------------ */ int dotconf_register_options(configfile_t * configfile, const configoption_t * options); /* ------ dotconf_warning() - handle the dispatch of error messages of various levels ----------- */ int dotconf_warning(configfile_t * configfile, int level, unsigned long errnum, const char *, ...); /* ------ dotconf_callback() - register a special callback -------------------------------------- */ void dotconf_callback(configfile_t * configfile, callback_types type, dotconf_callback_t); /* ------ dotconf_substitute_env() - handle the substitution on environment variables ----------- */ char *dotconf_substitute_env(configfile_t *, char *); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* DOTCONF_H */ dotconf-1.4.1/src/dotconf_priv.h000066400000000000000000000027131460526106700166170ustar00rootroot00000000000000#ifndef DOTCONF_PRIV_H #define DOTCONF_PRIV_H /* verify whether or not a character is in the WILDCARDS list */ int dotconf_is_wild_card(char value); /* call the appropriate routine for the wildcard passed in */ int dotconf_handle_wild_card(command_t * cmd, char wild_card, char *path, char *pre, char *ext); /* free allocated memory from dotcont_find_wild_card */ void dotconf_wild_card_cleanup(char *path, char *pre); /* check for wild cards in file path */ /* path and pre must be freed by the developer ( dotconf_wild_card_cleanup) */ int dotconf_find_wild_card(char *filename, char *wildcard, char **path, char **pre, char **ext); /* compare two strings from back to front */ int dotconf_strcmp_from_back(const char *s1, const char *s2); /* determine if a string matches the '?' criteria */ int dotconf_question_mark_match(char *dir_name, char *pre, char *ext); /* determine if a string matches the '*' criteria */ int dotconf_star_match(char *dir_name, char *pre, char *ext); /* determine matches for filenames with a '?' in name and call */ /* the Internal Include function on that filename */ int dotconf_handle_question_mark(command_t * cmd, char *path, char *pre, char *ext); /* determine matches for filenames with a '*' in name and call */ /* the Internal Include function on that filename */ int dotconf_handle_star(command_t * cmd, char *path, char *pre, char *ext); char *get_cwd(void); char *get_path(char *name); #endif dotconf-1.4.1/src/readdir.c000066400000000000000000000111161460526106700155250ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR * ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. */ #ifdef WIN32 #include #include #include #include "readdir.h" /********************************************************************** * Implement dirent-style opendir/readdir/closedir on Window 95/NT * * Functions defined are opendir(), readdir() and closedir() with the * same prototypes as the normal dirent.h implementation. * * Does not implement telldir(), seekdir(), rewinddir() or scandir(). * The dirent struct is compatible with Unix, except that d_ino is * always 1 and d_off is made up as we go along. * * The DIR typedef is not compatible with Unix. **********************************************************************/ DIR * opendir(const char *dir) { DIR * dp; char *filespec; long handle; int index; filespec = malloc(strlen(dir) + 2 + 1); strcpy(filespec, dir); index = strlen(filespec) - 1; if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\')) filespec[index] = '\0'; strcat(filespec, "/*"); dp = (DIR *) malloc(sizeof(DIR)); dp->offset = 0; dp->finished = 0; dp->dir = strdup(dir); if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) { if (errno == ENOENT) dp->finished = 1; else return NULL; } dp->handle = handle; free(filespec); return dp; } struct dirent *readdir(DIR * dp) { if (!dp || dp->finished) return NULL; if (dp->offset != 0) { if (_findnext(dp->handle, &(dp->fileinfo)) < 0) { dp->finished = 1; return NULL; } } dp->offset++; strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME); dp->dent.d_ino = 1; dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name); dp->dent.d_off = dp->offset; return &(dp->dent); } int closedir(DIR * dp) { if (!dp) return 0; _findclose(dp->handle); if (dp->dir) free(dp->dir); if (dp) free(dp); return 0; } #endif /* WIN32 */ dotconf-1.4.1/src/readdir.h000066400000000000000000000074731460526106700155450ustar00rootroot00000000000000/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR * ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. */ /* * Structures and types used to implement opendir/readdir/closedir * on Windows 95/NT. */ #ifndef APACHE_READDIR_H #define APACHE_READDIR_H #ifdef WIN32 #include #include #include #include /* struct dirent - same as Unix */ struct dirent { long d_ino; /* inode (always 1 in WIN32) */ off_t d_off; /* offset to this dirent */ unsigned short d_reclen; /* length of d_name */ char d_name[_MAX_FNAME + 1]; /* filename (null terminated) */ }; /* typedef DIR - not the same as Unix */ typedef struct { long handle; /* _findfirst/_findnext handle */ short offset; /* offset into directory */ short finished; /* 1 if there are not more files */ struct _finddata_t fileinfo; /* from _findfirst/_findnext */ char *dir; /* the dir we are reading */ struct dirent dent; /* the dirent to return */ } DIR; /* Function prototypes */ DIR * opendir(const char *); struct dirent *readdir(DIR *); int closedir(DIR *); #endif /* WIN32 */ #endif /* ndef APACHE_READDIR_H */