mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-28 19:58:56 +03:00
Initial commit
This commit is contained in:
commit
1b29a420bc
102 changed files with 11603 additions and 0 deletions
1
AUTHORS
Normal file
1
AUTHORS
Normal file
|
@ -0,0 +1 @@
|
|||
Andreas Schneider <mail@cynapses.org>
|
43
CMakeLists.txt
Normal file
43
CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
project(csync)
|
||||
|
||||
# global needed variables
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
set(APPLICATION_VERSION "0.1")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_SOURCE_DIR}/cmake/Modules
|
||||
)
|
||||
|
||||
# add definitions
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
include(DefineInstallationPaths)
|
||||
|
||||
include(DefineOptions.cmake)
|
||||
|
||||
# add macros
|
||||
include(MacroAddPlugin)
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
include(MacroAddCheckTest)
|
||||
|
||||
if (WITH_LOG4C)
|
||||
find_package(LOG4C REQUIRED)
|
||||
endif (WITH_LOG4C)
|
||||
find_package(Check)
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
# disallow in-source build
|
||||
macro_ensure_out_of_source_build("libcsync requires an out of source build. Please create a separate build directory and run 'cmake path_to_wengophone [options]' there.")
|
||||
|
||||
add_subdirectory(iniparser/src)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(client)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(doc)
|
||||
if (CHECK_FOUND)
|
||||
add_subdirectory(tests)
|
||||
endif (CHECK_FOUND)
|
||||
|
8
CTestConfig.cmake
Normal file
8
CTestConfig.cmake
Normal file
|
@ -0,0 +1,8 @@
|
|||
SET (UPDATE_TYPE "true")
|
||||
set(CTEST_PROJECT_NAME "csync")
|
||||
set(CTEST_DROP_METHOD "xmlrpc" )
|
||||
set(CTEST_DROP_SITE "http://csync.org/")
|
||||
set(CTEST_DROP_LOCATION "csync")
|
||||
set(COMPRESS_SUBMISSON ON)
|
||||
#set (CTEST_TRIGGER_SITE "http://${CTEST_DROP_SITE}/cgi-bin/Submit-cSync-TestingResults.pl")
|
||||
|
13
ConfigureChecks.cmake
Normal file
13
ConfigureChecks.cmake
Normal file
|
@ -0,0 +1,13 @@
|
|||
include(CheckIncludeFile)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
set(PACKAGE ${APPLICATION_NAME})
|
||||
set(VERSION ${APPLICATION_VERSION})
|
||||
set(DATADIR ${DATA_INSTALL_DIR})
|
||||
set(LIBDIR ${LIB_INSTALL_DIR})
|
||||
set(PLUGINDIR ${PLUGIN_INSTALL_DIR})
|
||||
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
1
DefineOptions.cmake
Normal file
1
DefineOptions.cmake
Normal file
|
@ -0,0 +1 @@
|
|||
option(WITH_LOG4C "Build csync without log4c" ON)
|
80
INSTALL
Normal file
80
INSTALL
Normal file
|
@ -0,0 +1,80 @@
|
|||
# How to build from source
|
||||
|
||||
## Requirements
|
||||
|
||||
### Common requirements
|
||||
|
||||
In order to build csync, you need to install several components:
|
||||
|
||||
- A C++ compiler
|
||||
- [CMake](http://www.cmake.org/) >= 2.4.4.
|
||||
- [check](http://check.sourceforge.net)
|
||||
- [log4c](http://log4c.sourceforge.net)
|
||||
|
||||
- [libsmbclient](http://www.samba.org)
|
||||
|
||||
log4c is a runtime requirements too. check is only for testing
|
||||
purposes.
|
||||
|
||||
Note that these version numbers are version we know works correctly. If you
|
||||
build and run csync successfully with an older version, please let us know.
|
||||
|
||||
|
||||
## Building
|
||||
First, you need to configure the compilation, using CMake. Go inside the
|
||||
`build` dir.
|
||||
|
||||
GNU/Linux and MacOS X:
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make
|
||||
|
||||
### CMake standard options
|
||||
Here is a list of the most interesting options provided out of the box by CMake.
|
||||
|
||||
- CMAKE_BUILD_TYPE: The type of build (can be Debug Release MinSizeRel RelWithDebInfo)
|
||||
- CMAKE_INSTALL_PREFIX: The prefix to use when running make install (Default to
|
||||
/usr/local on GNU/Linux and MacOS X)
|
||||
- CMAKE_C_COMPILER: The path to the C compiler
|
||||
- CMAKE_CXX_COMPILER: The path to the C++ compiler
|
||||
|
||||
### CMake options defined for csync
|
||||
|
||||
Options are defined in the following files:
|
||||
|
||||
- DefineOptions.cmake
|
||||
|
||||
They can be changed with the -D option:
|
||||
|
||||
`cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_LOG4C=OFF ..`
|
||||
|
||||
### Browsing/editing CMake options
|
||||
|
||||
In addition to passing options on the command line, you can browse and edit
|
||||
CMake options using `cmakesetup` (Windows) or `ccmake` (GNU/Linux and MacOS X).
|
||||
|
||||
- Go to the build dir
|
||||
- On Windows: run `cmakesetup`
|
||||
- On GNU/Linux and MacOS X: run `ccmake ..`
|
||||
|
||||
## Installing
|
||||
|
||||
Befor installing you can run the tests if everything is working:
|
||||
|
||||
make test
|
||||
|
||||
If you want to install csync after compilation run:
|
||||
|
||||
make install
|
||||
|
||||
## Running
|
||||
|
||||
The csync binary can be found in the `build/client` directory.
|
||||
|
||||
## About this document
|
||||
|
||||
This document is written using [Markdown][] syntax, making it possible to
|
||||
provide usable information in both plain text and HTML format. Whenever
|
||||
modifying this document please use [Markdown][] syntax.
|
||||
|
||||
[markdown]: http://www.daringfireball.net/projects/markdown
|
0
README
Normal file
0
README
Normal file
148
build/build_make.sh
Executable file
148
build/build_make.sh
Executable file
|
@ -0,0 +1,148 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script to build csync on UNIX.
|
||||
#
|
||||
# Copyright (c) 2006-2007 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
|
||||
SOURCE_DIR=".."
|
||||
|
||||
LANG=C
|
||||
export LANG
|
||||
|
||||
SCRIPT="$0"
|
||||
COUNT=0
|
||||
while [ -L "${SCRIPT}" ]
|
||||
do
|
||||
SCRIPT=$(readlink ${SCRIPT})
|
||||
COUNT=$(expr ${COUNT} + 1)
|
||||
if [ ${COUNT} -gt 100 ]; then
|
||||
echo "Too many symbolic links"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
BUILDDIR=$(dirname ${SCRIPT})
|
||||
|
||||
cleanup_and_exit () {
|
||||
if test "$1" = 0 -o -z "$1" ; then
|
||||
exit 0
|
||||
else
|
||||
exit $1
|
||||
fi
|
||||
}
|
||||
|
||||
function configure() {
|
||||
cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
|
||||
}
|
||||
|
||||
function compile() {
|
||||
CPUCOUNT=$(grep -c processor /proc/cpuinfo)
|
||||
if [ "${CPUCOUNT}" -gt "1" ]; then
|
||||
make -j${CPUCOUNT} $1 || cleanup_and_exit $?
|
||||
else
|
||||
make $1 || exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
function clean_build_dir() {
|
||||
find ! -path "*.svn*" ! -name "*.bat" ! -name "*.sh" ! -name "." -print0 | xargs -0 rm -rf
|
||||
}
|
||||
|
||||
function usage () {
|
||||
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help]"
|
||||
cleanup_and_exit
|
||||
}
|
||||
|
||||
cd ${BUILDDIR}
|
||||
|
||||
OPTIONS="--graphviz=${BUILDDIR}/csync.dot"
|
||||
|
||||
while test -n "$1"; do
|
||||
PARAM="$1"
|
||||
ARG="$2"
|
||||
shift
|
||||
case ${PARAM} in
|
||||
*-*=*)
|
||||
ARG=${PARAM#*=}
|
||||
PARAM=${PARAM%%=*}
|
||||
set -- "----noarg=${PARAM}" "$@"
|
||||
esac
|
||||
case ${PARAM} in
|
||||
*-help|-h)
|
||||
#echo_help
|
||||
usage
|
||||
cleanup_and_exit
|
||||
;;
|
||||
*-build)
|
||||
DOMAKE="1"
|
||||
BUILD_TYPE="${ARG}"
|
||||
test -n "${BUILD_TYPE}" && shift
|
||||
;;
|
||||
*-clean)
|
||||
clean_build_dir
|
||||
cleanup_and_exit
|
||||
;;
|
||||
*-verbose)
|
||||
DOVERBOSE="1"
|
||||
;;
|
||||
*-libsuffix)
|
||||
OPTIONS="${OPTIONS} -DLIB_SUFFIX=${ARG}"
|
||||
shift
|
||||
;;
|
||||
*-prefix)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_INSTALL_PREFIX=${ARG}"
|
||||
shift
|
||||
;;
|
||||
----noarg)
|
||||
echo "$ARG does not take an argument"
|
||||
cleanup_and_exit
|
||||
;;
|
||||
-*)
|
||||
echo Unknown Option "$PARAM". Exit.
|
||||
cleanup_and_exit 1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case ${BUILD_TYPE} in
|
||||
debug)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=Debug"
|
||||
;;
|
||||
release)
|
||||
OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=Release"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "${DOVERBOSE}" ]; then
|
||||
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=1"
|
||||
else
|
||||
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=0"
|
||||
fi
|
||||
|
||||
test -f "${BUILDDIR}/.build.log" && rm -f ${BUILDDIR}/.build.log
|
||||
touch ${BUILDDIR}/.build.log
|
||||
# log everything from here to .build.log
|
||||
exec 1> >(exec -a 'build logging tee' tee -a ${BUILDDIR}/.build.log) 2>&1
|
||||
echo "${HOST} started build at $(date)."
|
||||
echo
|
||||
|
||||
configure ${OPTIONS} "$@"
|
||||
|
||||
if [ -n "${DOMAKE}" ]; then
|
||||
test -n "${DOVERBOSE}" && compile VERBOSE=1 || compile
|
||||
fi
|
||||
|
||||
DOT=$(which dot 2>/dev/null)
|
||||
if [ -n "${DOT}" ]; then
|
||||
${DOT} -Tpng -o${BUILDDIR}/csync.png ${BUILDDIR}/csync.dot
|
||||
${DOT} -Tsvg -o${BUILDDIR}/csync.svg ${BUILDDIR}/csync.dot
|
||||
fi
|
||||
|
||||
exec >&0 2>&0 # so that the logging tee finishes
|
||||
sleep 1 # wait till tee terminates
|
||||
|
||||
cleanup_and_exit 0
|
||||
|
44
client/CMakeLists.txt
Normal file
44
client/CMakeLists.txt
Normal file
|
@ -0,0 +1,44 @@
|
|||
project(client)
|
||||
|
||||
set(CLIENT_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
CACHE INTERNAL "csync client public include directories"
|
||||
)
|
||||
|
||||
set(CLIENT_PRIVATE_INCLUDE_DIRS
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(CLIENT_EXECUTABLE
|
||||
csync_client
|
||||
CACHE INTERNAL "csync client"
|
||||
)
|
||||
|
||||
set(CLIENT_LINK_LIBRARIES
|
||||
${CLIENT_EXECUTABLE}
|
||||
${CSYNC_LIBRARY}
|
||||
)
|
||||
|
||||
set(client_SRCS
|
||||
csync_client.c
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CLIENT_PUBLIC_INCLUDE_DIRS}
|
||||
${CLIENT_PRIVATE_INCLUDE_DIRS}
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_executable(${CLIENT_EXECUTABLE} ${client_SRCS})
|
||||
|
||||
target_link_libraries(${CLIENT_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${CLIENT_EXECUTABLE}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME
|
||||
csync
|
||||
)
|
||||
|
127
client/csync_client.c
Normal file
127
client/csync_client.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a replica with another
|
||||
*
|
||||
* Copyright (c) 2006-2007 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
const char *argp_program_version = "csync commandline client 0.1";
|
||||
const char *argp_program_bug_address = "<csync-devel@csync.org>";
|
||||
|
||||
/* Program documentation. */
|
||||
static char doc[] = "csync -- a user level file synchronizer";
|
||||
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "SOURCE DESTINATION";
|
||||
|
||||
/* The options we understand. */
|
||||
static struct argp_option options[] = {
|
||||
{"update", 'u', 0, 0, "Run only the update detection", 0},
|
||||
{"reconcile",'r', 0, 0, "Run update detection and recoincilation", 0},
|
||||
{NULL, 0, 0, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Used by main to communicate with parse_opt. */
|
||||
struct argument_s {
|
||||
char *args[2]; /* SOURCE and DESTINATION */
|
||||
int update;
|
||||
int reconcile;
|
||||
int propagate;
|
||||
};
|
||||
|
||||
/* Parse a single option. */
|
||||
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
/* Get the input argument from argp_parse, which we
|
||||
* know is a pointer to our arguments structure.
|
||||
*/
|
||||
struct argument_s *arguments = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'u':
|
||||
arguments->reconcile = 0;
|
||||
arguments->propagate = 0;
|
||||
break;
|
||||
case 'r':
|
||||
arguments->propagate = 0;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 2) {
|
||||
/* Too many arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
arguments->args[state->arg_num] = arg;
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if (state->arg_num < 2) {
|
||||
/* Not enough arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Our argp parser. */
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CSYNC *csync;
|
||||
|
||||
struct argument_s arguments;
|
||||
|
||||
/* Default values. */
|
||||
arguments.update = 1;
|
||||
arguments.reconcile = 1;
|
||||
arguments.propagate = 1;
|
||||
|
||||
/*
|
||||
* Parse our arguments; every option seen by parse_opt will
|
||||
* be reflected in arguments.
|
||||
*/
|
||||
argp_parse (&argp, argc, argv, 0, 0, &arguments);
|
||||
|
||||
if (csync_create(&csync) < 0) {
|
||||
fprintf(stderr, "csync_create: failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
csync->init(csync);
|
||||
printf("Version: %s\n", csync->version());
|
||||
|
||||
if (arguments.update) {
|
||||
}
|
||||
|
||||
if (arguments.reconcile) {
|
||||
}
|
||||
|
||||
if (arguments.propagate) {
|
||||
}
|
||||
|
||||
csync->destroy(csync);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
22
cmake/Modules/COPYING-CMAKE-SCRIPTS
Normal file
22
cmake/Modules/COPYING-CMAKE-SCRIPTS
Normal file
|
@ -0,0 +1,22 @@
|
|||
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 copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR 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.
|
16
cmake/Modules/CheckCXXCompilerFlag.cmake
Normal file
16
cmake/Modules/CheckCXXCompilerFlag.cmake
Normal file
|
@ -0,0 +1,16 @@
|
|||
# - Check whether the compiler supports a given flag.
|
||||
# CHECK_CXX_COMPILER_FLAG(FLAG VARIABLE)
|
||||
#
|
||||
# FLAG - the compiler flag
|
||||
# VARIABLE - variable to store the result
|
||||
#
|
||||
|
||||
INCLUDE(CheckCXXSourceCompiles)
|
||||
|
||||
MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
|
||||
SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
|
||||
SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT})
|
||||
SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
|
||||
ENDMACRO (CHECK_CXX_COMPILER_FLAG)
|
||||
|
31
cmake/Modules/DefineCMakeDefaults.cmake
Normal file
31
cmake/Modules/DefineCMakeDefaults.cmake
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Required cmake version
|
||||
cmake_minimum_required(VERSION 2.4.3)
|
||||
|
||||
# Always include srcdir and builddir in include path
|
||||
# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in
|
||||
# about every subdir
|
||||
# since cmake 2.4.0
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# Put the include dirs which are in the source or build tree
|
||||
# before all other include dirs, so the headers in the sources
|
||||
# are prefered over the already installed ones
|
||||
# since cmake 2.4.1
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
|
||||
|
||||
# Use colored output
|
||||
# since cmake 2.4.0
|
||||
set(CMAKE_COLOR_MAKEFILE ON)
|
||||
|
||||
# Define the generic version of the libraries here
|
||||
set(GENERIC_LIB_VERSION "2.0.0")
|
||||
set(GENERIC_LIB_SOVERSION "2")
|
||||
|
||||
# Set the default build type to release with debug info
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug
|
||||
CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE
|
||||
)
|
||||
endif (NOT CMAKE_BUILD_TYPE)
|
39
cmake/Modules/DefineCompilerFlags.cmake
Normal file
39
cmake/Modules/DefineCompilerFlags.cmake
Normal file
|
@ -0,0 +1,39 @@
|
|||
# define system dependent compiler flags
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
# with -fPIC
|
||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
check_cxx_compiler_flag("-fPIC" WITH_FPIC)
|
||||
if (WITH_FPIC)
|
||||
add_definitions(-fPIC)
|
||||
endif (WITH_FPIC)
|
||||
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS64_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
# with large file support
|
||||
execute_process(
|
||||
COMMAND
|
||||
getconf LFS_CFLAGS
|
||||
OUTPUT_VARIABLE
|
||||
_lfs_CFLAGS
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||
|
||||
string(REGEX REPLACE "[\r\n]" " " ${_lfs_CFLAGS} "${${_lfs_CFLAGS}}")
|
||||
|
||||
add_definitions(${_lfs_CFLAGS})
|
||||
|
||||
add_definitions(-Wall -W -Wmissing-prototypes -Wdeclaration-after-statement -D_FORTIFY_SOURCE=2)
|
||||
endif (UNIX AND NOT WIN32)
|
124
cmake/Modules/DefineInstallationPaths.cmake
Normal file
124
cmake/Modules/DefineInstallationPaths.cmake
Normal file
|
@ -0,0 +1,124 @@
|
|||
if (UNIX)
|
||||
IF (NOT APPLICATION_NAME)
|
||||
MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
|
||||
SET(APPLICATION_NAME ${PROJECT_NAME})
|
||||
ENDIF (NOT APPLICATION_NAME)
|
||||
|
||||
# Suffix for Linux
|
||||
SET(LIB_SUFFIX
|
||||
CACHE STRING "Define suffix of directory name (32/64)"
|
||||
)
|
||||
|
||||
SET(EXEC_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}"
|
||||
CACHE PATH "Base directory for executables and libraries"
|
||||
FORCE
|
||||
)
|
||||
SET(SHARE_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE PATH "Base directory for files which go to share/"
|
||||
FORCE
|
||||
)
|
||||
SET(DATA_INSTALL_PREFIX
|
||||
"${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The parent directory where applications can install their data" FORCE)
|
||||
|
||||
# The following are directories where stuff will be installed to
|
||||
SET(BIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/bin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
|
||||
FORCE
|
||||
)
|
||||
SET(SBIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/sbin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
|
||||
FORCE
|
||||
)
|
||||
SET(LIB_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
|
||||
FORCE
|
||||
)
|
||||
SET(LIBEXEC_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/libexec"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
|
||||
FORCE
|
||||
)
|
||||
SET(PLUGIN_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
|
||||
FORCE
|
||||
)
|
||||
SET(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/include"
|
||||
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(DATA_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}"
|
||||
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
|
||||
FORCE
|
||||
)
|
||||
SET(HTML_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/doc/HTML"
|
||||
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
|
||||
FORCE
|
||||
)
|
||||
SET(ICON_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/icons"
|
||||
CACHE PATH "The icon install dir (default data/icons/)"
|
||||
FORCE
|
||||
)
|
||||
SET(SOUND_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/sounds"
|
||||
CACHE PATH "The install dir for sound files (default data/sounds)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(LOCALE_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/locale"
|
||||
CACHE PATH "The install dir for translations (default prefix/share/locale)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(XDG_APPS_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/applications/"
|
||||
CACHE PATH "The XDG apps dir"
|
||||
FORCE
|
||||
)
|
||||
SET(XDG_DIRECTORY_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/desktop-directories"
|
||||
CACHE PATH "The XDG directory"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(SYSCONF_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/etc"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
|
||||
FORCE
|
||||
)
|
||||
SET(MAN_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/man"
|
||||
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
|
||||
FORCE
|
||||
)
|
||||
SET(INFO_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/info"
|
||||
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
|
||||
FORCE
|
||||
)
|
||||
endif (UNIX)
|
||||
|
||||
if (WIN32)
|
||||
# Same same
|
||||
SET(BIN_INSTALL_DIR .)
|
||||
SET(SBIN_INSTALL_DIR .)
|
||||
SET(LIB_INSTALL_DIR .)
|
||||
SET(PLUGIN_INSTALL_DIR plugins)
|
||||
SET(HTML_INSTALL_DIR doc/HTML)
|
||||
SET(ICON_INSTALL_DIR .)
|
||||
SET(SOUND_INSTALL_DIR .)
|
||||
SET(LOCALE_INSTALL_DIR lang)
|
||||
endif (WIN32)
|
||||
|
46
cmake/Modules/FindCheck.cmake
Normal file
46
cmake/Modules/FindCheck.cmake
Normal file
|
@ -0,0 +1,46 @@
|
|||
# - Try to find the CHECK libraries
|
||||
# Once done this will define
|
||||
#
|
||||
# CHECK_FOUND - system has check
|
||||
# CHECK_INCLUDE_DIR - the check include directory
|
||||
# CHECK_LIBRARIES - check library
|
||||
#
|
||||
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
|
||||
# Copyright (c) 2007 Bjoern Ricks <b.ricks@fh-osnabrueck.de>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
INCLUDE( FindPkgConfig )
|
||||
|
||||
# Take care about check.pc settings
|
||||
PKG_SEARCH_MODULE( CHECK check )
|
||||
|
||||
# Look for CHECK include dir and libraries
|
||||
IF( NOT CHECK_FOUND )
|
||||
|
||||
FIND_PATH( CHECK_INCLUDE_DIR check.h )
|
||||
|
||||
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
|
||||
|
||||
IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
|
||||
SET( CHECK_FOUND 1 )
|
||||
IF ( NOT Check_FIND_QUIETLY )
|
||||
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
|
||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
||||
ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
|
||||
IF ( Check_FIND_REQUIRED )
|
||||
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
|
||||
ELSE ( Check_FIND_REQUIRED )
|
||||
IF ( NOT Check_FIND_QUIETLY )
|
||||
MESSAGE( STATUS "Could NOT find CHECK" )
|
||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
||||
ENDIF ( Check_FIND_REQUIRED )
|
||||
ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
|
||||
ENDIF( NOT CHECK_FOUND )
|
||||
|
||||
# Hide advanced variables from CMake GUIs
|
||||
MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES )
|
||||
|
74
cmake/Modules/FindIniparser.cmake
Normal file
74
cmake/Modules/FindIniparser.cmake
Normal file
|
@ -0,0 +1,74 @@
|
|||
# - Try to find Iniparser
|
||||
# Once done this will define
|
||||
#
|
||||
# INIPARSER_FOUND - system has Iniparser
|
||||
# INIPARSER_INCLUDE_DIRS - the Iniparser include directory
|
||||
# INIPARSER_LIBRARIES - Link these to use Iniparser
|
||||
# INIPARSER_DEFINITIONS - Compiler switches required for using Iniparser
|
||||
#
|
||||
# Copyright (c) 2007 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
|
||||
if (INIPARSER_LIBRARIES AND INIPARSER_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(INIPARSER_FOUND TRUE)
|
||||
else (INIPARSER_LIBRARIES AND INIPARSER_INCLUDE_DIRS)
|
||||
find_path(INIPARSER_INCLUDE_DIR
|
||||
NAMES
|
||||
iniparser.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
)
|
||||
|
||||
find_library(INIPARSER_LIBRARY
|
||||
NAMES
|
||||
iniparser
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
)
|
||||
|
||||
if (INIPARSER_LIBRARY)
|
||||
set(INIPARSER_FOUND TRUE)
|
||||
endif (INIPARSER_LIBRARY)
|
||||
|
||||
set(INIPARSER_INCLUDE_DIRS
|
||||
${INIPARSER_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (INIPARSER_FOUND)
|
||||
set(INIPARSER_LIBRARIES
|
||||
${INIPARSER_LIBRARIES}
|
||||
${INIPARSER_LIBRARY}
|
||||
)
|
||||
endif (INIPARSER_FOUND)
|
||||
|
||||
if (INIPARSER_INCLUDE_DIRS AND INIPARSER_LIBRARIES)
|
||||
set(INIPARSER_FOUND TRUE)
|
||||
endif (INIPARSER_INCLUDE_DIRS AND INIPARSER_LIBRARIES)
|
||||
|
||||
if (INIPARSER_FOUND)
|
||||
if (NOT Iniparser_FIND_QUIETLY)
|
||||
message(STATUS "Found Iniparser: ${INIPARSER_LIBRARIES}")
|
||||
endif (NOT Iniparser_FIND_QUIETLY)
|
||||
else (INIPARSER_FOUND)
|
||||
if (Iniparser_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find Iniparser")
|
||||
endif (Iniparser_FIND_REQUIRED)
|
||||
endif (INIPARSER_FOUND)
|
||||
|
||||
# show the INIPARSER_INCLUDE_DIRS and INIPARSER_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(INIPARSER_INCLUDE_DIRS INIPARSER_LIBRARIES)
|
||||
|
||||
endif (INIPARSER_LIBRARIES AND INIPARSER_INCLUDE_DIRS)
|
||||
|
74
cmake/Modules/FindLOG4C.cmake
Normal file
74
cmake/Modules/FindLOG4C.cmake
Normal file
|
@ -0,0 +1,74 @@
|
|||
# - Try to find LOG4C
|
||||
# Once done this will define
|
||||
#
|
||||
# LOG4C_FOUND - system has LOG4C
|
||||
# LOG4C_INCLUDE_DIRS - the LOG4C include directory
|
||||
# LOG4C_LIBRARIES - Link these to use LOG4C
|
||||
# LOG4C_DEFINITIONS - Compiler switches required for using LOG4C
|
||||
#
|
||||
# Copyright (c) 2007 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
|
||||
if (LOG4C_LIBRARIES AND LOG4C_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LOG4C_FOUND TRUE)
|
||||
else (LOG4C_LIBRARIES AND LOG4C_INCLUDE_DIRS)
|
||||
find_path(LOG4C_INCLUDE_DIR
|
||||
NAMES
|
||||
log4c.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
)
|
||||
|
||||
find_library(LOG4C_LIBRARY
|
||||
NAMES
|
||||
log4c
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
)
|
||||
|
||||
if (LOG4C_LIBRARY)
|
||||
set(LOG4C_FOUND TRUE)
|
||||
endif (LOG4C_LIBRARY)
|
||||
|
||||
set(LOG4C_INCLUDE_DIRS
|
||||
${LOG4C_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (LOG4C_FOUND)
|
||||
set(LOG4C_LIBRARIES
|
||||
${LOG4C_LIBRARIES}
|
||||
${LOG4C_LIBRARY}
|
||||
)
|
||||
endif (LOG4C_FOUND)
|
||||
|
||||
if (LOG4C_INCLUDE_DIRS AND LOG4C_LIBRARIES)
|
||||
set(LOG4C_FOUND TRUE)
|
||||
endif (LOG4C_INCLUDE_DIRS AND LOG4C_LIBRARIES)
|
||||
|
||||
if (LOG4C_FOUND)
|
||||
if (NOT LOG4C_FIND_QUIETLY)
|
||||
message(STATUS "Found LOG4C: ${LOG4C_LIBRARIES}")
|
||||
endif (NOT LOG4C_FIND_QUIETLY)
|
||||
else (LOG4C_FOUND)
|
||||
if (LOG4C_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find LOG4C")
|
||||
endif (LOG4C_FIND_REQUIRED)
|
||||
endif (LOG4C_FOUND)
|
||||
|
||||
# show the LOG4C_INCLUDE_DIRS and LOG4C_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(LOG4C_INCLUDE_DIRS LOG4C_LIBRARIES)
|
||||
|
||||
endif (LOG4C_LIBRARIES AND LOG4C_INCLUDE_DIRS)
|
||||
|
74
cmake/Modules/FindLibsmbclient.cmake
Normal file
74
cmake/Modules/FindLibsmbclient.cmake
Normal file
|
@ -0,0 +1,74 @@
|
|||
# - Try to find Libsmbclient
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBSMBCLIENT_FOUND - system has Libsmbclient
|
||||
# LIBSMBCLIENT_INCLUDE_DIRS - the Libsmbclient include directory
|
||||
# LIBSMBCLIENT_LIBRARIES - Link these to use Libsmbclient
|
||||
# LIBSMBCLIENT_DEFINITIONS - Compiler switches required for using Libsmbclient
|
||||
#
|
||||
# Copyright (c) 2006 Andreas Schneider <anschneider@suse.de>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
|
||||
if (LIBSMBCLIENT_LIBRARIES AND LIBSMBCLIENT_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBSMBCLIENT_FOUND TRUE)
|
||||
else (LIBSMBCLIENT_LIBRARIES AND LIBSMBCLIENT_INCLUDE_DIRS)
|
||||
find_path(LIBSMBCLIENT_INCLUDE_DIR
|
||||
NAMES
|
||||
libsmbclient.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
)
|
||||
|
||||
find_library(SMBCLIENT_LIBRARY
|
||||
NAMES
|
||||
smbclient
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
)
|
||||
|
||||
if (SMBCLIENT_LIBRARY)
|
||||
set(SMBCLIENT_FOUND TRUE)
|
||||
endif (SMBCLIENT_LIBRARY)
|
||||
|
||||
set(LIBSMBCLIENT_INCLUDE_DIRS
|
||||
${LIBSMBCLIENT_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (SMBCLIENT_FOUND)
|
||||
set(LIBSMBCLIENT_LIBRARIES
|
||||
${LIBSMBCLIENT_LIBRARIES}
|
||||
${SMBCLIENT_LIBRARY}
|
||||
)
|
||||
endif (SMBCLIENT_FOUND)
|
||||
|
||||
if (LIBSMBCLIENT_INCLUDE_DIRS AND LIBSMBCLIENT_LIBRARIES)
|
||||
set(LIBSMBCLIENT_FOUND TRUE)
|
||||
endif (LIBSMBCLIENT_INCLUDE_DIRS AND LIBSMBCLIENT_LIBRARIES)
|
||||
|
||||
if (LIBSMBCLIENT_FOUND)
|
||||
if (NOT Libsmbclient_FIND_QUIETLY)
|
||||
message(STATUS "Found Libsmbclient: ${LIBSMBCLIENT_LIBRARIES}")
|
||||
endif (NOT Libsmbclient_FIND_QUIETLY)
|
||||
else (LIBSMBCLIENT_FOUND)
|
||||
if (Libsmbclient_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find Libsmbclient")
|
||||
endif (Libsmbclient_FIND_REQUIRED)
|
||||
endif (LIBSMBCLIENT_FOUND)
|
||||
|
||||
# show the LIBSMBCLIENT_INCLUDE_DIRS and LIBSMBCLIENT_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(LIBSMBCLIENT_INCLUDE_DIRS LIBSMBCLIENT_LIBRARIES)
|
||||
|
||||
endif (LIBSMBCLIENT_LIBRARIES AND LIBSMBCLIENT_INCLUDE_DIRS)
|
||||
|
82
cmake/Modules/FindSqlite3.cmake
Normal file
82
cmake/Modules/FindSqlite3.cmake
Normal file
|
@ -0,0 +1,82 @@
|
|||
# - Try to find sqlite3
|
||||
# Find sqlite3 headers, libraries and the answer to all questions.
|
||||
#
|
||||
# SQLITE3_FOUND True if sqlite3 got found
|
||||
# SQLITE3_INCLUDEDIR Location of sqlite3 headers
|
||||
# SQLITE3_LIBRARIES List of libaries to use sqlite3
|
||||
# SQLITE3_DEFINITIONS Definitions to compile sqlite3
|
||||
#
|
||||
# Copyright (c) 2007 Juha Tuomala <tuju@iki.fi>
|
||||
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
|
||||
# Copyright (c) 2007 Alban Browaeys <prahal@yahoo.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
INCLUDE( FindPkgConfig )
|
||||
# Take care about sqlite3.pc settings
|
||||
IF ( Sqlite3_FIND_REQUIRED )
|
||||
SET( _pkgconfig_REQUIRED "REQUIRED" )
|
||||
ELSE ( Sqlite3_FIND_REQUIRED )
|
||||
SET( _pkgconfig_REQUIRED "" )
|
||||
ENDIF ( Sqlite3_FIND_REQUIRED )
|
||||
|
||||
IF ( SQLITE3_MIN_VERSION )
|
||||
PKG_SEARCH_MODULE( SQLITE3 ${_pkgconfig_REQUIRED} sqlite3>=${SQLITE3_MIN_VERSION} )
|
||||
ELSE ( SQLITE3_MIN_VERSION )
|
||||
pkg_search_module( SQLITE3 ${_pkgconfig_REQUIRED} sqlite3 )
|
||||
ENDIF ( SQLITE3_MIN_VERSION )
|
||||
|
||||
|
||||
# Look for sqlite3 include dir and libraries w/o pkgconfig
|
||||
IF ( NOT SQLITE3_FOUND AND NOT PKG_CONFIG_FOUND )
|
||||
FIND_PATH( _sqlite3_include_DIR sqlite3.h
|
||||
PATHS
|
||||
/opt/local/include/
|
||||
/sw/include/
|
||||
/usr/local/include/
|
||||
/usr/include/
|
||||
)
|
||||
FIND_LIBRARY( _sqlite3_link_DIR sqlite3
|
||||
PATHS
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/usr/lib64
|
||||
/usr/local/lib64
|
||||
/opt/lib64
|
||||
)
|
||||
IF ( _sqlite3_include_DIR AND _sqlite3_link_DIR )
|
||||
SET ( _sqlite3_FOUND TRUE )
|
||||
ENDIF ( _sqlite3_include_DIR AND _sqlite3_link_DIR )
|
||||
|
||||
|
||||
IF ( _sqlite3_FOUND )
|
||||
SET ( SQLITE3_INCLUDE_DIRS ${_sqlite3_include_DIR} )
|
||||
SET ( SQLITE3_LIBRARIES ${_sqlite3_link_DIR} )
|
||||
ENDIF ( _sqlite3_FOUND )
|
||||
|
||||
# Report results
|
||||
IF ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
|
||||
SET( SQLITE3_FOUND 1 )
|
||||
IF ( NOT Sqlite3_FIND_QUIETLY )
|
||||
MESSAGE( STATUS "Found sqlite3: ${SQLITE3_LIBRARIES} ${SQLITE3_INCLUDE_DIRS}" )
|
||||
ENDIF ( NOT Sqlite3_FIND_QUIETLY )
|
||||
ELSE ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
|
||||
IF ( Sqlite3_FIND_REQUIRED )
|
||||
MESSAGE( SEND_ERROR "Could NOT find sqlite3" )
|
||||
ELSE ( Sqlite3_FIND_REQUIRED )
|
||||
IF ( NOT Sqlite3_FIND_QUIETLY )
|
||||
MESSAGE( STATUS "Could NOT find sqlite3" )
|
||||
ENDIF ( NOT Sqlite3_FIND_QUIETLY )
|
||||
ENDIF ( Sqlite3_FIND_REQUIRED )
|
||||
ENDIF ( SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS AND _sqlite3_FOUND )
|
||||
|
||||
ENDIF ( NOT SQLITE3_FOUND AND NOT PKG_CONFIG_FOUND )
|
||||
|
||||
# Hide advanced variables from CMake GUIs
|
||||
MARK_AS_ADVANCED( SQLITE3_LIBRARIES SQLITE3_INCLUDE_DIRS )
|
||||
|
22
cmake/Modules/MacroAddCheckTest.cmake
Normal file
22
cmake/Modules/MacroAddCheckTest.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
# - MACRO_ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN)
|
||||
|
||||
# Copyright (c) 2007, Daniel Gollub, <dgollub@suse.de>
|
||||
# Copyright (c) 2007, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
|
||||
set(CMAKE_C_FLAGS_PROFILING "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Compiler Flags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
|
||||
macro (MACRO_ADD_CHECK_TEST _testName _testSource)
|
||||
add_executable(${_testName} ${_testSource})
|
||||
target_link_libraries(${_testName} ${ARGN})
|
||||
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
|
||||
endmacro (MACRO_ADD_CHECK_TEST)
|
||||
|
21
cmake/Modules/MacroAddCompileFlags.cmake
Normal file
21
cmake/Modules/MacroAddCompileFlags.cmake
Normal file
|
@ -0,0 +1,21 @@
|
|||
# - MACRO_ADD_COMPILE_FLAGS(target_name flag1 ... flagN)
|
||||
|
||||
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
macro (MACRO_ADD_COMPILE_FLAGS _target)
|
||||
|
||||
get_target_property(_flags ${_target} COMPILE_FLAGS)
|
||||
if (_flags)
|
||||
set(_flags ${_flags} ${ARGN})
|
||||
else (_flags)
|
||||
set(_flags ${ARGN})
|
||||
endif (_flags)
|
||||
|
||||
set_target_properties(${_target} PROPERTIES COMPILE_FLAGS ${_flags})
|
||||
|
||||
endmacro (MACRO_ADD_COMPILE_FLAGS)
|
20
cmake/Modules/MacroAddLinkFlags.cmake
Normal file
20
cmake/Modules/MacroAddLinkFlags.cmake
Normal file
|
@ -0,0 +1,20 @@
|
|||
# - MACRO_ADD_LINK_FLAGS(target_name flag1 ... flagN)
|
||||
|
||||
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
macro (MACRO_ADD_LINK_FLAGS _target)
|
||||
|
||||
get_target_property(_flags ${_target} LINK_FLAGS)
|
||||
if (_flags)
|
||||
set(_flags "${_flags} ${ARGN}")
|
||||
else (_flags)
|
||||
set(_flags "${ARGN}")
|
||||
endif (_flags)
|
||||
|
||||
set_target_properties(${_target} PROPERTIES LINK_FLAGS "${_flags}")
|
||||
|
||||
endmacro (MACRO_ADD_LINK_FLAGS)
|
30
cmake/Modules/MacroAddPlugin.cmake
Normal file
30
cmake/Modules/MacroAddPlugin.cmake
Normal file
|
@ -0,0 +1,30 @@
|
|||
# - MACRO_ADD_PLUGIN(name [WITH_PREFIX] file1 .. fileN)
|
||||
#
|
||||
# Create a plugin from the given source files.
|
||||
# If WITH_PREFIX is given, the resulting plugin will have the
|
||||
# prefix "lib", otherwise it won't.
|
||||
#
|
||||
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
|
||||
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
macro (MACRO_ADD_PLUGIN _target_NAME _with_PREFIX)
|
||||
|
||||
if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC)
|
||||
else (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC ${_with_PREFIX})
|
||||
endif (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
|
||||
add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
|
||||
|
||||
if (_first_SRC)
|
||||
set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
|
||||
endif (_first_SRC)
|
||||
|
||||
endmacro (MACRO_ADD_PLUGIN _name _sources)
|
||||
|
22
cmake/Modules/MacroCheckTest.cmake
Normal file
22
cmake/Modules/MacroCheckTest.cmake
Normal file
|
@ -0,0 +1,22 @@
|
|||
# - MACRO_ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN)
|
||||
|
||||
# Copyright (c) 2007, Daniel Gollub, <dgollub@suse.de>
|
||||
# Copyright (c) 2007, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
|
||||
set(CMAKE_C_FLAGS_PROFILING "-g -O0 -Wall -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wwrite-strings -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Compiler Flags")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_PROFILING " -fprofile-arcs -ftest-coverage" CACHE STRING "Profiling Linker Flags")
|
||||
|
||||
macro (MACRO_ADD_CHECK_TEST _testName _testSource)
|
||||
add_executable(${_testName} ${_testSource})
|
||||
target_link_libraries(${_testName} ${ARGN})
|
||||
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
|
||||
endmacro (MACRO_ADD_CHECK_TEST)
|
||||
|
17
cmake/Modules/MacroEnsureOutOfSourceBuild.cmake
Normal file
17
cmake/Modules/MacroEnsureOutOfSourceBuild.cmake
Normal file
|
@ -0,0 +1,17 @@
|
|||
# - MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
|
||||
# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
|
||||
|
||||
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
macro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage)
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource)
|
||||
if (_insource)
|
||||
message(SEND_ERROR "${_errorMessage}")
|
||||
message(FATAL_ERROR "Remove the file CMakeCache.txt in ${CMAKE_SOURCE_DIR} first.")
|
||||
endif (_insource)
|
||||
|
||||
endmacro (MACRO_ENSURE_OUT_OF_SOURCE_BUILD)
|
123
cmake/Modules/UseDoxygen.cmake
Normal file
123
cmake/Modules/UseDoxygen.cmake
Normal file
|
@ -0,0 +1,123 @@
|
|||
# -helper macro to add a "doc" target with CMake build system.
|
||||
# and configure doxy.config.in to doxy.config
|
||||
#
|
||||
# target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux
|
||||
# Creates .chm windows help file if MS HTML help workshop
|
||||
# (available from http://msdn.microsoft.com/workshop/author/htmlhelp)
|
||||
# is installed with its DLLs in PATH.
|
||||
#
|
||||
#
|
||||
# Please note, that the tools, e.g.:
|
||||
# doxygen, dot, latex, dvips, makeindex, gswin32, etc.
|
||||
# must be in path.
|
||||
#
|
||||
# Note about Visual Studio Projects:
|
||||
# MSVS has its own path environment which may differ from the shell.
|
||||
# See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1
|
||||
#
|
||||
# author Jan Woetzel 2004-2006
|
||||
# www.mip.informatik.uni-kiel.de/~jw
|
||||
|
||||
|
||||
FIND_PACKAGE(Doxygen)
|
||||
|
||||
IF (DOXYGEN_FOUND)
|
||||
|
||||
# click+jump in Emacs and Visual Studio (for doxy.config) (jw)
|
||||
IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"")
|
||||
ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"")
|
||||
ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)")
|
||||
|
||||
# we need latex for doxygen because of the formulas
|
||||
FIND_PACKAGE(LATEX)
|
||||
IF (NOT LATEX_COMPILER)
|
||||
MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.")
|
||||
ENDIF (NOT LATEX_COMPILER)
|
||||
IF (NOT MAKEINDEX_COMPILER)
|
||||
MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.")
|
||||
ENDIF (NOT MAKEINDEX_COMPILER)
|
||||
IF (NOT DVIPS_CONVERTER)
|
||||
MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.")
|
||||
ENDIF (NOT DVIPS_CONVERTER)
|
||||
|
||||
IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
||||
MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/doxy.config
|
||||
@ONLY )
|
||||
# use (configured) doxy.config from (out of place) BUILD tree:
|
||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
|
||||
ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
||||
# use static hand-edited doxy.config from SOURCE tree:
|
||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
||||
IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
||||
MESSAGE(STATUS "WARNING: using existing ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config instead of configuring from doxy.config.in file.")
|
||||
ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
||||
IF (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
||||
# using template doxy.config.in
|
||||
MESSAGE(STATUS "Generate ${CMAKE_CURRENT_BINARY_DIR}/doxy.config from doxy.config.in")
|
||||
CONFIGURE_FILE(${CMAKE_MODULE_PATH}/doxy.config.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/doxy.config
|
||||
@ONLY )
|
||||
SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config")
|
||||
ELSE (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
||||
# failed completely...
|
||||
MESSAGE(SEND_ERROR "Please create ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in (or doxy.config as fallback)")
|
||||
ENDIF(EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in")
|
||||
|
||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config")
|
||||
ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in")
|
||||
|
||||
ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
|
||||
|
||||
# create a windows help .chm file using hhc.exe
|
||||
# HTMLHelp DLL must be in path!
|
||||
# fallback: use hhw.exe interactively
|
||||
IF (WIN32)
|
||||
FIND_PACKAGE(HTMLHelp)
|
||||
IF (HTML_HELP_COMPILER)
|
||||
SET (TMP "${CMAKE_CURRENT_BINARY_DIR}\\doc\\html\\index.hhp")
|
||||
STRING(REGEX REPLACE "[/]" "\\\\" HHP_FILE ${TMP} )
|
||||
# MESSAGE(SEND_ERROR "DBG HHP_FILE=${HHP_FILE}")
|
||||
ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE})
|
||||
ADD_DEPENDENCIES (winhelp doc)
|
||||
|
||||
IF (NOT TARGET_DOC_SKIP_INSTALL)
|
||||
# install windows help?
|
||||
# determine useful name for output file
|
||||
# should be project and version unique to allow installing
|
||||
# multiple projects into one global directory
|
||||
IF (EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm")
|
||||
IF (PROJECT_NAME)
|
||||
SET(OUT "${PROJECT_NAME}")
|
||||
ELSE (PROJECT_NAME)
|
||||
SET(OUT "Documentation") # default
|
||||
ENDIF(PROJECT_NAME)
|
||||
IF (${PROJECT_NAME}_VERSION_MAJOR)
|
||||
SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}")
|
||||
IF (${PROJECT_NAME}_VERSION_MINOR)
|
||||
SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}")
|
||||
IF (${PROJECT_NAME}_VERSION_PATCH)
|
||||
SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}")
|
||||
ENDIF(${PROJECT_NAME}_VERSION_PATCH)
|
||||
ENDIF(${PROJECT_NAME}_VERSION_MINOR)
|
||||
ENDIF(${PROJECT_NAME}_VERSION_MAJOR)
|
||||
# keep suffix
|
||||
SET(OUT "${OUT}.chm")
|
||||
|
||||
#MESSAGE("DBG ${PROJECT_BINARY_DIR}/doc/html/index.chm \n${OUT}")
|
||||
# create target used by install and package commands
|
||||
INSTALL(FILES "${PROJECT_BINARY_DIR}/doc/html/index.chm"
|
||||
DESTINATION "doc"
|
||||
RENAME "${OUT}"
|
||||
)
|
||||
ENDIF(EXISTS "${PROJECT_BINARY_DIR}/doc/html/index.chm")
|
||||
ENDIF(NOT TARGET_DOC_SKIP_INSTALL)
|
||||
|
||||
ENDIF(HTML_HELP_COMPILER)
|
||||
# MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}")
|
||||
ENDIF (WIN32)
|
||||
ENDIF(DOXYGEN_FOUND)
|
||||
|
180
cmake/Scripts/generate_findpackage_file
Normal file
180
cmake/Scripts/generate_findpackage_file
Normal file
|
@ -0,0 +1,180 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# Simple script to generate simple cmake modules for finding
|
||||
# libraries (packages)
|
||||
#
|
||||
# usage: generate_findpackage_file
|
||||
# then you will be prompted to enter the required parameters
|
||||
#
|
||||
#####################################################################
|
||||
#
|
||||
# Copyright (c) 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
print("Name of package: ")
|
||||
package=gets.chomp
|
||||
|
||||
printf("\nYour Name (for copyright): ")
|
||||
name=gets.chomp
|
||||
|
||||
printf("\nYour mail (for copyright): ")
|
||||
email=gets.chomp
|
||||
|
||||
print("\npkgconfig package name (e.g. \"libxml-2.0\", leave empty to skip pkgconfig): ")
|
||||
pkgconfig=gets.chomp
|
||||
|
||||
print("\nLook for header (e.g. \"jpeglib.h\" or \"libxml/xpath.h\"): ")
|
||||
header=gets.chomp
|
||||
|
||||
print("\nLook for header subdir (e.g. \"libxml2\", empty to skip ): ")
|
||||
incSubDir=gets.chomp
|
||||
|
||||
print("\nLook for library (e.g. \"xml2\" or \"avcodec avutil\"): ")
|
||||
libs=gets.chomp
|
||||
|
||||
t = Time.now
|
||||
|
||||
cmakeIncDirName=package.upcase+"_INCLUDE_DIR"
|
||||
cmakeIncDirNames=package.upcase+"_INCLUDE_DIRS"
|
||||
cmakeLibNames=package.upcase+"_LIBRARIES"
|
||||
cmakeDefsName=package.upcase+"_DEFINITIONS"
|
||||
cmakeFoundName=package.upcase+"_FOUND"
|
||||
cmakeQuietName=package+"_FIND_QUIETLY"
|
||||
cmakeRequiredName=package+"_FIND_REQUIRED"
|
||||
|
||||
file=File.new("Find#{package}.cmake", "w+")
|
||||
|
||||
|
||||
file.printf("# - Try to find #{package}\n")
|
||||
file.printf("# Once done this will define\n")
|
||||
file.printf("#\n")
|
||||
file.printf("# #{cmakeFoundName} - system has #{package}\n")
|
||||
file.printf("# #{cmakeIncDirNames} - the #{package} include directory\n")
|
||||
file.printf("# #{cmakeLibNames} - Link these to use #{package}\n")
|
||||
file.printf("# #{cmakeDefsName} - Compiler switches required for using #{package}\n")
|
||||
file.printf("#\n")
|
||||
file.printf("# Copyright (c) #{t.year} #{name} <#{email}>\n")
|
||||
file.printf("#\n")
|
||||
file.printf("# Redistribution and use is allowed according to the terms of the New\n")
|
||||
file.printf("# BSD license.\n")
|
||||
file.printf("# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n")
|
||||
file.printf("#\n")
|
||||
|
||||
file.printf("\n")
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("if (#{cmakeLibNames} AND #{cmakeIncDirNames})\n")
|
||||
file.printf(" # in cache already\n")
|
||||
file.printf(" set(#{cmakeFoundName} TRUE)\n")
|
||||
file.printf("else (#{cmakeLibNames} AND #{cmakeIncDirNames})\n")
|
||||
|
||||
if not pkgconfig.empty?
|
||||
file.printf(" # use pkg-config to get the directories and then use these values\n")
|
||||
file.printf(" # in the FIND_PATH() and FIND_LIBRARY() calls\n")
|
||||
file.printf(" include(UsePkgConfig)\n\n")
|
||||
file.printf(" pkgconfig(#{pkgconfig} _#{package}IncDir _#{package}LinkDir _#{package}LinkFlags _#{package}Cflags)\n\n")
|
||||
file.printf(" set(#{cmakeDefsName} ${_#{package}Cflags})\n\n")
|
||||
end
|
||||
|
||||
|
||||
file.printf(" find_path(#{cmakeIncDirName}\n")
|
||||
file.printf(" NAMES\n")
|
||||
file.printf(" #{header}\n")
|
||||
file.printf(" PATHS\n")
|
||||
if not pkgconfig.empty?
|
||||
file.printf(" ${_#{package}IncDir}\n")
|
||||
end
|
||||
file.printf(" /usr/include\n")
|
||||
file.printf(" /usr/local/include\n")
|
||||
file.printf(" /opt/local/include\n")
|
||||
file.printf(" /sw/include\n")
|
||||
|
||||
if not incSubDir.empty?
|
||||
file.printf(" PATH_SUFFIXES\n")
|
||||
file.printf(" #{incSubDir}\n")
|
||||
end
|
||||
file.printf(" )\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
libs.split(" ").each do |lib|
|
||||
file.printf(" find_library(#{lib.upcase}_LIBRARY\n")
|
||||
file.printf(" NAMES\n")
|
||||
file.printf(" #{lib}\n")
|
||||
file.printf(" PATHS\n")
|
||||
if not pkgconfig.empty?
|
||||
file.printf(" ${_#{package}LinkDir}\n")
|
||||
end
|
||||
file.printf(" /usr/lib\n")
|
||||
file.printf(" /usr/local/lib\n")
|
||||
file.printf(" /opt/local/lib\n")
|
||||
file.printf(" /sw/lib\n")
|
||||
file.printf(" )\n")
|
||||
end
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
libs.split(" ").each do |lib|
|
||||
file.printf(" if (#{lib.upcase}_LIBRARY)\n")
|
||||
file.printf(" set(#{lib.upcase}_FOUND TRUE)\n")
|
||||
file.printf(" endif (#{lib.upcase}_LIBRARY)\n")
|
||||
end
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf(" set(#{cmakeIncDirNames}\n")
|
||||
file.printf(" ${#{cmakeIncDirName}}\n")
|
||||
file.printf(" )\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
|
||||
libs.split(" ").each do |lib|
|
||||
file.printf(" if (#{lib.upcase}_FOUND)\n")
|
||||
file.printf(" set(#{cmakeLibNames}\n")
|
||||
file.printf(" ${#{cmakeLibNames}}\n")
|
||||
file.printf(" ${#{lib.upcase}_LIBRARY}\n")
|
||||
file.printf(" )\n")
|
||||
file.printf(" endif (#{lib.upcase}_FOUND)\n")
|
||||
end
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf(" if (#{cmakeIncDirNames} AND #{cmakeLibNames})\n")
|
||||
file.printf(" set(#{cmakeFoundName} TRUE)\n")
|
||||
file.printf(" endif (#{cmakeIncDirNames} AND #{cmakeLibNames})\n\n")
|
||||
|
||||
file.printf(" if (#{cmakeFoundName})\n")
|
||||
file.printf(" if (NOT #{cmakeQuietName})\n")
|
||||
file.printf(" message(STATUS \"Found #{package}: ${#{cmakeLibNames}}\")\n")
|
||||
file.printf(" endif (NOT #{cmakeQuietName})\n")
|
||||
file.printf(" else (#{cmakeFoundName})\n")
|
||||
file.printf(" if (#{cmakeRequiredName})\n")
|
||||
file.printf(" message(FATAL_ERROR \"Could not find #{package}\")\n")
|
||||
file.printf(" endif (#{cmakeRequiredName})\n")
|
||||
file.printf(" endif (#{cmakeFoundName})\n\n")
|
||||
|
||||
|
||||
file.printf(" # show the #{cmakeIncDirNames} and #{cmakeLibNames} variables only in the advanced view\n")
|
||||
file.printf(" mark_as_advanced(#{cmakeIncDirNames} #{cmakeLibNames})\n\n")
|
||||
|
||||
file.printf("endif (#{cmakeLibNames} AND #{cmakeIncDirNames})\n\n")
|
||||
|
||||
printf("Done, generated Find#{package}.cmake\n")
|
||||
|
135
cmake/Scripts/generate_lib_file
Normal file
135
cmake/Scripts/generate_lib_file
Normal file
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# simple script to generate CMakeLists.txt for wengophone libs
|
||||
#
|
||||
# usage: generate_lib_file
|
||||
# then you will be prompted to enter the required parameters
|
||||
#
|
||||
#####################################################################
|
||||
#
|
||||
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
print("Name of project: ")
|
||||
project=gets.chomp
|
||||
|
||||
printf("\n")
|
||||
|
||||
print("Other projects to includes (e.g. \"owutil tinyxml\", leave emtpy to skip): ")
|
||||
otherprojects=gets.chomp
|
||||
|
||||
printf("\n")
|
||||
|
||||
print("Defininitions (leave empty to skip): ")
|
||||
definitions=gets.chomp
|
||||
|
||||
cmakePublicIncDirName = project.upcase+"_PUBLIC_INCLUDE_DIRS"
|
||||
cmakePrivateIncDirName = project.upcase+"_PRIVATE_INCLUDE_DIRS"
|
||||
cmakeLibName = project.upcase+"_LIBRARY"
|
||||
cmakeLibNames = project.upcase+"_LINK_LIBRARIES"
|
||||
cmakePublicDefsName = project.upcase+"_PUBLIC_DEFINITIONS"
|
||||
cmakePrivateDefsName = project.upcase+"_PRIVATE_DEFINITIONS"
|
||||
|
||||
file=File.new("CMakeLists.txt", "w+")
|
||||
|
||||
file.printf("project(#{project})\n")
|
||||
file.printf("\n")
|
||||
file.printf("# needed include directories to build #{project}\n")
|
||||
file.printf("# saves the variable in internal cache for later use\n")
|
||||
file.printf("set(#{cmakePublicIncDirName}\n")
|
||||
file.printf(" ${CMAKE_CURRENT_SOURCE_DIR}\n")
|
||||
file.printf(" ${CMAKE_CURRENT_SOURCE_DIR}/include\n")
|
||||
file.printf(" CACHE INTERNAL \"#{project} public include directories\"\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("set(#{cmakePrivateIncDirName}\n")
|
||||
otherprojects.split(" ").each do |otherproject|
|
||||
file.printf(" ${#{otherproject.upcase}_PUBLIC_INCLUDE_DIRS}\n")
|
||||
end
|
||||
file.printf(" ${CMAKE_CURRENT_BINARY_DIR}\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("set(#{cmakeLibName}\n")
|
||||
file.printf(" #{project}\n")
|
||||
file.printf(" CACHE INTERNAL \"#{project} library\"\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("# #{project} lib and dependencies\n")
|
||||
file.printf("set(#{cmakeLibNames}\n")
|
||||
file.printf(" #{cmakeLibName}\n")
|
||||
otherprojects.split(" ").each do |otherproject|
|
||||
file.printf(" ${#{otherproject.upcase}_LIBRARIES}\n")
|
||||
end
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
if not definitions.empty?
|
||||
file.printf("set(#{cmakePublicDefsName}\n")
|
||||
file.printf(" #{definitions}\n")
|
||||
file.printf(" CACHE INTERNAL \"#{project} public definitions\"\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("set(#{cmakePrivateDefsName}\n")
|
||||
file.printf(" #{definitions}\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
end
|
||||
|
||||
file.printf("set(#{project}_SRCS\n")
|
||||
file.printf(" files.c\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("include_directories(\n")
|
||||
file.printf(" ${#{cmakePublicIncDirName}}\n")
|
||||
file.printf(" ${#{cmakePrivateIncDirName}}\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
if not definitions.empty?
|
||||
file.printf("add_definitions(\n")
|
||||
file.printf(" ${#{cmakePublicDefsName}}\n")
|
||||
file.printf(" ${#{cmakePrivateDefsName}}\n")
|
||||
file.printf(")\n")
|
||||
|
||||
file.printf("\n")
|
||||
end
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("add_library(${#{cmakeLibName}} STATIC ${#{project}_SRCS})\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
file.printf("target_link_libraries(${#{cmakeLibNames}})\n")
|
||||
|
||||
file.printf("\n")
|
||||
|
||||
printf("Generated CMakeLists.txt for #{project}\n")
|
||||
|
9
config.h.cmake
Normal file
9
config.h.cmake
Normal file
|
@ -0,0 +1,9 @@
|
|||
#cmakedefine PACKAGE "${APPLICATION_NAME}"
|
||||
#cmakedefine VERSION "${APPLICATION_VERSION}"
|
||||
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
|
||||
#cmakedefine DATADIR "${SHARE_INSTALL_PREFIX}"
|
||||
#cmakedefine LIBDIR "${LIB_INSTALL_DIR}"
|
||||
#cmakedefine PLUGINDIR "${PLUGIN_INSTALL_DIR}"
|
||||
#cmakedefine SYSCONFDIR "${SYSCONF_INSTALL_DIR}"
|
||||
|
||||
#cmakedefine WITH_LOG4C 1
|
6
config/CMakeLists.txt
Normal file
6
config/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
INSTALL(
|
||||
FILES
|
||||
csync_log.conf
|
||||
DESTINATION
|
||||
${DATA_INSTALL_PREFIX}
|
||||
)
|
7
config/csync.conf
Normal file
7
config/csync.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
[global]
|
||||
|
||||
# max diff time between two recplicas in seconds
|
||||
max_diff_time = 10
|
||||
|
||||
# max directory depth recursion
|
||||
max_depth = 50
|
29
config/csync_log.conf
Normal file
29
config/csync_log.conf
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE log4c SYSTEM "">
|
||||
|
||||
<log4c version="1.2.1">
|
||||
|
||||
<config>
|
||||
<bufsize>0</bufsize>
|
||||
<debug level="0"/>
|
||||
<nocleanup>0</nocleanup>
|
||||
</config>
|
||||
|
||||
<!-- root category ========================================= -->
|
||||
<category name="root" priority="none"/>
|
||||
<category name="csync.api" priority="notice" appender="stderr"/>
|
||||
<category name="csync.journal" priority="notice" appender="stderr"/>
|
||||
<category name="csync.lock" priority="notice" appender="stderr"/>
|
||||
<category name="csync.updater" priority="notice" appender="stderr"/>
|
||||
<category name="csync.propagator" priority="notice" appender="stderr"/>
|
||||
<category name="csync.reconciler" priority="notice" appender="stderr"/>
|
||||
|
||||
<!-- default appenders ===================================== -->
|
||||
<appender name="stdout" type="stream" layout="basic"/>
|
||||
<appender name="stderr" type="stream" layout="dated"/>
|
||||
<appender name="syslog" type="syslog" layout="basic"/>
|
||||
|
||||
<!-- default layouts ======================================= -->
|
||||
<layout name="basic" type="basic"/>
|
||||
<layout name="dated" type="dated"/>
|
||||
</log4c>
|
21
doc/CMakeLists.txt
Normal file
21
doc/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
#
|
||||
# Build the documentation
|
||||
#
|
||||
include("${CMAKE_MODULE_PATH}/UseDoxygen.cmake" OPTIONAL)
|
||||
|
||||
#if (DOXYGEN_FOUND)
|
||||
# set(html_FILES
|
||||
# html/block_title_bottom.png
|
||||
# html/block_title_mid.png
|
||||
# html/block_title_top.png
|
||||
# html/csync.css
|
||||
# html/print.css
|
||||
# html/top.jpg
|
||||
# html/top-left.jpg
|
||||
# html/top-right.jpg
|
||||
# )
|
||||
# foreach(_html_FILE ${html_FILES})
|
||||
# configure_file(${_html_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${_html_FILE} COPYONLY)
|
||||
# endforeach(_html_FILE ${html_FILES})
|
||||
#endif (DOXYGEN_FOUND)
|
||||
|
23
doc/codeheader.c
Normal file
23
doc/codeheader.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
|
26
doc/codeheader.h
Normal file
26
doc/codeheader.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_X_H
|
||||
#define _CSYNC_X_H
|
||||
|
||||
#endif /* _CSYNC_X_H */
|
1329
doc/doxy.config.in
Normal file
1329
doc/doxy.config.in
Normal file
File diff suppressed because it is too large
Load diff
5
iniparser/AUTHORS
Normal file
5
iniparser/AUTHORS
Normal file
|
@ -0,0 +1,5 @@
|
|||
Author for this package:
|
||||
Nicolas Devillard <ndevilla@free.fr>
|
||||
|
||||
Many thanks to the many people who contributed ideas, code, suggestions,
|
||||
corrections, enhancements.
|
12
iniparser/INSTALL
Normal file
12
iniparser/INSTALL
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
iniParser installation instructions
|
||||
-----------------------------------
|
||||
|
||||
1. Modify the Makefile to suit your environment.
|
||||
2. Type 'make' to make the library.
|
||||
3. Type 'make check' to make the test program.
|
||||
4. Type 'test/iniexample' to launch the test program.
|
||||
|
||||
Enjoy!
|
||||
N. Devillard
|
||||
Tue Jan 14 11:52:03 CET 2003
|
21
iniparser/LICENSE
Normal file
21
iniparser/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) 2000 by Nicolas Devillard.
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
11
iniparser/README
Normal file
11
iniparser/README
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
Welcome to iniParser!
|
||||
|
||||
This modules offers parsing of ini files from the C level.
|
||||
See a complete documentation in HTML format, from this directory
|
||||
open the file html/index.html with any HTML-capable browser.
|
||||
|
||||
Enjoy!
|
||||
|
||||
N.Devillard
|
||||
Thu Nov 17 12:31:42 CET 2005
|
310
iniparser/html/doxygen.css
Normal file
310
iniparser/html/doxygen.css
Normal file
|
@ -0,0 +1,310 @@
|
|||
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
BODY,TD {
|
||||
font-size: 90%;
|
||||
}
|
||||
H1 {
|
||||
text-align: center;
|
||||
font-size: 160%;
|
||||
}
|
||||
H2 {
|
||||
font-size: 120%;
|
||||
}
|
||||
H3 {
|
||||
font-size: 100%;
|
||||
}
|
||||
CAPTION { font-weight: bold }
|
||||
DIV.qindex {
|
||||
width: 100%;
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.nav {
|
||||
width: 100%;
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 140%;
|
||||
}
|
||||
DIV.navtab {
|
||||
background-color: #e8eef2;
|
||||
border: 1px solid #84b0c7;
|
||||
text-align: center;
|
||||
margin: 2px;
|
||||
margin-right: 15px;
|
||||
padding: 2px;
|
||||
}
|
||||
TD.navtab {
|
||||
font-size: 70%;
|
||||
}
|
||||
A.qindex {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D;
|
||||
}
|
||||
A.qindex:visited {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
color: #1A419D
|
||||
}
|
||||
A.qindex:hover {
|
||||
text-decoration: none;
|
||||
background-color: #ddddff;
|
||||
}
|
||||
A.qindexHL {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
border: 1px double #9295C2;
|
||||
}
|
||||
A.qindexHL:hover {
|
||||
text-decoration: none;
|
||||
background-color: #6666cc;
|
||||
color: #ffffff;
|
||||
}
|
||||
A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff }
|
||||
A.el { text-decoration: none; font-weight: bold }
|
||||
A.elRef { font-weight: bold }
|
||||
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
|
||||
A.codeRef:link { font-weight: normal; color: #0000FF}
|
||||
A.codeRef:visited { font-weight: normal; color: #0000FF}
|
||||
A:hover { text-decoration: none; background-color: #f2f2ff }
|
||||
DL.el { margin-left: -1cm }
|
||||
.fragment {
|
||||
font-family: Fixed, monospace;
|
||||
font-size: 95%;
|
||||
}
|
||||
PRE.fragment {
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
|
||||
TD.md { background-color: #F4F4FB; font-weight: bold; }
|
||||
TD.mdPrefix {
|
||||
background-color: #F4F4FB;
|
||||
color: #606060;
|
||||
font-size: 80%;
|
||||
}
|
||||
TD.mdname1 { background-color: #F4F4FB; font-weight: bold; color: #602020; }
|
||||
TD.mdname { background-color: #F4F4FB; font-weight: bold; color: #602020; width: 600px; }
|
||||
DIV.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
|
||||
BODY {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
TD.indexkey {
|
||||
background-color: #e8eef2;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TD.indexvalue {
|
||||
background-color: #e8eef2;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px;
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
TR.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
P.formulaDsp { text-align: center; }
|
||||
IMG.formulaDsp { }
|
||||
IMG.formulaInl { vertical-align: middle; }
|
||||
SPAN.keyword { color: #008000 }
|
||||
SPAN.keywordtype { color: #604020 }
|
||||
SPAN.keywordflow { color: #e08000 }
|
||||
SPAN.comment { color: #800000 }
|
||||
SPAN.preprocessor { color: #806020 }
|
||||
SPAN.stringliteral { color: #002080 }
|
||||
SPAN.charliteral { color: #008080 }
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #F4F4FB;
|
||||
}
|
||||
.mdRow {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
.mdescLeft {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.mdescRight {
|
||||
padding: 0px 8px 4px 8px;
|
||||
font-size: 80%;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplItemRight {
|
||||
padding: 1px 8px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: none;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.memTemplParams {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-top-style: solid;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
color: #606060;
|
||||
background-color: #FAFAFA;
|
||||
font-size: 80%;
|
||||
}
|
||||
.search { color: #003399;
|
||||
font-weight: bold;
|
||||
}
|
||||
FORM.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
INPUT.search { font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #e8eef2;
|
||||
}
|
||||
TD.tiny { font-size: 75%;
|
||||
}
|
||||
a {
|
||||
color: #1A41A8;
|
||||
}
|
||||
a:visited {
|
||||
color: #2A3798;
|
||||
}
|
||||
.dirtab { padding: 4px;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #84b0c7;
|
||||
}
|
||||
TH.dirtab { background: #e8eef2;
|
||||
font-weight: bold;
|
||||
}
|
||||
HR { height: 1px;
|
||||
border: none;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
BIN
iniparser/html/doxygen.png
Normal file
BIN
iniparser/html/doxygen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
40
iniparser/html/globals_func.html
Normal file
40
iniparser/html/globals_func.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="author" content="ndevilla@free.fr">
|
||||
<meta name="keywords" content="ini file, config file, parser, C library">
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<title>iniparser 2.x</title>
|
||||
</head>
|
||||
|
||||
<body text="#000000" bgcolor="#ffffff">
|
||||
|
||||
|
||||
|
||||
<!-- Generated by Doxygen 1.4.6 -->
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li><a href="globals.html"><span>All</span></a></li>
|
||||
<li id="current"><a href="globals_func.html"><span>Functions</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>iniparser_dump()
|
||||
: <a class="el" href="iniparser_8h.html#046436b3489cd8854ba8e29109250324">iniparser.h</a><li>iniparser_dump_ini()
|
||||
: <a class="el" href="iniparser_8h.html#ece0e32de371c9e9592d8333f816dfac">iniparser.h</a><li>iniparser_find_entry()
|
||||
: <a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser.h</a><li>iniparser_freedict()
|
||||
: <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser.h</a><li>iniparser_getboolean()
|
||||
: <a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser.h</a><li>iniparser_getdouble()
|
||||
: <a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser.h</a><li>iniparser_getint()
|
||||
: <a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser.h</a><li>iniparser_getnsec()
|
||||
: <a class="el" href="iniparser_8h.html#0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser.h</a><li>iniparser_getsecname()
|
||||
: <a class="el" href="iniparser_8h.html#393212be805f395bbfdeb1bafa8bb72a">iniparser.h</a><li>iniparser_getstr()
|
||||
: <a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser.h</a><li>iniparser_getstring()
|
||||
: <a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser.h</a><li>iniparser_load()
|
||||
: <a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser.h</a><li>iniparser_setstr()
|
||||
: <a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser.h</a><li>iniparser_unset()
|
||||
: <a class="el" href="iniparser_8h.html#7b1a7f2492a35043867fa801b8f21e52">iniparser.h</a></ul>
|
||||
|
||||
</body>
|
||||
</html>
|
148
iniparser/html/index.html
Normal file
148
iniparser/html/index.html
Normal file
|
@ -0,0 +1,148 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="author" content="ndevilla@free.fr">
|
||||
<meta name="keywords" content="ini file, config file, parser, C library">
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<title>iniparser 2.x</title>
|
||||
</head>
|
||||
|
||||
<body text="#000000" bgcolor="#ffffff">
|
||||
|
||||
|
||||
|
||||
<!-- Generated by Doxygen 1.4.6 -->
|
||||
<h1>iniparser documentation</h1>
|
||||
<p>
|
||||
<h3 align="center">2.x </h3><hr>
|
||||
<h2><a class="anchor" name="welcome">
|
||||
Introduction</a></h2>
|
||||
iniParser is a simple C library offering ini file parsing services. The library is pretty small (less than 1500 lines of C) and robust, and does not depend on any other external library to compile. It is written in ANSI C and should compile anywhere without difficulty.<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="inidef">
|
||||
What is an ini file?</a></h2>
|
||||
An ini file is an ASCII file describing simple parameters (character strings, integers, floating-point values or booleans) in an explicit format, easy to use and modify for users.<p>
|
||||
An ini file is segmented into Sections, declared by the following syntax:<p>
|
||||
<div class="fragment"><pre class="fragment"> [Section Name]
|
||||
</pre></div><p>
|
||||
i.e. the section name enclosed in square brackets, alone on a line. Sections names are allowed to contain any character but square brackets or linefeeds. Slashes (/) are also reserved for hierarchical sections (see below).<p>
|
||||
In any section are zero or more variables, declared with the following syntax:<p>
|
||||
<div class="fragment"><pre class="fragment"> Key = value ; comment
|
||||
</pre></div><p>
|
||||
The key is any string (possibly containing blanks). The value is any character on the right side of the equal sign. Values can be given enclosed with quotes. If no quotes are present, the value is understood as containing all characters between the first and the last non-blank characters. The following declarations are identical:<p>
|
||||
<div class="fragment"><pre class="fragment"> Hello = "this is a long string value" ; comment
|
||||
Hello = this is a long string value ; comment
|
||||
</pre></div><p>
|
||||
The semicolon and comment at the end of the line are optional. If there is a comment, it starts from the first character after the semicolon up to the end of the line.<p>
|
||||
Comments in an ini file are:<p>
|
||||
<ul>
|
||||
<li>Lines starting with a hash sign</li><li>Blank lines (only blanks or tabs)</li><li>Comments given on value lines after the semicolon (if present)</li></ul>
|
||||
<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="install">
|
||||
Compiling/installing the library</a></h2>
|
||||
Edit the Makefile to indicate the C compiler you want to use, the options to provide to compile ANSI C, and possibly the options to pass to the <code>ar</code> program on your machine to build a library (.a) from a set of object (.o) files.<p>
|
||||
Defaults are set for the gcc compiler and the standard ar library builder.<p>
|
||||
Type 'make', that should do it.<p>
|
||||
To use the library in your programs, add the following line on top of your module:<p>
|
||||
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #include "<a class="code" href="iniparser_8h.html">iniparser.h</a>"</span>
|
||||
</pre></div><p>
|
||||
And link your program with the iniparser library by adding <code>-liniparser</code>.a to the compile line.<p>
|
||||
See the file test/initest.c for an example.<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="reference">
|
||||
Library reference</a></h2>
|
||||
The library is completely documented in its header file. On-line documentation has been generated and can be consulted here:<p>
|
||||
<ul>
|
||||
<li><a class="el" href="iniparser_8h.html">iniparser.h</a></li></ul>
|
||||
<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="usage">
|
||||
Using the parser</a></h2>
|
||||
Comments are discarded by the parser. Then sections are identified, and in each section a new entry is created for every keyword found. The keywords are stored with the following syntax:<p>
|
||||
<div class="fragment"><pre class="fragment"> [Section]
|
||||
Keyword = value ; comment
|
||||
</pre></div><p>
|
||||
is converted to the following key pair:<p>
|
||||
<div class="fragment"><pre class="fragment"> ("section:keyword", "value")
|
||||
</pre></div><p>
|
||||
This means that if you want to retrieve the value that was stored in the section called <code>Pizza</code>, in the keyword <code>Cheese</code>, you would make a request to the dictionary for <code>"pizza:cheese"</code>. All section and keyword names are converted to lowercase before storage in the structure. The value side is conserved as it has been parsed, though.<p>
|
||||
Section names are also stored in the structure. They are stored using as key the section name, and a NULL associated value. They can be queried through <a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser_find_entry()</a>.<p>
|
||||
To launch the parser, simply use the function called <a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load()</a>, which takes an input file name and returns a newly allocated <em>dictionary</em> structure. This latter object should remain opaque to the user and only accessed through the following accessor functions:<p>
|
||||
<ul>
|
||||
<li><a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr()</a></li><li><a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser_getint()</a></li><li><a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser_getdouble()</a></li><li><a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean()</a></li></ul>
|
||||
<p>
|
||||
Finally, discard this structure using <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict()</a>.<p>
|
||||
All values parsed from the ini file are stored as strings. The getint, getdouble and getboolean accessors are just converting these strings to the requested type on the fly, but you could basically perform this conversion by yourself after having called the getstr accessor.<p>
|
||||
Notice that the <a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean()</a> function will return an integer (0 or 1), trying to make sense of what was found in the file. Strings starting with "y", "Y", "t", "T" or "1" are considered true values (return 1), strings starting with "n", "N", "f", "F", "0" are considered false (return 0). This allows flexible handling of boolean answers.<p>
|
||||
If you want to add extra information into the structure that was not present in the ini file, you can use <a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser_setstr()</a> to insert a string.<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="implementation">
|
||||
A word about the implementation</a></h2>
|
||||
The dictionary structure is a pretty simple dictionary implementation which might find some uses in other applications. If you are curious, look into the source.<p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="hierarchical">
|
||||
Hierarchical ini files</a></h2>
|
||||
ini files are nice to present informations to the user in a readable format, but lack a very useful feature: the possibility of organizing data in a hierarchical (tree-like) fashion. The following convention can be used to make ini files obtain this second dimension:<p>
|
||||
A section depends on another section if it contains its name as a prefix, separated by slashes (/). For example: we have 2 main sections in the ini file. The first one is called <code>Pizza</code> and has two child subsections called <code>Cheese</code> and <code>Ham</code>. The second main section in the ini file is called <code>Wine</code> and has two child subsections called <code>Year</code> and <code>Grape</code>. As a tree, this could appear as:<p>
|
||||
<div class="fragment"><pre class="fragment"> |
|
||||
+-- Pizza
|
||||
| +-- Cheese
|
||||
| +-- Ham
|
||||
+-- Wine
|
||||
+--- Year
|
||||
+--- Grape
|
||||
</pre></div><p>
|
||||
In an ini file, that would be converted to:<p>
|
||||
<div class="fragment"><pre class="fragment"> [Pizza]
|
||||
|
||||
[Pizza/Cheese]
|
||||
Name = Gorgonzola ;
|
||||
Origin = Italy ;
|
||||
|
||||
[Pizza/Ham]
|
||||
Name = Parma ;
|
||||
Origin = Italy ;
|
||||
|
||||
[Wine]
|
||||
|
||||
[Wine/Year]
|
||||
Value = 1998 ;
|
||||
|
||||
[Wine/Grape]
|
||||
Name = Cabernet Sauvignon ;
|
||||
Origin = Chile ;
|
||||
</pre></div><p>
|
||||
This proposal is actually more related to the way people write ini files, more than the parser presented here. But it is certainly a useful way of making tree-like data declarations without going through painful formats like XML.<p>
|
||||
Accessing the above tree would give something like (error checking removed for clarity sake):<p>
|
||||
<div class="fragment"><pre class="fragment"> dictionary * d ;
|
||||
|
||||
d = <a class="code" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load</a>(<span class="stringliteral">"example.ini"</span>);
|
||||
|
||||
printf(<span class="stringliteral">"cheese name is %s\n"</span>, <a class="code" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a>(d, <span class="stringliteral">"pizza/cheese:name"</span>));
|
||||
printf(<span class="stringliteral">"grape name is %s\n"</span>, <a class="code" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a>(d, <span class="stringliteral">"wine/grape:name"</span>));
|
||||
|
||||
<a class="code" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict</a>(d);
|
||||
</pre></div><p>
|
||||
The whole ini file above is represented in the dictionary as the following list of pairs:<p>
|
||||
<div class="fragment"><pre class="fragment"> key value
|
||||
|
||||
"pizza" NULL
|
||||
"pizza/cheese" NULL
|
||||
"pizza/cheese:name" "Gorgonzola"
|
||||
"pizza/cheese:origin" "Italy"
|
||||
"pizza/ham" NULL
|
||||
"pizza/ham:name" "Parma"
|
||||
"pizza/ham:origin" "Italy"
|
||||
"wine" NULL
|
||||
"wine/year" NULL
|
||||
"wine/year:value" "1998"
|
||||
"wine/grape" NULL
|
||||
"wine/grape:name" "Cabernet Sauvignon"
|
||||
"wine/grape:origin" "Chile"
|
||||
</pre></div><p>
|
||||
<hr>
|
||||
<h2><a class="anchor" name="authors">
|
||||
Authors</a></h2>
|
||||
Nicolas Devillard (ndevilla AT free DOT fr).
|
||||
</body>
|
||||
</html>
|
741
iniparser/html/iniparser_8h.html
Normal file
741
iniparser/html/iniparser_8h.html
Normal file
|
@ -0,0 +1,741 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="author" content="ndevilla@free.fr">
|
||||
<meta name="keywords" content="ini file, config file, parser, C library">
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<title>iniparser 2.x</title>
|
||||
</head>
|
||||
|
||||
<body text="#000000" bgcolor="#ffffff">
|
||||
|
||||
|
||||
|
||||
<!-- Generated by Doxygen 1.4.6 -->
|
||||
<h1>iniparser.h File Reference</h1>Parser for ini files. <a href="#_details">More...</a>
|
||||
<p>
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td></td></tr>
|
||||
<tr><td colspan="2"><br><h2>Functions</h2></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#0b5d6cdc7587e2d27a30f5cdc4a91931">iniparser_getnsec</a> (dictionary *d)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get number of sections in a dictionary. <a href="#0b5d6cdc7587e2d27a30f5cdc4a91931"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">char * </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#393212be805f395bbfdeb1bafa8bb72a">iniparser_getsecname</a> (dictionary *d, int n)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get name for section n in a dictionary. <a href="#393212be805f395bbfdeb1bafa8bb72a"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#ece0e32de371c9e9592d8333f816dfac">iniparser_dump_ini</a> (dictionary *d, FILE *f)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Save a dictionary to a loadable ini file. <a href="#ece0e32de371c9e9592d8333f816dfac"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#046436b3489cd8854ba8e29109250324">iniparser_dump</a> (dictionary *d, FILE *f)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Dump a dictionary to an opened file pointer. <a href="#046436b3489cd8854ba8e29109250324"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">char * </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#587eafb48937fdee8ae414ad7a666db8">iniparser_getstr</a> (dictionary *d, const char *key)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get the string associated to a key, return NULL if not found. <a href="#587eafb48937fdee8ae414ad7a666db8"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">char * </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser_getstring</a> (dictionary *d, const char *key, char *def)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get the string associated to a key. <a href="#7894f8480e1f254d4a1b4a31bdc51b46"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#694eb1110f4200db8648820a0bb405fa">iniparser_getint</a> (dictionary *d, const char *key, int notfound)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get the string associated to a key, convert to an int. <a href="#694eb1110f4200db8648820a0bb405fa"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">double </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#480d35322f1252344cf2246ac21ee559">iniparser_getdouble</a> (dictionary *d, char *key, double notfound)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get the string associated to a key, convert to a double. <a href="#480d35322f1252344cf2246ac21ee559"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#eb93c13fcbb75efaa396f53bfd73ff4d">iniparser_getboolean</a> (dictionary *d, const char *key, int notfound)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Get the string associated to a key, convert to a boolean. <a href="#eb93c13fcbb75efaa396f53bfd73ff4d"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#605a88057bac4c3249513fc588421c32">iniparser_setstr</a> (dictionary *ini, char *entry, char *val)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Set an entry in a dictionary. <a href="#605a88057bac4c3249513fc588421c32"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#7b1a7f2492a35043867fa801b8f21e52">iniparser_unset</a> (dictionary *ini, char *entry)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Delete an entry in a dictionary. <a href="#7b1a7f2492a35043867fa801b8f21e52"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">int </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#3d67c98bbc0cb5239f024ad54bdc63f1">iniparser_find_entry</a> (dictionary *ini, char *entry)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Finds out if a given entry exists in a dictionary. <a href="#3d67c98bbc0cb5239f024ad54bdc63f1"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">dictionary * </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#b0be559bfb769224b3f1b75e26242a67">iniparser_load</a> (const char *ininame)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Parse an ini file and return an allocated dictionary object. <a href="#b0be559bfb769224b3f1b75e26242a67"></a><br></td></tr>
|
||||
<tr><td class="memItemLeft" nowrap align="right" valign="top">void </td><td class="memItemRight" valign="bottom"><a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict</a> (dictionary *d)</td></tr>
|
||||
|
||||
<tr><td class="mdescLeft"> </td><td class="mdescRight">Free all memory associated to an ini dictionary. <a href="#90549ee518523921886b74454ff872eb"></a><br></td></tr>
|
||||
</table>
|
||||
<hr><a name="_details"></a><h2>Detailed Description</h2>
|
||||
Parser for ini files.
|
||||
<p>
|
||||
<dl compact><dt><b>Author:</b></dt><dd>N. Devillard </dd></dl>
|
||||
<dl compact><dt><b>Date:</b></dt><dd>Mar 2000 </dd></dl>
|
||||
<dl compact><dt><b>Version:</b></dt><dd><dl compact><dt><b>Revision</b></dt><dd>1.23 </dd></dl>
|
||||
</dd></dl>
|
||||
<hr><h2>Function Documentation</h2>
|
||||
<a class="anchor" name="046436b3489cd8854ba8e29109250324"></a><!-- doxytag: member="iniparser.h::iniparser_dump" ref="046436b3489cd8854ba8e29109250324" args="(dictionary *d, FILE *f)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">void iniparser_dump </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>FILE * </td>
|
||||
<td class="mdname" nowrap> <em>f</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Dump a dictionary to an opened file pointer.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to dump. </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>f</em> </td><td>Opened file pointer to dump to. </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
|
||||
This function prints out the contents of a dictionary, one element by line, onto the provided file pointer. It is OK to specify <code>stderr</code> or <code>stdout</code> as output files. This function is meant for debugging purposes mostly. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="ece0e32de371c9e9592d8333f816dfac"></a><!-- doxytag: member="iniparser.h::iniparser_dump_ini" ref="ece0e32de371c9e9592d8333f816dfac" args="(dictionary *d, FILE *f)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">void iniparser_dump_ini </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>FILE * </td>
|
||||
<td class="mdname" nowrap> <em>f</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Save a dictionary to a loadable ini file.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to dump </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>f</em> </td><td>Opened file pointer to dump to </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
|
||||
This function dumps a given dictionary into a loadable ini file. It is Ok to specify <code>stderr</code> or <code>stdout</code> as output files. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="3d67c98bbc0cb5239f024ad54bdc63f1"></a><!-- doxytag: member="iniparser.h::iniparser_find_entry" ref="3d67c98bbc0cb5239f024ad54bdc63f1" args="(dictionary *ini, char *entry)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">int iniparser_find_entry </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>ini</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>entry</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Finds out if a given entry exists in a dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>ini</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>entry</em> </td><td>Name of the entry to look for </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>integer 1 if entry exists, 0 otherwise</dd></dl>
|
||||
Finds out if a given entry exists in the dictionary. Since sections are stored as keys with NULL associated values, this is the only way of querying for the presence of sections in a dictionary. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="90549ee518523921886b74454ff872eb"></a><!-- doxytag: member="iniparser.h::iniparser_freedict" ref="90549ee518523921886b74454ff872eb" args="(dictionary *d)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">void iniparser_freedict </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname1" valign="top" nowrap> <em>d</em> </td>
|
||||
<td class="md" valign="top"> ) </td>
|
||||
<td class="md" nowrap></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Free all memory associated to an ini dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to free </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
|
||||
Free all memory associated to an ini dictionary. It is mandatory to call this function before the dictionary object gets out of the current context. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="eb93c13fcbb75efaa396f53bfd73ff4d"></a><!-- doxytag: member="iniparser.h::iniparser_getboolean" ref="eb93c13fcbb75efaa396f53bfd73ff4d" args="(dictionary *d, const char *key, int notfound)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">int iniparser_getboolean </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>const char * </td>
|
||||
<td class="mdname" nowrap> <em>key</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>int </td>
|
||||
<td class="mdname" nowrap> <em>notfound</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get the string associated to a key, convert to a boolean.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>key</em> </td><td>Key string to look for </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>notfound</em> </td><td>Value to return in case of error </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>integer</dd></dl>
|
||||
This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.<p>
|
||||
A true boolean is found if one of the following is matched:<p>
|
||||
<ul>
|
||||
<li>A string starting with 'y'</li><li>A string starting with 'Y'</li><li>A string starting with 't'</li><li>A string starting with 'T'</li><li>A string starting with '1'</li></ul>
|
||||
<p>
|
||||
A false boolean is found if one of the following is matched:<p>
|
||||
<ul>
|
||||
<li>A string starting with 'n'</li><li>A string starting with 'N'</li><li>A string starting with 'f'</li><li>A string starting with 'F'</li><li>A string starting with '0'</li></ul>
|
||||
<p>
|
||||
The notfound value returned if no boolean is identified, does not necessarily have to be 0 or 1. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="480d35322f1252344cf2246ac21ee559"></a><!-- doxytag: member="iniparser.h::iniparser_getdouble" ref="480d35322f1252344cf2246ac21ee559" args="(dictionary *d, char *key, double notfound)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">double iniparser_getdouble </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>key</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>double </td>
|
||||
<td class="mdname" nowrap> <em>notfound</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get the string associated to a key, convert to a double.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>key</em> </td><td>Key string to look for </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>notfound</em> </td><td>Value to return in case of error </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>double</dd></dl>
|
||||
This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="694eb1110f4200db8648820a0bb405fa"></a><!-- doxytag: member="iniparser.h::iniparser_getint" ref="694eb1110f4200db8648820a0bb405fa" args="(dictionary *d, const char *key, int notfound)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">int iniparser_getint </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>const char * </td>
|
||||
<td class="mdname" nowrap> <em>key</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>int </td>
|
||||
<td class="mdname" nowrap> <em>notfound</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get the string associated to a key, convert to an int.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>key</em> </td><td>Key string to look for </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>notfound</em> </td><td>Value to return in case of error </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>integer</dd></dl>
|
||||
This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the notfound value is returned.<p>
|
||||
Supported values for integers include the usual C notation so decimal, octal (starting with 0) and hexadecimal (starting with 0x) are supported. Examples:<p>
|
||||
<ul>
|
||||
<li>"42" -> 42</li><li>"042" -> 34 (octal -> decimal)</li><li>"0x42" -> 66 (hexa -> decimal)</li></ul>
|
||||
<p>
|
||||
Warning: the conversion may overflow in various ways. Conversion is totally outsourced to strtol(), see the associated man page for overflow handling.<p>
|
||||
Credits: Thanks to A. Becker for suggesting strtol() </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="0b5d6cdc7587e2d27a30f5cdc4a91931"></a><!-- doxytag: member="iniparser.h::iniparser_getnsec" ref="0b5d6cdc7587e2d27a30f5cdc4a91931" args="(dictionary *d)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">int iniparser_getnsec </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname1" valign="top" nowrap> <em>d</em> </td>
|
||||
<td class="md" valign="top"> ) </td>
|
||||
<td class="md" nowrap></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get number of sections in a dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to examine </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>int Number of sections found in dictionary</dd></dl>
|
||||
This function returns the number of sections found in a dictionary. The test to recognize sections is done on the string stored in the dictionary: a section name is given as "section" whereas a key is stored as "section:key", thus the test looks for entries that do not contain a colon.<p>
|
||||
This clearly fails in the case a section name contains a colon, but this should simply be avoided.<p>
|
||||
This function returns -1 in case of error. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="393212be805f395bbfdeb1bafa8bb72a"></a><!-- doxytag: member="iniparser.h::iniparser_getsecname" ref="393212be805f395bbfdeb1bafa8bb72a" args="(dictionary *d, int n)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">char* iniparser_getsecname </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>int </td>
|
||||
<td class="mdname" nowrap> <em>n</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get name for section n in a dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to examine </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>n</em> </td><td>Section number (from 0 to nsec-1). </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>Pointer to char string</dd></dl>
|
||||
This function locates the n-th section in a dictionary and returns its name as a pointer to a string statically allocated inside the dictionary. Do not free or modify the returned string!<p>
|
||||
This function returns NULL in case of error. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="587eafb48937fdee8ae414ad7a666db8"></a><!-- doxytag: member="iniparser.h::iniparser_getstr" ref="587eafb48937fdee8ae414ad7a666db8" args="(dictionary *d, const char *key)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">char* iniparser_getstr </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>const char * </td>
|
||||
<td class="mdname" nowrap> <em>key</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get the string associated to a key, return NULL if not found.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>key</em> </td><td>Key string to look for </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>pointer to statically allocated character string, or NULL.</dd></dl>
|
||||
This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, NULL is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it.<p>
|
||||
This function is only provided for backwards compatibility with previous versions of iniparser. It is recommended to use <a class="el" href="iniparser_8h.html#7894f8480e1f254d4a1b4a31bdc51b46">iniparser_getstring()</a> instead. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="7894f8480e1f254d4a1b4a31bdc51b46"></a><!-- doxytag: member="iniparser.h::iniparser_getstring" ref="7894f8480e1f254d4a1b4a31bdc51b46" args="(dictionary *d, const char *key, char *def)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">char* iniparser_getstring </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>d</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>const char * </td>
|
||||
<td class="mdname" nowrap> <em>key</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>def</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Get the string associated to a key.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>d</em> </td><td>Dictionary to search </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>key</em> </td><td>Key string to look for </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>def</em> </td><td>Default value to return if key not found. </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>pointer to statically allocated character string</dd></dl>
|
||||
This function queries a dictionary for a key. A key as read from an ini file is given as "section:key". If the key cannot be found, the pointer passed as 'def' is returned. The returned char pointer is pointing to a string allocated in the dictionary, do not free or modify it. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="b0be559bfb769224b3f1b75e26242a67"></a><!-- doxytag: member="iniparser.h::iniparser_load" ref="b0be559bfb769224b3f1b75e26242a67" args="(const char *ininame)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">dictionary* iniparser_load </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">const char * </td>
|
||||
<td class="mdname1" valign="top" nowrap> <em>ininame</em> </td>
|
||||
<td class="md" valign="top"> ) </td>
|
||||
<td class="md" nowrap></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Parse an ini file and return an allocated dictionary object.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>ininame</em> </td><td>Name of the ini file to read. </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>Pointer to newly allocated dictionary</dd></dl>
|
||||
This is the parser for ini files. This function is called, providing the name of the file to be read. It returns a dictionary object that should not be accessed directly, but through accessor functions instead.<p>
|
||||
The returned dictionary must be freed using <a class="el" href="iniparser_8h.html#90549ee518523921886b74454ff872eb">iniparser_freedict()</a>. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="605a88057bac4c3249513fc588421c32"></a><!-- doxytag: member="iniparser.h::iniparser_setstr" ref="605a88057bac4c3249513fc588421c32" args="(dictionary *ini, char *entry, char *val)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">int iniparser_setstr </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>ini</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>entry</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>val</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Set an entry in a dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>ini</em> </td><td>Dictionary to modify. </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>entry</em> </td><td>Entry to modify (entry name) </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>val</em> </td><td>New value to associate to the entry. </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>int 0 if Ok, -1 otherwise.</dd></dl>
|
||||
If the given entry can be found in the dictionary, it is modified to contain the provided value. If it cannot be found, -1 is returned. It is Ok to set val to NULL. </td>
|
||||
</tr>
|
||||
</table>
|
||||
<a class="anchor" name="7b1a7f2492a35043867fa801b8f21e52"></a><!-- doxytag: member="iniparser.h::iniparser_unset" ref="7b1a7f2492a35043867fa801b8f21e52" args="(dictionary *ini, char *entry)" --><p>
|
||||
<table class="mdTable" cellpadding="2" cellspacing="0">
|
||||
<tr>
|
||||
<td class="mdRow">
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td class="md" nowrap valign="top">void iniparser_unset </td>
|
||||
<td class="md" valign="top">( </td>
|
||||
<td class="md" nowrap valign="top">dictionary * </td>
|
||||
<td class="mdname" nowrap> <em>ini</em>, </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md" nowrap align="right"></td>
|
||||
<td class="md"></td>
|
||||
<td class="md" nowrap>char * </td>
|
||||
<td class="mdname" nowrap> <em>entry</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="md"></td>
|
||||
<td class="md">) </td>
|
||||
<td class="md" colspan="2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellspacing="5" cellpadding="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
<p>
|
||||
Delete an entry in a dictionary.
|
||||
<p>
|
||||
<dl compact><dt><b>Parameters:</b></dt><dd>
|
||||
<table border="0" cellspacing="2" cellpadding="0">
|
||||
<tr><td valign="top"></td><td valign="top"><em>ini</em> </td><td>Dictionary to modify </td></tr>
|
||||
<tr><td valign="top"></td><td valign="top"><em>entry</em> </td><td>Entry to delete (entry name) </td></tr>
|
||||
</table>
|
||||
</dl>
|
||||
<dl compact><dt><b>Returns:</b></dt><dd>void</dd></dl>
|
||||
If the given entry can be found, it is deleted from the dictionary. </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
19
iniparser/html/iniparser_8main.html
Normal file
19
iniparser/html/iniparser_8main.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta name="author" content="ndevilla@free.fr">
|
||||
<meta name="keywords" content="ini file, config file, parser, C library">
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<title>iniparser 2.x</title>
|
||||
</head>
|
||||
|
||||
<body text="#000000" bgcolor="#ffffff">
|
||||
|
||||
|
||||
|
||||
<!-- Generated by Doxygen 1.4.6 -->
|
||||
<h1>iniparser.main File Reference</h1><table border="0" cellpadding="0" cellspacing="0">
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
iniparser/html/tab_b.gif
Normal file
BIN
iniparser/html/tab_b.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 B |
BIN
iniparser/html/tab_l.gif
Normal file
BIN
iniparser/html/tab_l.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 706 B |
BIN
iniparser/html/tab_r.gif
Normal file
BIN
iniparser/html/tab_r.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
102
iniparser/html/tabs.css
Normal file
102
iniparser/html/tabs.css
Normal file
|
@ -0,0 +1,102 @@
|
|||
/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */
|
||||
|
||||
DIV.tabs
|
||||
{
|
||||
float : left;
|
||||
width : 100%;
|
||||
background : url("tab_b.gif") repeat-x bottom;
|
||||
margin-bottom : 4px;
|
||||
}
|
||||
|
||||
DIV.tabs UL
|
||||
{
|
||||
margin : 0px;
|
||||
padding-left : 10px;
|
||||
list-style : none;
|
||||
}
|
||||
|
||||
DIV.tabs LI, DIV.tabs FORM
|
||||
{
|
||||
display : inline;
|
||||
margin : 0px;
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
DIV.tabs FORM
|
||||
{
|
||||
float : right;
|
||||
}
|
||||
|
||||
DIV.tabs A
|
||||
{
|
||||
float : left;
|
||||
background : url("tab_r.gif") no-repeat right top;
|
||||
border-bottom : 1px solid #84B0C7;
|
||||
font-size : x-small;
|
||||
font-weight : bold;
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
DIV.tabs A:hover
|
||||
{
|
||||
background-position: 100% -150px;
|
||||
}
|
||||
|
||||
DIV.tabs A:link, DIV.tabs A:visited,
|
||||
DIV.tabs A:active, DIV.tabs A:hover
|
||||
{
|
||||
color: #1A419D;
|
||||
}
|
||||
|
||||
DIV.tabs SPAN
|
||||
{
|
||||
float : left;
|
||||
display : block;
|
||||
background : url("tab_l.gif") no-repeat left top;
|
||||
padding : 5px 9px;
|
||||
white-space : nowrap;
|
||||
}
|
||||
|
||||
DIV.tabs INPUT
|
||||
{
|
||||
float : right;
|
||||
display : inline;
|
||||
font-size : 1em;
|
||||
}
|
||||
|
||||
DIV.tabs TD
|
||||
{
|
||||
font-size : x-small;
|
||||
font-weight : bold;
|
||||
text-decoration : none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Commented Backslash Hack hides rule from IE5-Mac \*/
|
||||
DIV.tabs SPAN {float : none;}
|
||||
/* End IE5-Mac hack */
|
||||
|
||||
DIV.tabs A:hover SPAN
|
||||
{
|
||||
background-position: 0% -150px;
|
||||
}
|
||||
|
||||
DIV.tabs LI#current A
|
||||
{
|
||||
background-position: 100% -150px;
|
||||
border-width : 0px;
|
||||
}
|
||||
|
||||
DIV.tabs LI#current SPAN
|
||||
{
|
||||
background-position: 0% -150px;
|
||||
padding-bottom : 6px;
|
||||
}
|
||||
|
||||
DIV.nav
|
||||
{
|
||||
background : none;
|
||||
border : none;
|
||||
border-bottom : 1px solid #84B0C7;
|
||||
}
|
44
iniparser/src/CMakeLists.txt
Normal file
44
iniparser/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,44 @@
|
|||
project(iniparser)
|
||||
|
||||
find_package(Iniparser)
|
||||
|
||||
if (INIPARSER_FOUND)
|
||||
set(INIPARSER_INCLUDE_DIRS
|
||||
${INIPARSER_INCLUDE_DIRS}
|
||||
CACHE INTERNAL "iniparser include directory"
|
||||
)
|
||||
|
||||
set(INIPARSER_LIBRARY
|
||||
${INIPARSER_LIBRARY}
|
||||
CACHE INTERNAL "iniparser shared library"
|
||||
)
|
||||
|
||||
set(INIPARSER_LIBRARIES
|
||||
${INIPARSER_LIBRARY}
|
||||
CACHE INTERNAL "iniparser shared libraries"
|
||||
)
|
||||
else (INIPARSER_FOUND)
|
||||
set(INIPARSER_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
CACHE INTERNAL "iniparser include directory"
|
||||
)
|
||||
|
||||
set(INIPARSER_LIBRARY
|
||||
iniparser
|
||||
CACHE INTERNAL "iniparser static library"
|
||||
)
|
||||
|
||||
set(INIPARSER_LIBRARIES
|
||||
${INIPARSER_LIBRARY}
|
||||
CACHE INTERNAL "iniparser static libraries"
|
||||
)
|
||||
|
||||
set(iniparser_SRCS
|
||||
dictionary.c
|
||||
iniparser.c
|
||||
strlib.c
|
||||
)
|
||||
|
||||
add_library(${INIPARSER_LIBRARY} STATIC ${iniparser_SRCS})
|
||||
endif (INIPARSER_FOUND)
|
||||
|
508
iniparser/src/dictionary.c
Normal file
508
iniparser/src/dictionary.c
Normal file
|
@ -0,0 +1,508 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file dictionary.c
|
||||
@author N. Devillard
|
||||
@date Aug 2000
|
||||
@version $Revision: 1.24 $
|
||||
@brief Implements a dictionary for string variables.
|
||||
|
||||
This module implements a simple dictionary object, i.e. a list
|
||||
of string/string associations. This object is useful to store e.g.
|
||||
informations retrieved from a configuration file (ini files).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: dictionary.c,v 1.24 2006-09-27 11:02:22 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2006-09-27 11:02:22 $
|
||||
$Revision: 1.24 $
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include "dictionary.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/** Maximum value size for integers and doubles. */
|
||||
#define MAXVALSZ 1024
|
||||
|
||||
/** Minimal allocated number of entries in a dictionary */
|
||||
#define DICTMINSZ 128
|
||||
|
||||
/** Invalid key token */
|
||||
#define DICT_INVALID_KEY ((char*)-1)
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Private functions
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* Doubles the allocated size associated to a pointer */
|
||||
/* 'size' is the current allocated size. */
|
||||
static void * mem_double(void * ptr, int size)
|
||||
{
|
||||
void * newptr ;
|
||||
|
||||
newptr = calloc(2*size, 1);
|
||||
memcpy(newptr, ptr, size);
|
||||
free(ptr);
|
||||
return newptr ;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Function codes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Compute the hash key for a string.
|
||||
@param key Character string to use for key.
|
||||
@return 1 unsigned int on at least 32 bits.
|
||||
|
||||
This hash function has been taken from an Article in Dr Dobbs Journal.
|
||||
This is normally a collision-free function, distributing keys evenly.
|
||||
The key is stored anyway in the struct so that collision can be avoided
|
||||
by comparing the key itself in last resort.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned dictionary_hash(char * key)
|
||||
{
|
||||
int len ;
|
||||
unsigned hash ;
|
||||
int i ;
|
||||
|
||||
len = strlen(key);
|
||||
for (hash=0, i=0 ; i<len ; i++) {
|
||||
hash += (unsigned)key[i] ;
|
||||
hash += (hash<<10);
|
||||
hash ^= (hash>>6) ;
|
||||
}
|
||||
hash += (hash <<3);
|
||||
hash ^= (hash >>11);
|
||||
hash += (hash <<15);
|
||||
return hash ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Create a new dictionary object.
|
||||
@param size Optional initial size of the dictionary.
|
||||
@return 1 newly allocated dictionary objet.
|
||||
|
||||
This function allocates a new dictionary object of given size and returns
|
||||
it. If you do not know in advance (roughly) the number of entries in the
|
||||
dictionary, give size=0.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
dictionary * dictionary_new(int size)
|
||||
{
|
||||
dictionary * d ;
|
||||
|
||||
/* If no size was specified, allocate space for DICTMINSZ */
|
||||
if (size<DICTMINSZ) size=DICTMINSZ ;
|
||||
|
||||
d = (dictionary *)calloc(1, sizeof(dictionary));
|
||||
d->size = size ;
|
||||
d->val = (char **)calloc(size, sizeof(char*));
|
||||
d->key = (char **)calloc(size, sizeof(char*));
|
||||
d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
|
||||
return d ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete a dictionary object
|
||||
@param d dictionary object to deallocate.
|
||||
@return void
|
||||
|
||||
Deallocate a dictionary object and all memory associated to it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void dictionary_del(dictionary * d)
|
||||
{
|
||||
int i ;
|
||||
|
||||
if (d==NULL) return ;
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]!=NULL)
|
||||
free(d->key[i]);
|
||||
if (d->val[i]!=NULL)
|
||||
free(d->val[i]);
|
||||
}
|
||||
free(d->val);
|
||||
free(d->key);
|
||||
free(d->hash);
|
||||
free(d);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value to return if key not found.
|
||||
@return 1 pointer to internally allocated character string.
|
||||
|
||||
This function locates a key in a dictionary and returns a pointer to its
|
||||
value, or the passed 'def' pointer if no such key can be found in
|
||||
dictionary. The returned character pointer points to data internal to the
|
||||
dictionary object, you should not try to free it or modify it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * dictionary_get(dictionary * d, char * key, char * def)
|
||||
{
|
||||
unsigned hash ;
|
||||
int i ;
|
||||
|
||||
hash = dictionary_hash(key);
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key==NULL)
|
||||
continue ;
|
||||
/* Compare hash */
|
||||
if (hash==d->hash[i]) {
|
||||
/* Compare string, to avoid hash collisions */
|
||||
if (!strcmp(key, d->key[i])) {
|
||||
return d->val[i] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return def ;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as a char.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return char
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and returns the first char of the found string.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char dictionary_getchar(dictionary * d, char * key, char def)
|
||||
{
|
||||
char * v ;
|
||||
|
||||
if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
|
||||
return def ;
|
||||
} else {
|
||||
return v[0] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as an int.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return int
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and applies atoi on it to return an int. If the value cannot be found
|
||||
in the dictionary, the default is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int dictionary_getint(dictionary * d, char * key, int def)
|
||||
{
|
||||
char * v ;
|
||||
|
||||
if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
|
||||
return def ;
|
||||
} else {
|
||||
return atoi(v);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as a double.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return double
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and applies atof on it to return a double. If the value cannot be found
|
||||
in the dictionary, the default is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
double dictionary_getdouble(dictionary * d, char * key, double def)
|
||||
{
|
||||
char * v ;
|
||||
|
||||
if ((v=dictionary_get(d,key,DICT_INVALID_KEY))==DICT_INVALID_KEY) {
|
||||
return def ;
|
||||
} else {
|
||||
return atof(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a value in a dictionary.
|
||||
@param d dictionary object to modify.
|
||||
@param key Key to modify or add.
|
||||
@param val Value to add.
|
||||
@return void
|
||||
|
||||
If the given key is found in the dictionary, the associated value is
|
||||
replaced by the provided one. If the key cannot be found in the
|
||||
dictionary, it is added to it.
|
||||
|
||||
It is Ok to provide a NULL value for val, but NULL values for the dictionary
|
||||
or the key are considered as errors: the function will return immediately
|
||||
in such a case.
|
||||
|
||||
Notice that if you dictionary_set a variable to NULL, a call to
|
||||
dictionary_get will return a NULL value: the variable will be found, and
|
||||
its value (NULL) is returned. In other words, setting the variable
|
||||
content to NULL is equivalent to deleting the variable from the
|
||||
dictionary. It is not possible (in this implementation) to have a key in
|
||||
the dictionary without value.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void dictionary_set(dictionary * d, char * key, char * val)
|
||||
{
|
||||
int i ;
|
||||
unsigned hash ;
|
||||
|
||||
if (d==NULL || key==NULL) return ;
|
||||
|
||||
/* Compute hash for this key */
|
||||
hash = dictionary_hash(key) ;
|
||||
/* Find if value is already in blackboard */
|
||||
if (d->n>0) {
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
if (hash==d->hash[i]) { /* Same hash value */
|
||||
if (!strcmp(key, d->key[i])) { /* Same key */
|
||||
/* Found a value: modify and return */
|
||||
if (d->val[i]!=NULL)
|
||||
free(d->val[i]);
|
||||
d->val[i] = val ? strdup(val) : NULL ;
|
||||
/* Value has been modified: return */
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add a new value */
|
||||
/* See if dictionary needs to grow */
|
||||
if (d->n==d->size) {
|
||||
|
||||
/* Reached maximum size: reallocate blackboard */
|
||||
d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
|
||||
d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
|
||||
d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
|
||||
|
||||
/* Double size */
|
||||
d->size *= 2 ;
|
||||
}
|
||||
|
||||
/* Insert key in the first empty slot */
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL) {
|
||||
/* Add key here */
|
||||
break ;
|
||||
}
|
||||
}
|
||||
/* Copy key */
|
||||
d->key[i] = strdup(key);
|
||||
d->val[i] = val ? strdup(val) : NULL ;
|
||||
d->hash[i] = hash;
|
||||
d->n ++ ;
|
||||
return ;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete a key in a dictionary
|
||||
@param d dictionary object to modify.
|
||||
@param key Key to remove.
|
||||
@return void
|
||||
|
||||
This function deletes a key in a dictionary. Nothing is done if the
|
||||
key cannot be found.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_unset(dictionary * d, char * key)
|
||||
{
|
||||
unsigned hash ;
|
||||
int i ;
|
||||
|
||||
hash = dictionary_hash(key);
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
/* Compare hash */
|
||||
if (hash==d->hash[i]) {
|
||||
/* Compare string, to avoid hash collisions */
|
||||
if (!strcmp(key, d->key[i])) {
|
||||
/* Found key */
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i>=d->size)
|
||||
/* Key not found */
|
||||
return ;
|
||||
|
||||
free(d->key[i]);
|
||||
d->key[i] = NULL ;
|
||||
if (d->val[i]!=NULL) {
|
||||
free(d->val[i]);
|
||||
d->val[i] = NULL ;
|
||||
}
|
||||
d->hash[i] = 0 ;
|
||||
d->n -- ;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a key in a dictionary, providing an int.
|
||||
@param d Dictionary to update.
|
||||
@param key Key to modify or add
|
||||
@param val Integer value to store (will be stored as a string).
|
||||
@return void
|
||||
|
||||
This helper function calls dictionary_set() with the provided integer
|
||||
converted to a string using %d.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void dictionary_setint(dictionary * d, char * key, int val)
|
||||
{
|
||||
char sval[MAXVALSZ];
|
||||
sprintf(sval, "%d", val);
|
||||
dictionary_set(d, key, sval);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a key in a dictionary, providing a double.
|
||||
@param d Dictionary to update.
|
||||
@param key Key to modify or add
|
||||
@param val Double value to store (will be stored as a string).
|
||||
@return void
|
||||
|
||||
This helper function calls dictionary_set() with the provided double
|
||||
converted to a string using %g.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void dictionary_setdouble(dictionary * d, char * key, double val)
|
||||
{
|
||||
char sval[MAXVALSZ];
|
||||
sprintf(sval, "%g", val);
|
||||
dictionary_set(d, key, sval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Dump a dictionary to an opened file pointer.
|
||||
@param d Dictionary to dump
|
||||
@param f Opened file pointer.
|
||||
@return void
|
||||
|
||||
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
|
||||
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
|
||||
output file pointers.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void dictionary_dump(dictionary * d, FILE * out)
|
||||
{
|
||||
int i ;
|
||||
|
||||
if (d==NULL || out==NULL) return ;
|
||||
if (d->n<1) {
|
||||
fprintf(out, "empty dictionary\n");
|
||||
return ;
|
||||
}
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]) {
|
||||
fprintf(out, "%20s\t[%s]\n",
|
||||
d->key[i],
|
||||
d->val[i] ? d->val[i] : "UNDEF");
|
||||
}
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Example code */
|
||||
#ifdef TESTDIC
|
||||
#define NVALS 20000
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
dictionary * d ;
|
||||
char * val ;
|
||||
int i ;
|
||||
char cval[90] ;
|
||||
|
||||
/* allocate blackboard */
|
||||
printf("allocating...\n");
|
||||
d = dictionary_new(0);
|
||||
|
||||
/* Set values in blackboard */
|
||||
printf("setting %d values...\n", NVALS);
|
||||
for (i=0 ; i<NVALS ; i++) {
|
||||
sprintf(cval, "%04d", i);
|
||||
dictionary_set(d, cval, "salut");
|
||||
}
|
||||
printf("getting %d values...\n", NVALS);
|
||||
for (i=0 ; i<NVALS ; i++) {
|
||||
sprintf(cval, "%04d", i);
|
||||
val = dictionary_get(d, cval, DICT_INVALID_KEY);
|
||||
if (val==DICT_INVALID_KEY) {
|
||||
printf("cannot get value for key [%s]\n", cval);
|
||||
}
|
||||
}
|
||||
printf("unsetting %d values...\n", NVALS);
|
||||
for (i=0 ; i<NVALS ; i++) {
|
||||
sprintf(cval, "%04d", i);
|
||||
dictionary_unset(d, cval);
|
||||
}
|
||||
if (d->n != 0) {
|
||||
printf("error deleting values\n");
|
||||
}
|
||||
|
||||
printf("deallocating...\n");
|
||||
dictionary_del(d);
|
||||
return 0 ;
|
||||
}
|
||||
#endif
|
||||
/* vim: set ts=4 et sw=4 tw=75 */
|
244
iniparser/src/dictionary.h
Normal file
244
iniparser/src/dictionary.h
Normal file
|
@ -0,0 +1,244 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file dictionary.h
|
||||
@author N. Devillard
|
||||
@date Aug 2000
|
||||
@version $Revision: 1.11 $
|
||||
@brief Implements a dictionary for string variables.
|
||||
|
||||
This module implements a simple dictionary object, i.e. a list
|
||||
of string/string associations. This object is useful to store e.g.
|
||||
informations retrieved from a configuration file (ini files).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: dictionary.h,v 1.11 2002-06-17 09:30:46 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2002-06-17 09:30:46 $
|
||||
$Revision: 1.11 $
|
||||
*/
|
||||
|
||||
#ifndef _DICTIONARY_H_
|
||||
#define _DICTIONARY_H_
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
New types
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Dictionary object
|
||||
|
||||
This object contains a list of string/string associations. Each
|
||||
association is identified by a unique string key. Looking up values
|
||||
in the dictionary is speeded up by the use of a (hopefully collision-free)
|
||||
hash function.
|
||||
*/
|
||||
/*-------------------------------------------------------------------------*/
|
||||
typedef struct _dictionary_ {
|
||||
int n ; /** Number of entries in dictionary */
|
||||
int size ; /** Storage size */
|
||||
char ** val ; /** List of string values */
|
||||
char ** key ; /** List of string keys */
|
||||
unsigned * hash ; /** List of hash values for keys */
|
||||
} dictionary ;
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Function prototypes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Compute the hash key for a string.
|
||||
@param key Character string to use for key.
|
||||
@return 1 unsigned int on at least 32 bits.
|
||||
|
||||
This hash function has been taken from an Article in Dr Dobbs Journal.
|
||||
This is normally a collision-free function, distributing keys evenly.
|
||||
The key is stored anyway in the struct so that collision can be avoided
|
||||
by comparing the key itself in last resort.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
unsigned dictionary_hash(char * key);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Create a new dictionary object.
|
||||
@param size Optional initial size of the dictionary.
|
||||
@return 1 newly allocated dictionary objet.
|
||||
|
||||
This function allocates a new dictionary object of given size and returns
|
||||
it. If you do not know in advance (roughly) the number of entries in the
|
||||
dictionary, give size=0.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
dictionary * dictionary_new(int size);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete a dictionary object
|
||||
@param d dictionary object to deallocate.
|
||||
@return void
|
||||
|
||||
Deallocate a dictionary object and all memory associated to it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_del(dictionary * vd);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value to return if key not found.
|
||||
@return 1 pointer to internally allocated character string.
|
||||
|
||||
This function locates a key in a dictionary and returns a pointer to its
|
||||
value, or the passed 'def' pointer if no such key can be found in
|
||||
dictionary. The returned character pointer points to data internal to the
|
||||
dictionary object, you should not try to free it or modify it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * dictionary_get(dictionary * d, char * key, char * def);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as a char.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return char
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and returns the first char of the found string.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char dictionary_getchar(dictionary * d, char * key, char def) ;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as an int.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return int
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and applies atoi on it to return an int. If the value cannot be found
|
||||
in the dictionary, the default is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int dictionary_getint(dictionary * d, char * key, int def);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get a value from a dictionary, as a double.
|
||||
@param d dictionary object to search.
|
||||
@param key Key to look for in the dictionary.
|
||||
@param def Default value for the key if not found.
|
||||
@return double
|
||||
|
||||
This function locates a key in a dictionary using dictionary_get,
|
||||
and applies atof on it to return a double. If the value cannot be found
|
||||
in the dictionary, the default is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
double dictionary_getdouble(dictionary * d, char * key, double def);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a value in a dictionary.
|
||||
@param d dictionary object to modify.
|
||||
@param key Key to modify or add.
|
||||
@param val Value to add.
|
||||
@return void
|
||||
|
||||
If the given key is found in the dictionary, the associated value is
|
||||
replaced by the provided one. If the key cannot be found in the
|
||||
dictionary, it is added to it.
|
||||
|
||||
It is Ok to provide a NULL value for val, but NULL values for the dictionary
|
||||
or the key are considered as errors: the function will return immediately
|
||||
in such a case.
|
||||
|
||||
Notice that if you dictionary_set a variable to NULL, a call to
|
||||
dictionary_get will return a NULL value: the variable will be found, and
|
||||
its value (NULL) is returned. In other words, setting the variable
|
||||
content to NULL is equivalent to deleting the variable from the
|
||||
dictionary. It is not possible (in this implementation) to have a key in
|
||||
the dictionary without value.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_set(dictionary * vd, char * key, char * val);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete a key in a dictionary
|
||||
@param d dictionary object to modify.
|
||||
@param key Key to remove.
|
||||
@return void
|
||||
|
||||
This function deletes a key in a dictionary. Nothing is done if the
|
||||
key cannot be found.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_unset(dictionary * d, char * key);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a key in a dictionary, providing an int.
|
||||
@param d Dictionary to update.
|
||||
@param key Key to modify or add
|
||||
@param val Integer value to store (will be stored as a string).
|
||||
@return void
|
||||
|
||||
This helper function calls dictionary_set() with the provided integer
|
||||
converted to a string using %d.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_setint(dictionary * d, char * key, int val);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set a key in a dictionary, providing a double.
|
||||
@param d Dictionary to update.
|
||||
@param key Key to modify or add
|
||||
@param val Double value to store (will be stored as a string).
|
||||
@return void
|
||||
|
||||
This helper function calls dictionary_set() with the provided double
|
||||
converted to a string using %g.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_setdouble(dictionary * d, char * key, double val);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Dump a dictionary to an opened file pointer.
|
||||
@param d Dictionary to dump
|
||||
@param f Opened file pointer.
|
||||
@return void
|
||||
|
||||
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
|
||||
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
|
||||
output file pointers.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void dictionary_dump(dictionary * d, FILE * out);
|
||||
|
||||
#endif
|
531
iniparser/src/iniparser.c
Normal file
531
iniparser/src/iniparser.c
Normal file
|
@ -0,0 +1,531 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file iniparser.c
|
||||
@author N. Devillard
|
||||
@date Mar 2000
|
||||
@version $Revision: 2.16 $
|
||||
@brief Parser for ini files.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: iniparser.c,v 2.16 2006-09-27 11:03:34 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2006-09-27 11:03:34 $
|
||||
$Revision: 2.16 $
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include "iniparser.h"
|
||||
#include "strlib.h"
|
||||
|
||||
#define ASCIILINESZ 1024
|
||||
#define INI_INVALID_KEY ((char*)-1)
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Private to this module
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* Private: add an entry to the dictionary */
|
||||
static void iniparser_add_entry(
|
||||
dictionary * d,
|
||||
char * sec,
|
||||
char * key,
|
||||
char * val)
|
||||
{
|
||||
char longkey[2*ASCIILINESZ+1];
|
||||
|
||||
/* Make a key as section:keyword */
|
||||
if (key!=NULL) {
|
||||
sprintf(longkey, "%s:%s", sec, key);
|
||||
} else {
|
||||
strcpy(longkey, sec);
|
||||
}
|
||||
|
||||
/* Add (key,val) to dictionary */
|
||||
dictionary_set(d, longkey, val);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get number of sections in a dictionary
|
||||
@param d Dictionary to examine
|
||||
@return int Number of sections found in dictionary
|
||||
|
||||
This function returns the number of sections found in a dictionary.
|
||||
The test to recognize sections is done on the string stored in the
|
||||
dictionary: a section name is given as "section" whereas a key is
|
||||
stored as "section:key", thus the test looks for entries that do not
|
||||
contain a colon.
|
||||
|
||||
This clearly fails in the case a section name contains a colon, but
|
||||
this should simply be avoided.
|
||||
|
||||
This function returns -1 in case of error.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int iniparser_getnsec(dictionary * d)
|
||||
{
|
||||
int i ;
|
||||
int nsec ;
|
||||
|
||||
if (d==NULL) return -1 ;
|
||||
nsec=0 ;
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
if (strchr(d->key[i], ':')==NULL) {
|
||||
nsec ++ ;
|
||||
}
|
||||
}
|
||||
return nsec ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get name for section n in a dictionary.
|
||||
@param d Dictionary to examine
|
||||
@param n Section number (from 0 to nsec-1).
|
||||
@return Pointer to char string
|
||||
|
||||
This function locates the n-th section in a dictionary and returns
|
||||
its name as a pointer to a string statically allocated inside the
|
||||
dictionary. Do not free or modify the returned string!
|
||||
|
||||
This function returns NULL in case of error.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * iniparser_getsecname(dictionary * d, int n)
|
||||
{
|
||||
int i ;
|
||||
int foundsec ;
|
||||
|
||||
if (d==NULL || n<0) return NULL ;
|
||||
foundsec=0 ;
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
if (strchr(d->key[i], ':')==NULL) {
|
||||
foundsec++ ;
|
||||
if (foundsec>n)
|
||||
break ;
|
||||
}
|
||||
}
|
||||
if (foundsec<=n) {
|
||||
return NULL ;
|
||||
}
|
||||
return d->key[i] ;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Dump a dictionary to an opened file pointer.
|
||||
@param d Dictionary to dump.
|
||||
@param f Opened file pointer to dump to.
|
||||
@return void
|
||||
|
||||
This function prints out the contents of a dictionary, one element by
|
||||
line, onto the provided file pointer. It is OK to specify @c stderr
|
||||
or @c stdout as output files. This function is meant for debugging
|
||||
purposes mostly.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void iniparser_dump(dictionary * d, FILE * f)
|
||||
{
|
||||
int i ;
|
||||
|
||||
if (d==NULL || f==NULL) return ;
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
if (d->val[i]!=NULL) {
|
||||
fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
|
||||
} else {
|
||||
fprintf(f, "[%s]=UNDEF\n", d->key[i]);
|
||||
}
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Save a dictionary to a loadable ini file
|
||||
@param d Dictionary to dump
|
||||
@param f Opened file pointer to dump to
|
||||
@return void
|
||||
|
||||
This function dumps a given dictionary into a loadable ini file.
|
||||
It is Ok to specify @c stderr or @c stdout as output files.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void iniparser_dump_ini(dictionary * d, FILE * f)
|
||||
{
|
||||
int i, j ;
|
||||
char keym[ASCIILINESZ+1];
|
||||
int nsec ;
|
||||
char * secname ;
|
||||
int seclen ;
|
||||
|
||||
if (d==NULL || f==NULL) return ;
|
||||
|
||||
nsec = iniparser_getnsec(d);
|
||||
if (nsec<1) {
|
||||
/* No section in file: dump all keys as they are */
|
||||
for (i=0 ; i<d->size ; i++) {
|
||||
if (d->key[i]==NULL)
|
||||
continue ;
|
||||
fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
for (i=0 ; i<nsec ; i++) {
|
||||
secname = iniparser_getsecname(d, i) ;
|
||||
seclen = (int)strlen(secname);
|
||||
fprintf(f, "\n[%s]\n", secname);
|
||||
sprintf(keym, "%s:", secname);
|
||||
for (j=0 ; j<d->size ; j++) {
|
||||
if (d->key[j]==NULL)
|
||||
continue ;
|
||||
if (!strncmp(d->key[j], keym, seclen+1)) {
|
||||
fprintf(f,
|
||||
"%-30s = %s\n",
|
||||
d->key[j]+seclen+1,
|
||||
d->val[j] ? d->val[j] : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, return NULL if not found
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@return pointer to statically allocated character string, or NULL.
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
NULL is returned.
|
||||
The returned char pointer is pointing to a string allocated in
|
||||
the dictionary, do not free or modify it.
|
||||
|
||||
This function is only provided for backwards compatibility with
|
||||
previous versions of iniparser. It is recommended to use
|
||||
iniparser_getstring() instead.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * iniparser_getstr(dictionary * d, const char * key)
|
||||
{
|
||||
return iniparser_getstring(d, key, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param def Default value to return if key not found.
|
||||
@return pointer to statically allocated character string
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the pointer passed as 'def' is returned.
|
||||
The returned char pointer is pointing to a string allocated in
|
||||
the dictionary, do not free or modify it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * iniparser_getstring(dictionary * d, const char * key, char * def)
|
||||
{
|
||||
char * lc_key ;
|
||||
char * sval ;
|
||||
|
||||
if (d==NULL || key==NULL)
|
||||
return def ;
|
||||
|
||||
lc_key = strdup(strlwc(key));
|
||||
sval = dictionary_get(d, lc_key, def);
|
||||
free(lc_key);
|
||||
return sval ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to an int
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return integer
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
|
||||
Supported values for integers include the usual C notation
|
||||
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
|
||||
are supported. Examples:
|
||||
|
||||
"42" -> 42
|
||||
"042" -> 34 (octal -> decimal)
|
||||
"0x42" -> 66 (hexa -> decimal)
|
||||
|
||||
Warning: the conversion may overflow in various ways. Conversion is
|
||||
totally outsourced to strtol(), see the associated man page for overflow
|
||||
handling.
|
||||
|
||||
Credits: Thanks to A. Becker for suggesting strtol()
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int iniparser_getint(dictionary * d, const char * key, int notfound)
|
||||
{
|
||||
char * str ;
|
||||
|
||||
str = iniparser_getstring(d, key, INI_INVALID_KEY);
|
||||
if (str==INI_INVALID_KEY) return notfound ;
|
||||
return (int)strtol(str, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to a double
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return double
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
double iniparser_getdouble(dictionary * d, char * key, double notfound)
|
||||
{
|
||||
char * str ;
|
||||
|
||||
str = iniparser_getstring(d, key, INI_INVALID_KEY);
|
||||
if (str==INI_INVALID_KEY) return notfound ;
|
||||
return atof(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to a boolean
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return integer
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
|
||||
A true boolean is found if one of the following is matched:
|
||||
|
||||
- A string starting with 'y'
|
||||
- A string starting with 'Y'
|
||||
- A string starting with 't'
|
||||
- A string starting with 'T'
|
||||
- A string starting with '1'
|
||||
|
||||
A false boolean is found if one of the following is matched:
|
||||
|
||||
- A string starting with 'n'
|
||||
- A string starting with 'N'
|
||||
- A string starting with 'f'
|
||||
- A string starting with 'F'
|
||||
- A string starting with '0'
|
||||
|
||||
The notfound value returned if no boolean is identified, does not
|
||||
necessarily have to be 0 or 1.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int iniparser_getboolean(dictionary * d, const char * key, int notfound)
|
||||
{
|
||||
char * c ;
|
||||
int ret ;
|
||||
|
||||
c = iniparser_getstring(d, key, INI_INVALID_KEY);
|
||||
if (c==INI_INVALID_KEY) return notfound ;
|
||||
if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
|
||||
ret = 1 ;
|
||||
} else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
|
||||
ret = 0 ;
|
||||
} else {
|
||||
ret = notfound ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Finds out if a given entry exists in a dictionary
|
||||
@param ini Dictionary to search
|
||||
@param entry Name of the entry to look for
|
||||
@return integer 1 if entry exists, 0 otherwise
|
||||
|
||||
Finds out if a given entry exists in the dictionary. Since sections
|
||||
are stored as keys with NULL associated values, this is the only way
|
||||
of querying for the presence of sections in a dictionary.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int iniparser_find_entry(
|
||||
dictionary * ini,
|
||||
char * entry
|
||||
)
|
||||
{
|
||||
int found=0 ;
|
||||
if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
|
||||
found = 1 ;
|
||||
}
|
||||
return found ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set an entry in a dictionary.
|
||||
@param ini Dictionary to modify.
|
||||
@param entry Entry to modify (entry name)
|
||||
@param val New value to associate to the entry.
|
||||
@return int 0 if Ok, -1 otherwise.
|
||||
|
||||
If the given entry can be found in the dictionary, it is modified to
|
||||
contain the provided value. If it cannot be found, -1 is returned.
|
||||
It is Ok to set val to NULL.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int iniparser_setstr(dictionary * ini, char * entry, char * val)
|
||||
{
|
||||
dictionary_set(ini, strlwc(entry), val);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete an entry in a dictionary
|
||||
@param ini Dictionary to modify
|
||||
@param entry Entry to delete (entry name)
|
||||
@return void
|
||||
|
||||
If the given entry can be found, it is deleted from the dictionary.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void iniparser_unset(dictionary * ini, char * entry)
|
||||
{
|
||||
dictionary_unset(ini, strlwc(entry));
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Parse an ini file and return an allocated dictionary object
|
||||
@param ininame Name of the ini file to read.
|
||||
@return Pointer to newly allocated dictionary
|
||||
|
||||
This is the parser for ini files. This function is called, providing
|
||||
the name of the file to be read. It returns a dictionary object that
|
||||
should not be accessed directly, but through accessor functions
|
||||
instead.
|
||||
|
||||
The returned dictionary must be freed using iniparser_freedict().
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
dictionary * iniparser_load(const char * ininame)
|
||||
{
|
||||
dictionary * d ;
|
||||
char lin[ASCIILINESZ+1];
|
||||
char sec[ASCIILINESZ+1];
|
||||
char key[ASCIILINESZ+1];
|
||||
char val[ASCIILINESZ+1];
|
||||
char * where ;
|
||||
FILE * ini ;
|
||||
int lineno ;
|
||||
|
||||
if ((ini=fopen(ininame, "r"))==NULL) {
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
sec[0]=0;
|
||||
|
||||
/*
|
||||
* Initialize a new dictionary entry
|
||||
*/
|
||||
d = dictionary_new(0);
|
||||
lineno = 0 ;
|
||||
while (fgets(lin, ASCIILINESZ, ini)!=NULL) {
|
||||
lineno++ ;
|
||||
where = strskp(lin); /* Skip leading spaces */
|
||||
if (*where==';' || *where=='#' || *where==0)
|
||||
continue ; /* Comment lines */
|
||||
else {
|
||||
if (sscanf(where, "[%[^]]", sec)==1) {
|
||||
/* Valid section name */
|
||||
strcpy(sec, strlwc(sec));
|
||||
iniparser_add_entry(d, sec, NULL, NULL);
|
||||
} else if (sscanf (where, "%[^=] = \"%[^\"]\"", key, val) == 2
|
||||
|| sscanf (where, "%[^=] = '%[^\']'", key, val) == 2
|
||||
|| sscanf (where, "%[^=] = %[^;#]", key, val) == 2) {
|
||||
strcpy(key, strlwc(strcrop(key)));
|
||||
/*
|
||||
* sscanf cannot handle "" or '' as empty value,
|
||||
* this is done here
|
||||
*/
|
||||
if (!strcmp(val, "\"\"") || !strcmp(val, "''")) {
|
||||
val[0] = (char)0;
|
||||
} else {
|
||||
strcpy(val, strcrop(val));
|
||||
}
|
||||
iniparser_add_entry(d, sec, key, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(ini);
|
||||
return d ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Free all memory associated to an ini dictionary
|
||||
@param d Dictionary to free
|
||||
@return void
|
||||
|
||||
Free all memory associated to an ini dictionary.
|
||||
It is mandatory to call this function before the dictionary object
|
||||
gets out of the current context.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void iniparser_freedict(dictionary * d)
|
||||
{
|
||||
dictionary_del(d);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 et sw=4 tw=75 */
|
296
iniparser/src/iniparser.h
Normal file
296
iniparser/src/iniparser.h
Normal file
|
@ -0,0 +1,296 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file iniparser.h
|
||||
@author N. Devillard
|
||||
@date Mar 2000
|
||||
@version $Revision: 1.23 $
|
||||
@brief Parser for ini files.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: iniparser.h,v 1.23 2006-09-27 11:03:35 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2006-09-27 11:03:35 $
|
||||
$Revision: 1.23 $
|
||||
*/
|
||||
|
||||
#ifndef _INIPARSER_H_
|
||||
#define _INIPARSER_H_
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* The following #include is necessary on many Unixes but not Linux.
|
||||
* It is not needed for Windows platforms.
|
||||
* Uncomment it if needed.
|
||||
*/
|
||||
/* #include <unistd.h> */
|
||||
|
||||
#include "dictionary.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get number of sections in a dictionary
|
||||
@param d Dictionary to examine
|
||||
@return int Number of sections found in dictionary
|
||||
|
||||
This function returns the number of sections found in a dictionary.
|
||||
The test to recognize sections is done on the string stored in the
|
||||
dictionary: a section name is given as "section" whereas a key is
|
||||
stored as "section:key", thus the test looks for entries that do not
|
||||
contain a colon.
|
||||
|
||||
This clearly fails in the case a section name contains a colon, but
|
||||
this should simply be avoided.
|
||||
|
||||
This function returns -1 in case of error.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int iniparser_getnsec(dictionary * d);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get name for section n in a dictionary.
|
||||
@param d Dictionary to examine
|
||||
@param n Section number (from 0 to nsec-1).
|
||||
@return Pointer to char string
|
||||
|
||||
This function locates the n-th section in a dictionary and returns
|
||||
its name as a pointer to a string statically allocated inside the
|
||||
dictionary. Do not free or modify the returned string!
|
||||
|
||||
This function returns NULL in case of error.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * iniparser_getsecname(dictionary * d, int n);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Save a dictionary to a loadable ini file
|
||||
@param d Dictionary to dump
|
||||
@param f Opened file pointer to dump to
|
||||
@return void
|
||||
|
||||
This function dumps a given dictionary into a loadable ini file.
|
||||
It is Ok to specify @c stderr or @c stdout as output files.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void iniparser_dump_ini(dictionary * d, FILE * f);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Dump a dictionary to an opened file pointer.
|
||||
@param d Dictionary to dump.
|
||||
@param f Opened file pointer to dump to.
|
||||
@return void
|
||||
|
||||
This function prints out the contents of a dictionary, one element by
|
||||
line, onto the provided file pointer. It is OK to specify @c stderr
|
||||
or @c stdout as output files. This function is meant for debugging
|
||||
purposes mostly.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void iniparser_dump(dictionary * d, FILE * f);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, return NULL if not found
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@return pointer to statically allocated character string, or NULL.
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
NULL is returned.
|
||||
The returned char pointer is pointing to a string allocated in
|
||||
the dictionary, do not free or modify it.
|
||||
|
||||
This function is only provided for backwards compatibility with
|
||||
previous versions of iniparser. It is recommended to use
|
||||
iniparser_getstring() instead.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * iniparser_getstr(dictionary * d, const char * key);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param def Default value to return if key not found.
|
||||
@return pointer to statically allocated character string
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the pointer passed as 'def' is returned.
|
||||
The returned char pointer is pointing to a string allocated in
|
||||
the dictionary, do not free or modify it.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * iniparser_getstring(dictionary * d, const char * key, char * def);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to an int
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return integer
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
|
||||
Supported values for integers include the usual C notation
|
||||
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
|
||||
are supported. Examples:
|
||||
|
||||
- "42" -> 42
|
||||
- "042" -> 34 (octal -> decimal)
|
||||
- "0x42" -> 66 (hexa -> decimal)
|
||||
|
||||
Warning: the conversion may overflow in various ways. Conversion is
|
||||
totally outsourced to strtol(), see the associated man page for overflow
|
||||
handling.
|
||||
|
||||
Credits: Thanks to A. Becker for suggesting strtol()
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int iniparser_getint(dictionary * d, const char * key, int notfound);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to a double
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return double
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
double iniparser_getdouble(dictionary * d, char * key, double notfound);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Get the string associated to a key, convert to a boolean
|
||||
@param d Dictionary to search
|
||||
@param key Key string to look for
|
||||
@param notfound Value to return in case of error
|
||||
@return integer
|
||||
|
||||
This function queries a dictionary for a key. A key as read from an
|
||||
ini file is given as "section:key". If the key cannot be found,
|
||||
the notfound value is returned.
|
||||
|
||||
A true boolean is found if one of the following is matched:
|
||||
|
||||
- A string starting with 'y'
|
||||
- A string starting with 'Y'
|
||||
- A string starting with 't'
|
||||
- A string starting with 'T'
|
||||
- A string starting with '1'
|
||||
|
||||
A false boolean is found if one of the following is matched:
|
||||
|
||||
- A string starting with 'n'
|
||||
- A string starting with 'N'
|
||||
- A string starting with 'f'
|
||||
- A string starting with 'F'
|
||||
- A string starting with '0'
|
||||
|
||||
The notfound value returned if no boolean is identified, does not
|
||||
necessarily have to be 0 or 1.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int iniparser_getboolean(dictionary * d, const char * key, int notfound);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Set an entry in a dictionary.
|
||||
@param ini Dictionary to modify.
|
||||
@param entry Entry to modify (entry name)
|
||||
@param val New value to associate to the entry.
|
||||
@return int 0 if Ok, -1 otherwise.
|
||||
|
||||
If the given entry can be found in the dictionary, it is modified to
|
||||
contain the provided value. If it cannot be found, -1 is returned.
|
||||
It is Ok to set val to NULL.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
int iniparser_setstr(dictionary * ini, char * entry, char * val);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Delete an entry in a dictionary
|
||||
@param ini Dictionary to modify
|
||||
@param entry Entry to delete (entry name)
|
||||
@return void
|
||||
|
||||
If the given entry can be found, it is deleted from the dictionary.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void iniparser_unset(dictionary * ini, char * entry);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Finds out if a given entry exists in a dictionary
|
||||
@param ini Dictionary to search
|
||||
@param entry Name of the entry to look for
|
||||
@return integer 1 if entry exists, 0 otherwise
|
||||
|
||||
Finds out if a given entry exists in the dictionary. Since sections
|
||||
are stored as keys with NULL associated values, this is the only way
|
||||
of querying for the presence of sections in a dictionary.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int iniparser_find_entry(dictionary * ini, char * entry) ;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Parse an ini file and return an allocated dictionary object
|
||||
@param ininame Name of the ini file to read.
|
||||
@return Pointer to newly allocated dictionary
|
||||
|
||||
This is the parser for ini files. This function is called, providing
|
||||
the name of the file to be read. It returns a dictionary object that
|
||||
should not be accessed directly, but through accessor functions
|
||||
instead.
|
||||
|
||||
The returned dictionary must be freed using iniparser_freedict().
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
dictionary * iniparser_load(const char * ininame);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Free all memory associated to an ini dictionary
|
||||
@param d Dictionary to free
|
||||
@return void
|
||||
|
||||
Free all memory associated to an ini dictionary.
|
||||
It is mandatory to call this function before the dictionary object
|
||||
gets out of the current context.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void iniparser_freedict(dictionary * d);
|
||||
|
||||
#endif
|
211
iniparser/src/strlib.c
Normal file
211
iniparser/src/strlib.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file strlib.c
|
||||
@author N. Devillard
|
||||
@date Jan 2001
|
||||
@version $Revision: 1.9 $
|
||||
@brief Various string handling routines to complement the C lib.
|
||||
|
||||
This modules adds a few complementary string routines usually missing
|
||||
in the standard C library.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: strlib.c,v 1.9 2006-09-27 11:04:11 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2006-09-27 11:04:11 $
|
||||
$Revision: 1.9 $
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "strlib.h"
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Defines
|
||||
---------------------------------------------------------------------------*/
|
||||
#define ASCIILINESZ 1024
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Function codes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Convert a string to lowercase.
|
||||
@param s String to convert.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string
|
||||
containing a lowercased version of the input string. Do not free
|
||||
or modify the returned string! Since the returned string is statically
|
||||
allocated, it will be modified at each function call (not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * strlwc(const char * s)
|
||||
{
|
||||
static char l[ASCIILINESZ+1];
|
||||
int i ;
|
||||
|
||||
if (s==NULL) return NULL ;
|
||||
memset(l, 0, ASCIILINESZ+1);
|
||||
i=0 ;
|
||||
while (s[i] && i<ASCIILINESZ) {
|
||||
l[i] = (char)tolower((int)s[i]);
|
||||
i++ ;
|
||||
}
|
||||
l[ASCIILINESZ]=(char)0;
|
||||
return l ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Convert a string to uppercase.
|
||||
@param s String to convert.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string
|
||||
containing an uppercased version of the input string. Do not free
|
||||
or modify the returned string! Since the returned string is statically
|
||||
allocated, it will be modified at each function call (not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * strupc(char * s)
|
||||
{
|
||||
static char l[ASCIILINESZ+1];
|
||||
int i ;
|
||||
|
||||
if (s==NULL) return NULL ;
|
||||
memset(l, 0, ASCIILINESZ+1);
|
||||
i=0 ;
|
||||
while (s[i] && i<ASCIILINESZ) {
|
||||
l[i] = (char)toupper((int)s[i]);
|
||||
i++ ;
|
||||
}
|
||||
l[ASCIILINESZ]=(char)0;
|
||||
return l ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Skip blanks until the first non-blank character.
|
||||
@param s String to parse.
|
||||
@return Pointer to char inside given string.
|
||||
|
||||
This function returns a pointer to the first non-blank character in the
|
||||
given string.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * strskp(char * s)
|
||||
{
|
||||
char * skip = s;
|
||||
if (s==NULL) return NULL ;
|
||||
while (isspace((int)*skip) && *skip) skip++;
|
||||
return skip ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Remove blanks at the end of a string.
|
||||
@param s String to parse.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string,
|
||||
which is identical to the input string, except that all blank
|
||||
characters at the end of the string have been removed.
|
||||
Do not free or modify the returned string! Since the returned string
|
||||
is statically allocated, it will be modified at each function call
|
||||
(not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
char * strcrop(char * s)
|
||||
{
|
||||
static char l[ASCIILINESZ+1];
|
||||
char * last ;
|
||||
|
||||
if (s==NULL) return NULL ;
|
||||
memset(l, 0, ASCIILINESZ+1);
|
||||
strcpy(l, s);
|
||||
last = l + strlen(l);
|
||||
while (last > l) {
|
||||
if (!isspace((int)*(last-1)))
|
||||
break ;
|
||||
last -- ;
|
||||
}
|
||||
*last = (char)0;
|
||||
return l ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Remove blanks at the beginning and the end of a string.
|
||||
@param s String to parse.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string,
|
||||
which is identical to the input string, except that all blank
|
||||
characters at the end and the beg. of the string have been removed.
|
||||
Do not free or modify the returned string! Since the returned string
|
||||
is statically allocated, it will be modified at each function call
|
||||
(not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strstrip(char * s)
|
||||
{
|
||||
static char l[ASCIILINESZ+1];
|
||||
char * last ;
|
||||
|
||||
if (s==NULL) return NULL ;
|
||||
|
||||
while (isspace((int)*s) && *s) s++;
|
||||
|
||||
memset(l, 0, ASCIILINESZ+1);
|
||||
strcpy(l, s);
|
||||
last = l + strlen(l);
|
||||
while (last > l) {
|
||||
if (!isspace((int)*(last-1)))
|
||||
break ;
|
||||
last -- ;
|
||||
}
|
||||
*last = (char)0;
|
||||
|
||||
return (char*)l ;
|
||||
}
|
||||
|
||||
/* Test code */
|
||||
#ifdef TEST
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
char * str ;
|
||||
|
||||
str = "\t\tI'm a lumberkack and I'm OK " ;
|
||||
printf("lowercase: [%s]\n", strlwc(str));
|
||||
printf("uppercase: [%s]\n", strupc(str));
|
||||
printf("skipped : [%s]\n", strskp(str));
|
||||
printf("cropped : [%s]\n", strcrop(str));
|
||||
printf("stripped : [%s]\n", strstrip(str));
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
#endif
|
||||
/* vim: set ts=4 et sw=4 tw=75 */
|
108
iniparser/src/strlib.h
Normal file
108
iniparser/src/strlib.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@file strlib.h
|
||||
@author N. Devillard
|
||||
@date Jan 2001
|
||||
@version $Revision: 1.4 $
|
||||
@brief Various string handling routines to complement the C lib.
|
||||
|
||||
This modules adds a few complementary string routines usually missing
|
||||
in the standard C library.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
$Id: strlib.h,v 1.4 2006-09-27 11:04:11 ndevilla Exp $
|
||||
$Author: ndevilla $
|
||||
$Date: 2006-09-27 11:04:11 $
|
||||
$Revision: 1.4 $
|
||||
*/
|
||||
|
||||
#ifndef _STRLIB_H_
|
||||
#define _STRLIB_H_
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Includes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Function codes
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Convert a string to lowercase.
|
||||
@param s String to convert.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string
|
||||
containing a lowercased version of the input string. Do not free
|
||||
or modify the returned string! Since the returned string is statically
|
||||
allocated, it will be modified at each function call (not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strlwc(const char * s);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Convert a string to uppercase.
|
||||
@param s String to convert.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string
|
||||
containing an uppercased version of the input string. Do not free
|
||||
or modify the returned string! Since the returned string is statically
|
||||
allocated, it will be modified at each function call (not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strupc(char * s);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Skip blanks until the first non-blank character.
|
||||
@param s String to parse.
|
||||
@return Pointer to char inside given string.
|
||||
|
||||
This function returns a pointer to the first non-blank character in the
|
||||
given string.
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strskp(char * s);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Remove blanks at the end of a string.
|
||||
@param s String to parse.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string,
|
||||
which is identical to the input string, except that all blank
|
||||
characters at the end of the string have been removed.
|
||||
Do not free or modify the returned string! Since the returned string
|
||||
is statically allocated, it will be modified at each function call
|
||||
(not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strcrop(char * s);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/**
|
||||
@brief Remove blanks at the beginning and the end of a string.
|
||||
@param s String to parse.
|
||||
@return ptr to statically allocated string.
|
||||
|
||||
This function returns a pointer to a statically allocated string,
|
||||
which is identical to the input string, except that all blank
|
||||
characters at the end and the beg. of the string have been removed.
|
||||
Do not free or modify the returned string! Since the returned string
|
||||
is statically allocated, it will be modified at each function call
|
||||
(not re-entrant).
|
||||
*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
char * strstrip(char * s) ;
|
||||
|
||||
#endif
|
24
iniparser/test/Makefile
Normal file
24
iniparser/test/Makefile
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# iniparser tests Makefile
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -g -I../src
|
||||
LFLAGS = -L.. -liniparser
|
||||
AR = ar
|
||||
ARFLAGS = rcv
|
||||
RM = rm -f
|
||||
|
||||
|
||||
default: all
|
||||
|
||||
all: iniexample
|
||||
|
||||
iniexample: iniexample.c
|
||||
$(CC) $(CFLAGS) -o iniexample iniexample.c -I../src -L.. -liniparser
|
||||
|
||||
clean veryclean:
|
||||
$(RM) iniexample example.ini
|
||||
|
||||
|
||||
|
117
iniparser/test/iniexample.c
Normal file
117
iniparser/test/iniexample.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "iniparser.h"
|
||||
|
||||
void create_example_ini_file(void);
|
||||
int parse_ini_file(char * ini_name);
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int status ;
|
||||
|
||||
if (argc<2) {
|
||||
create_example_ini_file();
|
||||
status = parse_ini_file("example.ini");
|
||||
} else {
|
||||
status = parse_ini_file(argv[1]);
|
||||
}
|
||||
return status ;
|
||||
}
|
||||
|
||||
void create_example_ini_file(void)
|
||||
{
|
||||
FILE * ini ;
|
||||
|
||||
ini = fopen("example.ini", "w");
|
||||
fprintf(ini, "\n\
|
||||
#\n\
|
||||
# This is an example of ini file\n\
|
||||
#\n\
|
||||
\n\
|
||||
[Pizza]\n\
|
||||
\n\
|
||||
Ham = yes ;\n\
|
||||
Mushrooms = TRUE ;\n\
|
||||
Capres = 0 ;\n\
|
||||
Cheese = NO ;\n\
|
||||
\n\
|
||||
\n\
|
||||
[Wine]\n\
|
||||
\n\
|
||||
Grape = Cabernet Sauvignon ;\n\
|
||||
Year = 1989 ;\n\
|
||||
Country = Spain ;\n\
|
||||
Alcohol = 12.5 ;\n\
|
||||
\n\
|
||||
#\n\
|
||||
# end of file\n\
|
||||
#\n");
|
||||
|
||||
fclose(ini);
|
||||
}
|
||||
|
||||
|
||||
int parse_ini_file(char * ini_name)
|
||||
{
|
||||
dictionary * ini ;
|
||||
|
||||
/* Some temporary variables to hold query results */
|
||||
int b ;
|
||||
int i ;
|
||||
double d ;
|
||||
char * s ;
|
||||
|
||||
ini = iniparser_load(ini_name);
|
||||
if (ini==NULL) {
|
||||
fprintf(stderr, "cannot parse file [%s]", ini_name);
|
||||
return -1 ;
|
||||
}
|
||||
iniparser_dump(ini, stderr);
|
||||
|
||||
/* Get pizza attributes */
|
||||
printf("Pizza:\n");
|
||||
|
||||
b = iniparser_getboolean(ini, "pizza:ham", -1);
|
||||
printf("Ham: [%d]\n", b);
|
||||
b = iniparser_getboolean(ini, "pizza:mushrooms", -1);
|
||||
printf("Mushrooms: [%d]\n", b);
|
||||
b = iniparser_getboolean(ini, "pizza:capres", -1);
|
||||
printf("Capres: [%d]\n", b);
|
||||
b = iniparser_getboolean(ini, "pizza:cheese", -1);
|
||||
printf("Cheese: [%d]\n", b);
|
||||
|
||||
/* Get wine attributes */
|
||||
printf("Wine:\n");
|
||||
s = iniparser_getstr(ini, "wine:grape");
|
||||
if (s) {
|
||||
printf("grape: [%s]\n", s);
|
||||
} else {
|
||||
printf("grape: not found\n");
|
||||
}
|
||||
i = iniparser_getint(ini, "wine:year", -1);
|
||||
if (i>0) {
|
||||
printf("year: [%d]\n", i);
|
||||
} else {
|
||||
printf("year: not found\n");
|
||||
}
|
||||
s = iniparser_getstr(ini, "wine:country");
|
||||
if (s) {
|
||||
printf("country: [%s]\n", s);
|
||||
} else {
|
||||
printf("country: not found\n");
|
||||
}
|
||||
d = iniparser_getdouble(ini, "wine:alcohol", -1.0);
|
||||
if (d>0.0) {
|
||||
printf("alcohol: [%g]\n", d);
|
||||
} else {
|
||||
printf("alcohol: not found\n");
|
||||
}
|
||||
|
||||
iniparser_freedict(ini);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
76
src/CMakeLists.txt
Normal file
76
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
project(libcsync)
|
||||
|
||||
add_subdirectory(std)
|
||||
|
||||
find_package(Sqlite3 REQUIRED)
|
||||
|
||||
set(CSYNC_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
CACHE INTERNAL "csync public include directories"
|
||||
)
|
||||
|
||||
set(CSYNC_PRIVATE_INCLUDE_DIRS
|
||||
${SQLITE3_INCLUDE_DIRS}
|
||||
${INIPARSER_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(CSYNC_LIBRARY
|
||||
csync
|
||||
CACHE INTERNAL "csync library"
|
||||
)
|
||||
|
||||
set(CSYNC_LINK_LIBRARIES
|
||||
${CSYNC_LIBRARY}
|
||||
${CSTDLIB_LIBRARY}
|
||||
${INIPARSER_LIBRARIES}
|
||||
${LOG4C_LIBRARIES}
|
||||
${SQLITE3_LIBRARIES}
|
||||
dl
|
||||
)
|
||||
|
||||
set(csync_SRCS
|
||||
csync.c
|
||||
csync_journal.c
|
||||
csync_lock.c
|
||||
csync_util.c
|
||||
)
|
||||
|
||||
set(csync_HDRS
|
||||
csync.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
${CSYNC_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(${CSYNC_LIBRARY} SHARED ${csync_SRCS})
|
||||
|
||||
target_link_libraries(${CSYNC_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${CSYNC_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
0.1.0
|
||||
SOVERSION
|
||||
0
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
TARGETS
|
||||
${CSYNC_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${csync_HDRS}
|
||||
DESTINATION
|
||||
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
||||
)
|
||||
|
178
src/csync.c
Normal file
178
src/csync.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006-2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program 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, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* asprintf */
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
#include "csync_lock.h"
|
||||
#include "csync_journal.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.api"
|
||||
#include "csync_log.h"
|
||||
|
||||
int csync_create(CSYNC **csync) {
|
||||
CSYNC *ctx;
|
||||
|
||||
ctx = c_malloc(sizeof(CSYNC));
|
||||
if (ctx == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->internal = c_malloc(sizeof(csync_internal_t));
|
||||
if (ctx->internal == NULL) {
|
||||
SAFE_FREE(ctx);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->options.max_depth = MAX_DEPTH;
|
||||
ctx->options.max_time_difference = MAX_TIME_DIFFERENCE;
|
||||
|
||||
if (asprintf(&ctx->options.config_dir, "%s/%s", getenv("HOME"), CSYNC_CONF_DIR) < 0) {
|
||||
SAFE_FREE(ctx->internal);
|
||||
SAFE_FREE(ctx);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->init = csync_init;
|
||||
ctx->destroy = csync_destroy;
|
||||
ctx->version = csync_version;
|
||||
|
||||
*csync = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csync_init(CSYNC *ctx) {
|
||||
int rc;
|
||||
char *log = NULL;
|
||||
char *journal = NULL;
|
||||
char *lock = NULL;
|
||||
|
||||
if (ctx == NULL || ctx->internal == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Do not initialize twice */
|
||||
if (ctx->internal->_initialized) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* load log file */
|
||||
if (csync_log_init() < 0) {
|
||||
fprintf(stderr, "csync_init: logger init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create dir if it doesn't exist */
|
||||
if (! c_isdir(ctx->options.config_dir)) {
|
||||
c_mkdirs(ctx->options.config_dir, 0700);
|
||||
}
|
||||
|
||||
if (asprintf(&log, "%s/%s", ctx->options.config_dir, CSYNC_LOG_FILE) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* load log if it exists */
|
||||
if (c_isfile(log)) {
|
||||
csync_log_load(log);
|
||||
} else {
|
||||
if (c_copy(DATADIR "/csync/" CSYNC_LOG_FILE, log, 0644) == 0) {
|
||||
csync_log_load(log);
|
||||
}
|
||||
}
|
||||
|
||||
/* create lock file */
|
||||
if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (csync_lock(lock) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: load config */
|
||||
|
||||
/* TODO: load exclude list */
|
||||
|
||||
/* create/load journal */
|
||||
if (asprintf(&journal, "%s/%s", ctx->options.config_dir, CSYNC_JOURNAL_FILE) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (csync_journal_load(ctx, journal) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx->internal->_initialized = 1;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
SAFE_FREE(log);
|
||||
SAFE_FREE(lock);
|
||||
SAFE_FREE(journal);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int csync_destroy(CSYNC *ctx) {
|
||||
char *lock = NULL;
|
||||
|
||||
/* TODO: write journal */
|
||||
|
||||
if (ctx->internal->_journal) {
|
||||
sqlite3_close(ctx->internal->_journal);
|
||||
}
|
||||
|
||||
if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) > 0) {
|
||||
csync_lock_remove(lock);
|
||||
}
|
||||
|
||||
csync_log_fini();
|
||||
|
||||
SAFE_FREE(ctx->options.config_dir);
|
||||
|
||||
SAFE_FREE(ctx->internal);
|
||||
SAFE_FREE(ctx);
|
||||
|
||||
SAFE_FREE(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *csync_version(void) {
|
||||
return CSYNC_VERSION_STRING;
|
||||
}
|
||||
|
128
src/csync.h
Normal file
128
src/csync.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006-2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program 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, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync.h
|
||||
*
|
||||
* @brief Application developer interface for csync.
|
||||
*
|
||||
* @defgroup csyncPublicAPI csync public API
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_H
|
||||
#define _CSYNC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* csync version information
|
||||
*/
|
||||
#define CSYNC_VERSION_MAJOR 0
|
||||
#define CSYNC_VERSION_MINOR 1
|
||||
#define CSYNC_VERSION_PATCH 0
|
||||
#define CSYNC_VERSION_STRING "csync version 0.1.0"
|
||||
|
||||
#undef __P
|
||||
#define __P(protos) protos
|
||||
|
||||
/**
|
||||
* How deep to scan directories.
|
||||
*/
|
||||
#define MAX_DEPTH 50
|
||||
|
||||
/**
|
||||
* Maximum time difference between two replicas in seconds
|
||||
*/
|
||||
#define MAX_TIME_DIFFERENCE 10
|
||||
|
||||
/*
|
||||
* csync file declarations
|
||||
*/
|
||||
#define CSYNC_CONF_DIR ".csync"
|
||||
#define CSYNC_CONF_FILE "csync.conf"
|
||||
#define CSYNC_LOG_FILE "csync_log.conf"
|
||||
#define CSYNC_EXCLUDE_FILE "csync_exclude.conf"
|
||||
#define CSYNC_JOURNAL_FILE "csync_journal.db"
|
||||
#define CSYNC_LOCK_FILE "lock"
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
struct csync_s; typedef struct csync_s CSYNC;
|
||||
struct csync_config_s; typedef struct csync_config_s csync_config_t;
|
||||
struct csync_internal_s; typedef struct csync_internal_s csync_internal_t;
|
||||
|
||||
/**
|
||||
* @brief csync public structure
|
||||
*/
|
||||
struct csync_s {
|
||||
int (*init) __P((CSYNC *));
|
||||
int (*update) __P((CSYNC *));
|
||||
int (*reconcile) __P((CSYNC *));
|
||||
int (*propagate) __P((CSYNC *));
|
||||
int (*destroy) __P((CSYNC *));
|
||||
const char *(*version) __P((void));
|
||||
|
||||
struct {
|
||||
int max_depth;
|
||||
int max_time_difference;
|
||||
char *config_dir;
|
||||
} options;
|
||||
|
||||
csync_internal_t *internal;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allocate a csync context.
|
||||
*
|
||||
* @param ctx context variable to allocate
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured with errno set.
|
||||
*/
|
||||
int csync_create __P((CSYNC **));
|
||||
|
||||
int csync_init __P((CSYNC *));
|
||||
|
||||
int csync_update __P((CSYNC *));
|
||||
|
||||
int csync_reconcile __P((CSYNC *));
|
||||
|
||||
int csync_propagate __P((CSYNC *));
|
||||
|
||||
int csync_destroy __P((CSYNC *));
|
||||
|
||||
const char *csync_version __P((void));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_H */
|
||||
|
271
src/csync_journal.c
Normal file
271
src/csync_journal.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "std/c_string.h"
|
||||
#include "csync_private.h"
|
||||
#include "csync_journal.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.journal"
|
||||
#include "csync_log.h"
|
||||
|
||||
static int csync_journal_check(const char *journal) {
|
||||
FILE *fp = NULL;
|
||||
char buf[16] = {0};
|
||||
sqlite3 *db = NULL;
|
||||
|
||||
/* check db version */
|
||||
fp = fopen(journal, "r");
|
||||
if (fp) {
|
||||
if (fread((void *) buf, (size_t) 16, 1, fp) == 0) {
|
||||
buf[16] = '\0';
|
||||
fclose(fp);
|
||||
if (c_streq(buf, "SQLite format 3")) {
|
||||
if (sqlite3_open(journal, &db ) == SQLITE_OK) {
|
||||
/* everything is fine */
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "database corrupted, removing!");
|
||||
unlink(journal);
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "sqlite version mismatch");
|
||||
unlink(journal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create database */
|
||||
if (sqlite3_open(journal, &db ) == SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int csync_journal_is_empty(CSYNC *ctx) {
|
||||
c_strlist_t *result = NULL;
|
||||
int rc = 0;
|
||||
|
||||
result = csync_journal_query(ctx, "SELECT COUNT(key) FROM metadata LIMIT 1 OFFSET 0;");
|
||||
if (result && result->count == 0) {
|
||||
rc = 1;
|
||||
}
|
||||
c_strlist_destroy(result);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int csync_journal_load(CSYNC *ctx, const char *journal) {
|
||||
if (csync_journal_check(journal) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sqlite3_open(journal, &ctx->internal->_journal) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (csync_journal_is_empty(ctx)) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "Journal doesn't exist");
|
||||
ctx->internal->_journal_exists = 0;
|
||||
} else {
|
||||
ctx->internal->_journal_exists = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: void csync_journal_create_tables(CSYNC *ctx) */
|
||||
/* TODO: void csync_journal_empty_tables(CSYNC *ctx) */
|
||||
|
||||
c_strlist_t *csync_journal_query(CSYNC *ctx, const char *statement) {
|
||||
int err;
|
||||
int rc = 0;
|
||||
size_t i = 0;
|
||||
size_t busy_count = 0;
|
||||
size_t retry_count = 0;
|
||||
size_t column_count = 0;
|
||||
sqlite3_stmt *stmt;
|
||||
const char *tail = NULL;
|
||||
c_strlist_t *result = NULL;
|
||||
|
||||
do {
|
||||
/* compile SQL program into a virtual machine, reattempteing if busy */
|
||||
do {
|
||||
if (busy_count) {
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %d", busy_count);
|
||||
}
|
||||
err = sqlite3_prepare(ctx->internal->_journal, statement, -1, &stmt, &tail);
|
||||
} while (err == SQLITE_BUSY && busy_count ++ < 120);
|
||||
|
||||
if (err != SQLITE_OK) {
|
||||
if (err == SQLITE_BUSY) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "sqlite3_compile error: %s - on query %s", sqlite3_errmsg(ctx->internal->_journal), statement);
|
||||
result = c_strlist_new(1);
|
||||
break;
|
||||
} else {
|
||||
busy_count = 0;
|
||||
column_count = sqlite3_column_count(stmt);
|
||||
|
||||
/* execute virtual machine by iterating over rows */
|
||||
for(;;) {
|
||||
err = sqlite3_step(stmt);
|
||||
|
||||
if (err == SQLITE_BUSY) {
|
||||
if (busy_count++ > 120) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
|
||||
break;
|
||||
}
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %d", busy_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (err == SQLITE_MISUSE) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
|
||||
}
|
||||
|
||||
if (err == SQLITE_DONE || err == SQLITE_ERROR) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = c_strlist_new(column_count);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* iterate over columns */
|
||||
for (i = 0; i < column_count; i++) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", (char *) sqlite3_column_text(stmt, i));
|
||||
if (c_strlist_add(result, (char *) sqlite3_column_text(stmt, i)) < 0) {
|
||||
c_strlist_destroy(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} /* end infinite for loop */
|
||||
|
||||
/* deallocate vm resources */
|
||||
rc = sqlite3_finalize(stmt);
|
||||
|
||||
if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(ctx->internal->_journal), statement);
|
||||
result = c_strlist_new(1);
|
||||
}
|
||||
|
||||
if (rc == SQLITE_SCHEMA) {
|
||||
retry_count ++;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement);
|
||||
if (retry_count < 10) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
|
||||
result = c_strlist_new(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (rc == SQLITE_SCHEMA && retry_count < 10);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int csync_journal_insert(CSYNC *ctx, const char *statement) {
|
||||
int err;
|
||||
int rc = 0;
|
||||
int busy_count = 0;
|
||||
int retry_count = 0;
|
||||
sqlite3_stmt *stmt;
|
||||
const char *tail;
|
||||
|
||||
do {
|
||||
/* compile SQL program into a virtual machine, reattempteing if busy */
|
||||
do {
|
||||
if (busy_count) {
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %d", busy_count);
|
||||
}
|
||||
err = sqlite3_prepare(ctx->internal->_journal, statement, -1, &stmt, &tail);
|
||||
} while (err == SQLITE_BUSY && busy_count++ < 120);
|
||||
|
||||
if (err != SQLITE_OK) {
|
||||
if (err == SQLITE_BUSY) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_compile error: %s on query %s", sqlite3_errmsg(ctx->internal->_journal), statement);
|
||||
break;
|
||||
} else {
|
||||
busy_count = 0;
|
||||
|
||||
/* execute virtual machine by iterating over rows */
|
||||
for(;;) {
|
||||
err = sqlite3_step(stmt);
|
||||
|
||||
if (err == SQLITE_BUSY) {
|
||||
if (busy_count++ > 120) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
|
||||
break;
|
||||
}
|
||||
/* sleep 100 msec */
|
||||
usleep(100000);
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %d", busy_count);
|
||||
}
|
||||
|
||||
if (err == SQLITE_MISUSE) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
|
||||
}
|
||||
|
||||
if (err == SQLITE_DONE || err == SQLITE_ERROR) {
|
||||
break;
|
||||
}
|
||||
} /* end infinite for loop */
|
||||
|
||||
/* deallocate vm resources */
|
||||
rc = sqlite3_finalize(stmt);
|
||||
|
||||
if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s on insert: %s", sqlite3_errmsg(ctx->internal->_journal), statement);
|
||||
}
|
||||
|
||||
if (rc == SQLITE_SCHEMA) {
|
||||
retry_count++;
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on insert: %s", statement);
|
||||
if (retry_count < 10) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (rc == SQLITE_SCHEMA && retry_count < 10);
|
||||
|
||||
return sqlite3_last_insert_rowid(ctx->internal->_journal);
|
||||
}
|
||||
|
80
src/csync_journal.h
Normal file
80
src/csync_journal.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_private.h
|
||||
*
|
||||
* @brief Private interface of csync
|
||||
*
|
||||
* @defgroup csyncJournalInternals csync journal internals
|
||||
* @ingroup csyncInternalAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_JOURNAL_H
|
||||
#define _CSYNC_JOURNAL_H
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
|
||||
/**
|
||||
* @brief Load the journal.
|
||||
*
|
||||
* This function tries to load the journal. If it doesn't exists it creates
|
||||
* the sqlite3 database, but doesn't create the tables. This will be done when
|
||||
* csync gets destroyed.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
* @param journal Path to the journal file (sqlite3 db).
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured with errno set.
|
||||
*/
|
||||
int csync_journal_load(CSYNC *ctx, const char *journal);
|
||||
|
||||
/**
|
||||
* @brief A generic Journal query.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
* @param statement The SQL statement to execute
|
||||
*
|
||||
* @return A stringlist of the entries of a column. An emtpy stringlist if
|
||||
* nothing has been found. NULL on error.
|
||||
*/
|
||||
c_strlist_t *csync_journal_query(CSYNC *ctx, const char *statement);
|
||||
|
||||
/**
|
||||
* @brief Insert function for the journal.
|
||||
*
|
||||
* @param ctx The csync context.
|
||||
* @param statement The SQL statement to insert into the journal.
|
||||
*
|
||||
* @return The rowid of the most recent INSERT on success, 0 if the query
|
||||
* wasn't successful.
|
||||
*/
|
||||
int csync_journal_insert(CSYNC *ctx, const char *statement);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_JOURNAL_H */
|
||||
|
155
src/csync_lock.c
Normal file
155
src/csync_lock.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_lock.h"
|
||||
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.lock"
|
||||
#include "csync_log.h"
|
||||
|
||||
static int csync_lock_create(const char *lockfile) {
|
||||
int fd, pid, rc = -1;
|
||||
char *tmpfile = NULL;
|
||||
char *dir = NULL;
|
||||
char *buf = NULL;
|
||||
|
||||
pid = getpid();
|
||||
|
||||
dir = c_dirname(lockfile);
|
||||
if (dir == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (asprintf(&tmpfile, "%s/tmp_lock_XXXXXX", dir) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Create temporary lock file: %s", tmpfile);
|
||||
if ((fd = mkstemp(tmpfile)) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to create temporary lock file: %s - %s", tmpfile, strerror(errno));
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Write pid (%d) to temporary lock file: %s", pid, tmpfile);
|
||||
pid = asprintf(&buf, "%d\n", pid);
|
||||
if (write(fd, buf, pid) == pid) {
|
||||
/* Create lock file */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Create a hardlink from %s to %s.", tmpfile, lockfile);
|
||||
if (link(tmpfile, lockfile) < 0 ) {
|
||||
/* Oops, alredy locked */
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Already locked: %s - %s", lockfile, strerror(errno));
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Can't create %s - %s", tmpfile, strerror(errno));
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
unlink(tmpfile);
|
||||
|
||||
SAFE_FREE(buf);
|
||||
SAFE_FREE(dir);
|
||||
SAFE_FREE(tmpfile);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static pid_t csync_lock_read(const char *lockfile) {
|
||||
char buf[8] = {0};
|
||||
int fd, pid;
|
||||
|
||||
/* Read PID from existing lock */
|
||||
if ((fd = open(lockfile, O_RDONLY)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
|
||||
if (pid <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
pid = strtol(buf, NULL, 10);
|
||||
if (!pid || errno == ERANGE) {
|
||||
/* Broken lock file */
|
||||
if (unlink(lockfile) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to remove broken lock %s - %s", lockfile, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if process is still alive */
|
||||
if (kill(pid, 0) < 0 && errno == ESRCH) {
|
||||
/* Process is dead. Remove stale lock. */
|
||||
if (unlink(lockfile) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to remove stale lock %s - %s", lockfile, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int csync_lock(const char *lockfile) {
|
||||
/* Check if lock already exists. */
|
||||
if (csync_lock_read(lockfile) > 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Aborting, another synchronization process is running.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Creating lock file: %s", lockfile);
|
||||
|
||||
return csync_lock_create(lockfile);
|
||||
}
|
||||
|
||||
void csync_lock_remove(const char *lockfile) {
|
||||
/* You can't remove the lock if it is from another process */
|
||||
if (csync_lock_read(lockfile) == getpid()) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Removing lock file: %s", lockfile);
|
||||
if (unlink(lockfile) < 0) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Unable to remove lock %s - %s", lockfile, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
src/csync_lock.h
Normal file
65
src/csync_lock.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_LOCK_H
|
||||
#define _CSYNC_LOCK_H
|
||||
|
||||
/**
|
||||
* @file csync_lock.h
|
||||
*
|
||||
* @brief File locking
|
||||
*
|
||||
* This prevents csync to start the same synchronization task twice which could
|
||||
* lead to several problems.
|
||||
*
|
||||
* @defgroup csyncLockingInternals csync file lockling internals
|
||||
* @ingroup csyncInternalAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Lock the client if possible.
|
||||
*
|
||||
* This functiion tries to lock the client with a lock file.
|
||||
*
|
||||
* @param lockfile The lock file to create.
|
||||
*
|
||||
* @return 0 if the lock was successfull, less than 0 if the lock file
|
||||
* couldn't be created or if it is already locked.
|
||||
*/
|
||||
int csync_lock(const char *lockfile);
|
||||
|
||||
/**
|
||||
* @brief Remove the lockfile
|
||||
*
|
||||
* Only our own lock can be removed. This function can't remove a lock from
|
||||
* another client.
|
||||
*
|
||||
* @param lockfile The lock file to remove.
|
||||
*/
|
||||
void csync_lock_remove(const char *lockfile);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_LOCK_H */
|
151
src/csync_log.h
Normal file
151
src/csync_log.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_log.h
|
||||
*
|
||||
* @brief Logging interface of csync
|
||||
*
|
||||
* @defgroup csyncLogInternals csync logging internals
|
||||
* @ingroup csyncInternalAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_LOG_H
|
||||
#define _CSYNC_LOG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef WITH_LOG4C
|
||||
#include "log4c.h"
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifndef CSYNC_LOG_CATEGORY_NAME
|
||||
#define CSYNC_LOG_CATEGORY_NAME "root"
|
||||
#endif
|
||||
|
||||
#define CSYNC_LOG(priority, fmt, rest...) \
|
||||
csync_log(CSYNC_LOG_CATEGORY_NAME, priority, fmt, ##rest)
|
||||
|
||||
#ifdef WITH_LOG4C
|
||||
#define CSYNC_LOG_PRIORITY_FATAL LOG4C_PRIORITY_FATAL
|
||||
#define CSYNC_LOG_PRIORITY_ALERT LOG4C_PRIORITY_ALERT
|
||||
#define CSYNC_LOG_PRIORITY_CRIT LOG4C_PRIORITY_CRIT
|
||||
#define CSYNC_LOG_PRIORITY_ERROR LOG4C_PRIORITY_ERROR
|
||||
#define CSYNC_LOG_PRIORITY_WARN LOG4C_PRIORITY_WARN
|
||||
#define CSYNC_LOG_PRIORITY_NOTICE LOG4C_PRIORITY_NOTICE
|
||||
#define CSYNC_LOG_PRIORITY_INFO LOG4C_PRIORITY_INFO
|
||||
#define CSYNC_LOG_PRIORITY_DEBUG LOG4C_PRIORITY_DEBUG
|
||||
#define CSYNC_LOG_PRIORITY_TRACE LOG4C_PRIORITY_TRACE
|
||||
#define CSYNC_LOG_PRIORITY_NOTSET LOG4C_PRIORITY_NOTSET
|
||||
#define CSYNC_LOG_PRIORITY_UNKNOWN LOG4C_PRIORITY_UNKNOWN
|
||||
#else
|
||||
#define LOG4C_INLINE inline
|
||||
#define CSYNC_LOG_PRIORITY_FATAL 000
|
||||
#define CSYNC_LOG_PRIORITY_ALERT 100
|
||||
#define CSYNC_LOG_PRIORITY_CRIT 200
|
||||
#define CSYNC_LOG_PRIORITY_ERROR 300
|
||||
#define CSYNC_LOG_PRIORITY_WARN 500
|
||||
#define CSYNC_LOG_PRIORITY_NOTICE 500
|
||||
#define CSYNC_LOG_PRIORITY_INFO 600
|
||||
#define CSYNC_LOG_PRIORITY_DEBUG 700
|
||||
#define CSYNC_LOG_PRIORITY_TRACE 800
|
||||
#define CSYNC_LOG_PRIORITY_NOTSET 900
|
||||
#define CSYNC_LOG_PRIORITY_UNKNOWN 1000
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The constructor of the logging mechanism
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
static LOG4C_INLINE int csync_log_init() {
|
||||
#ifdef WITH_LOG4C
|
||||
return (log4c_init());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load resource configuration file
|
||||
*
|
||||
* @param Path to the file to load
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
**/
|
||||
static LOG4C_INLINE int csync_log_load(const char *path){
|
||||
#ifdef WITH_LOG4C
|
||||
return (log4c_load(path));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The destructor of the logging mechanism
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
static LOG4C_INLINE int csync_log_fini(){
|
||||
#ifdef WITH_LOG4C
|
||||
return(log4c_fini());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static LOG4C_INLINE int csync_log_setappender(char *catName, char *appName) {
|
||||
#ifdef WITH_LOG4C
|
||||
log4c_category_set_appender(log4c_category_get(catName),log4c_appender_get(appName));
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static LOG4C_INLINE void csync_log(char *catName, int a_priority, const char* a_format,...) {
|
||||
#ifdef WITH_LOG4C
|
||||
const log4c_category_t* a_category = log4c_category_get(catName);
|
||||
if (log4c_category_is_priority_enabled(a_category, a_priority)) {
|
||||
va_list va;
|
||||
va_start(va, a_format);
|
||||
log4c_category_vlog(a_category, a_priority, a_format, va);
|
||||
va_end(va);
|
||||
}
|
||||
#else
|
||||
va_list va;
|
||||
va_start(va, a_format);
|
||||
vprintf(a_format, va);
|
||||
va_end(va);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_LOG_H */
|
||||
|
33
src/csync_macros.h
Normal file
33
src/csync_macros.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_MACROS_H
|
||||
#define _CSYNC_MACROS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* How many elements there are in a static array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#endif /* _CSYNC_MACROS_H */
|
67
src/csync_private.h
Normal file
67
src/csync_private.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file csync_private.h
|
||||
*
|
||||
* @brief Private interface of csync
|
||||
*
|
||||
* @defgroup csyncInternalAPI csync internal API
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_PRIVATE_H
|
||||
#define _CSYNC_PRIVATE_H
|
||||
|
||||
#define _GNU_SOURCE /* asprintf */
|
||||
#include <stdlib.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
|
||||
#include "csync_macros.h"
|
||||
|
||||
/**
|
||||
* Maximum size of a buffer for transfer
|
||||
*/
|
||||
#define MAX_XFER_BUF_SIZE 16348
|
||||
|
||||
enum csync_replica_e {
|
||||
LOCAL_REPLICA,
|
||||
REMOTE_REPLCIA
|
||||
};
|
||||
|
||||
struct csync_internal_s {
|
||||
c_rbtree_t *_local;
|
||||
c_rbtree_t *_remote;
|
||||
sqlite3 *_journal;
|
||||
int _journal_exists;
|
||||
int _initialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CSYNC_PRIVATE_H */
|
||||
|
24
src/csync_util.c
Normal file
24
src/csync_util.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include "csync_util.h"
|
||||
|
26
src/csync_util.h
Normal file
26
src/csync_util.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#ifndef _CSYNC_UTIL_H
|
||||
#define _CSYNC_UTIL_H
|
||||
|
||||
#endif /* _CSYNC_UTIL_H */
|
35
src/std/CMakeLists.txt
Normal file
35
src/std/CMakeLists.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
project(cstdlib)
|
||||
|
||||
set(CSTDLIB_PUBLIC_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
CACHE INTERNAL "cstdlib public include directories"
|
||||
)
|
||||
|
||||
set(CSYNC_PRIVATE_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
set(CSTDLIB_LIBRARY
|
||||
cstdlib
|
||||
CACHE INTERNAL "cstdlib library"
|
||||
)
|
||||
|
||||
set(CSTDLIB_LINK_LIBRARIES
|
||||
${CSTDLIB_LIBRARY}
|
||||
)
|
||||
|
||||
set(cstdlib_SRCS
|
||||
c_alloc.c
|
||||
c_dir.c
|
||||
c_file.c
|
||||
c_path.c
|
||||
c_rbtree.c
|
||||
c_string.c
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CSTDLIB_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(${CSTDLIB_LIBRARY} STATIC ${cstdlib_SRCS})
|
||||
#target_link_libraries(${CSTDLIB_LINK_LIBRARIES})
|
58
src/std/c_alloc.c
Normal file
58
src/std/c_alloc.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
|
||||
void *c_calloc(size_t count, size_t size) {
|
||||
if (size == 0 || count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
#undef calloc
|
||||
return calloc(count, size);
|
||||
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_XCALLOC_INSTEAD
|
||||
}
|
||||
|
||||
void *c_malloc(size_t size) {
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
#undef malloc
|
||||
return c_calloc(1, size);
|
||||
#define malloc(x) DO_NOT_CALL_MALLOC__USE_XMALLOC_INSTEAD
|
||||
}
|
||||
|
||||
void *c_realloc(void *ptr, size_t size) {
|
||||
#undef realloc
|
||||
return realloc(ptr, size);
|
||||
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_XREALLOC_INSTEAD
|
||||
}
|
||||
|
||||
char *c_strdup(const char *str) {
|
||||
char *ret;
|
||||
ret = (char *) c_malloc(strlen(str) + 1);
|
||||
strcpy(ret, str);
|
||||
return ret;
|
||||
}
|
||||
|
102
src/std/c_alloc.h
Normal file
102
src/std/c_alloc.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_alloc.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc alloc function
|
||||
*
|
||||
* @defgroup cynLibraryAPI cynapses libc API (internal)
|
||||
*
|
||||
* @defgroup cynAllocInternals cynapses libc alloc functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_ALLOC_H
|
||||
#define _C_ALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c_macro.h"
|
||||
|
||||
/**
|
||||
* @brief Allocates memory for an array.
|
||||
*
|
||||
* Allocates memory for an array of <count> elements of <size> bytes each and
|
||||
* returns a pointer to the allocated memory. The memory is set to zero.
|
||||
*
|
||||
* @param count Amount of elements to allocate
|
||||
* @param size Size in bytes of each element to allocate.
|
||||
*
|
||||
* @return A unique pointer value that can later be successfully passed to
|
||||
* free(). If size or count is 0, NULL will be returned.
|
||||
*/
|
||||
void *c_calloc(size_t count, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocates memory for an array.
|
||||
*
|
||||
* Allocates <size> bytes of memory. The memory is set to zero.
|
||||
*
|
||||
* @param size Size in bytes to allocate.
|
||||
*
|
||||
* @return A unique pointer value that can later be successfully passed to
|
||||
* free(). If size or count is 0, NULL will be returned.
|
||||
*/
|
||||
void *c_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Changes the size of the memory block pointed to.
|
||||
*
|
||||
* Newly allocated memory will be uninitialized.
|
||||
*
|
||||
* @param ptr Pointer to the memory which should be resized.
|
||||
* @param size Value to resize.
|
||||
*
|
||||
* @return If ptr is NULL, the call is equivalent to c_malloc(size); if size
|
||||
* is equal to zero, the call is equivalent to free(ptr). Unless ptr
|
||||
* is NULL, it must have been returned by an earlier call to
|
||||
* c_malloc(), c_calloc() or c_realloc(). If the area pointed to was
|
||||
* moved, a free(ptr) is done.
|
||||
*/
|
||||
void *c_realloc(void *ptr, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a string.
|
||||
*
|
||||
* The function returns a pointer to a newly allocated string which is a
|
||||
* duplicate of the string str.
|
||||
*
|
||||
* @param str String to duplicate.
|
||||
*
|
||||
* @return Returns a pointer to the duplicated string, or NULL if insufficient
|
||||
* memory was available.
|
||||
*
|
||||
*/
|
||||
char *c_strdup(const char *str);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_ALLOC_H */
|
68
src/std/c_dir.c
Normal file
68
src/std/c_dir.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_dir.h"
|
||||
|
||||
int c_mkdirs(const char *path, mode_t mode) {
|
||||
int tmp;
|
||||
struct stat sb;
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lstat(path, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = strlen(path);
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] != '/') --tmp;
|
||||
while(tmp > 0 && path[tmp - 1] == '/') --tmp;
|
||||
|
||||
if (tmp > 0) {
|
||||
char subpath[tmp + 1];
|
||||
memcpy(subpath, path, tmp);
|
||||
subpath[tmp] = '\0';
|
||||
|
||||
if (lstat(subpath, &sb) == 0) {
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
} else if (errno != ENOENT) {
|
||||
return -1;
|
||||
} else if (c_mkdirs(subpath, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = mkdir(path, mode);
|
||||
if (errno == EEXIST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int c_isdir(const char *path) {
|
||||
struct stat sb;
|
||||
|
||||
if (lstat (path, &sb) < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
77
src/std/c_dir.h
Normal file
77
src/std/c_dir.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_dir.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc directory function
|
||||
*
|
||||
* @defgroup cynDirInternals cynapses libc directory functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_DIR_H
|
||||
#define _C_DIR_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create parent directories as needed.
|
||||
*
|
||||
* The newly created directory will be owned by the effective user ID of the
|
||||
* process.
|
||||
*
|
||||
* @param path The path to the directory to create.
|
||||
*
|
||||
* @param mode Specifies the permissions to use. It is modified
|
||||
* by the process's umask in the usual way: the
|
||||
* permissions of the created file are (mode & ~umask).
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set:
|
||||
* - EACCES The parent directory does not allow write
|
||||
* permission to the process, or one of the directories
|
||||
* - ENOTDIR if durl is not a directory
|
||||
* - EINVAL NULL durl passed or smbc_init not called.
|
||||
* - ENOMEM Insufficient memory was available.
|
||||
*
|
||||
* @see mkdir()
|
||||
*/
|
||||
int c_mkdirs(const char *path, mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a directory.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a directory, 0 if the path doesn't exist, is a
|
||||
* file or can't be accessed.
|
||||
*/
|
||||
int c_isdir(const char *path);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _CDIR_H */
|
||||
|
122
src/std/c_file.c
Normal file
122
src/std/c_file.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "c_file.h"
|
||||
#include "c_string.h"
|
||||
|
||||
/* check if path is a file */
|
||||
int c_isfile(const char *path) {
|
||||
struct stat sb;
|
||||
|
||||
if (lstat (path, &sb) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copy file from src to dst, overwrites dst */
|
||||
int c_copy(const char* src, const char *dst, mode_t mode) {
|
||||
int srcfd, dstfd, rc;
|
||||
ssize_t bread, bwritten;
|
||||
struct stat sb;
|
||||
char buf[MAX_XFER_BUF_SIZE];
|
||||
|
||||
if (c_streq(src, dst)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lstat(src, &sb) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
mode = sb.st_mode;
|
||||
}
|
||||
|
||||
if (lstat(dst, &sb) == 0) {
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((srcfd = open(src, O_RDONLY, 0)) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode)) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
bread = read(srcfd, buf, MAX_XFER_BUF_SIZE);
|
||||
if (bread == 0) {
|
||||
/* done */
|
||||
break;
|
||||
} else if (bread < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bwritten = write(dstfd, buf, bread);
|
||||
if (bwritten < 0) {
|
||||
errno = ENODATA;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bread != bwritten) {
|
||||
errno = EFAULT;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
close(srcfd);
|
||||
close(dstfd);
|
||||
if (rc < 0) {
|
||||
unlink(dst);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
70
src/std/c_file.h
Normal file
70
src/std/c_file.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_file.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc file function
|
||||
*
|
||||
* @defgroup cynFileInternals cynapses libc file functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_FILE_H
|
||||
#define _C_FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef MAX_XFER_BUF_SIZE
|
||||
#define MAX_XFER_BUF_SIZE 16348
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check if a path is a regular file or a link.
|
||||
*
|
||||
* @param path The path to check.
|
||||
*
|
||||
* @return 1 if the path is a file, 0 if the path doesn't exist, is a
|
||||
* something else or can't be accessed.
|
||||
*/
|
||||
int c_isfile(const char *path);
|
||||
|
||||
/**
|
||||
* @brief copy a file from source to destination.
|
||||
*
|
||||
* @param src Path to the source file
|
||||
* @param dst Path to the destination file
|
||||
* @param mode File creation mode of the destination. If mode is 0 then the
|
||||
* mode from the source will be used.
|
||||
*
|
||||
* @return 0 on success, less then 0 on error with errno set.
|
||||
* EISDIR if src or dst is a file.
|
||||
*/
|
||||
int c_copy(const char *src, const char *dst, mode_t mode);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_FILE_H */
|
||||
|
245
src/std/c_jhash.h
Normal file
245
src/std/c_jhash.h
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* c_jhash.c Jenkins Hash
|
||||
*
|
||||
* Copyright (c) 1997 Bob Jenkins <bob_jenkins@burtleburtle.net>
|
||||
*
|
||||
* lookup8.c, by Bob Jenkins, January 4 1997, Public Domain.
|
||||
* hash(), hash2(), hash3, and _c_mix() are externally useful functions.
|
||||
* Routines to test the hash are included if SELF_TEST is defined.
|
||||
* You can use this free for any purpose. It has no warranty.
|
||||
*
|
||||
* See http://burtleburtle.net/bob/hash/evahash.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_jhash.h
|
||||
*
|
||||
* @brief Interface of the cynapses jhash implementation
|
||||
*
|
||||
* @defgroup cynJHashInternals cynapses libc jhash function
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_JHASH_H
|
||||
#define _C_JHASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define c_hashsize(n) ((uint8_t) 1 << (n))
|
||||
#define c_hashmask(n) (xhashsize(n) - 1)
|
||||
|
||||
/**
|
||||
* _c_mix -- Mix 3 32-bit values reversibly.
|
||||
*
|
||||
* For every delta with one or two bit set, and the deltas of all three
|
||||
* high bits or all three low bits, whether the original value of a,b,c
|
||||
* is almost all zero or is uniformly distributed,
|
||||
* If _c_mix() is run forward or backward, at least 32 bits in a,b,c
|
||||
* have at least 1/4 probability of changing.
|
||||
* If _c_mix() is run forward, every bit of c will change between 1/3 and
|
||||
* 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
|
||||
* _c_mix() was built out of 36 single-cycle latency instructions in a
|
||||
* structure that could supported 2x parallelism, like so:
|
||||
* a -= b;
|
||||
* a -= c; x = (c>>13);
|
||||
* b -= c; a ^= x;
|
||||
* b -= a; x = (a<<8);
|
||||
* c -= a; b ^= x;
|
||||
* c -= b; x = (b>>13);
|
||||
* ...
|
||||
*
|
||||
* Unfortunately, superscalar Pentiums and Sparcs can't take advantage
|
||||
* of that parallelism. They've also turned some of those single-cycle
|
||||
* latency instructions into multi-cycle latency instructions. Still,
|
||||
* this is the fastest good hash I could find. There were about 2^^68
|
||||
* to choose from. I only looked at a billion or so.
|
||||
*/
|
||||
#define _c_mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
/**
|
||||
* _c_mix64 -- Mix 3 64-bit values reversibly.
|
||||
*
|
||||
* _c_mix64() takes 48 machine instructions, but only 24 cycles on a superscalar
|
||||
* machine (like Intel's new MMX architecture). It requires 4 64-bit
|
||||
* registers for 4::2 parallelism.
|
||||
* All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of
|
||||
* (a,b,c), and all deltas of bottom bits were tested. All deltas were
|
||||
* tested both on random keys and on keys that were nearly all zero.
|
||||
* These deltas all cause every bit of c to change between 1/3 and 2/3
|
||||
* of the time (well, only 113/400 to 287/400 of the time for some
|
||||
* 2-bit delta). These deltas all cause at least 80 bits to change
|
||||
* among (a,b,c) when the _c_mix is run either forward or backward (yes it
|
||||
* is reversible).
|
||||
* This implies that a hash using _c_mix64 has no funnels. There may be
|
||||
* characteristics with 3-bit deltas or bigger, I didn't test for
|
||||
* those.
|
||||
*/
|
||||
#define _c_mix64(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>43); \
|
||||
b -= c; b -= a; b ^= (a<<9); \
|
||||
c -= a; c -= b; c ^= (b>>8); \
|
||||
a -= b; a -= c; a ^= (c>>38); \
|
||||
b -= c; b -= a; b ^= (a<<23); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>35); \
|
||||
b -= c; b -= a; b ^= (a<<49); \
|
||||
c -= a; c -= b; c ^= (b>>11); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<18); \
|
||||
c -= a; c -= b; c ^= (b>>22); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash a variable-length key into a 32-bit value
|
||||
*
|
||||
* The best hash table sizes are powers of 2. There is no need to do
|
||||
* mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||
* use a bitmask. For example, if you need only 10 bits, do
|
||||
* h = (h & hashmask(10));
|
||||
* In which case, the hash table should have hashsize(10) elements.
|
||||
*
|
||||
* Use for hash table lookup, or anything where one collision in 2^32 is
|
||||
* acceptable. Do NOT use for cryptographic purposes.
|
||||
*
|
||||
* @param k The key (the unaligned variable-length array of bytes).
|
||||
*
|
||||
* @param length The length of the key, counting by bytes.
|
||||
*
|
||||
* @param initval Initial value, can be any 4-byte value.
|
||||
*
|
||||
* @return Returns a 32-bit value. Every bit of the key affects every bit
|
||||
* of the return value. Every 1-bit and 2-bit delta achieves
|
||||
* avalanche. About 36+6len instructions.
|
||||
*/
|
||||
static inline uint32_t c_jhash(uint8_t *k, uint32_t length, uint32_t initval) {
|
||||
uint32_t a,b,c,len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||
c = initval; /* the previous hash value */
|
||||
|
||||
while (len >= 12) {
|
||||
a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
|
||||
b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
|
||||
c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
|
||||
_c_mix(a,b,c);
|
||||
k += 12; len -= 12;
|
||||
}
|
||||
|
||||
/* handle the last 11 bytes */
|
||||
c += length;
|
||||
/* all the case statements fall through */
|
||||
switch(len) {
|
||||
case 11: c+=((uint32_t)k[10]<<24);
|
||||
case 10: c+=((uint32_t)k[9]<<16);
|
||||
case 9 : c+=((uint32_t)k[8]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 8 : b+=((uint32_t)k[7]<<24);
|
||||
case 7 : b+=((uint32_t)k[6]<<16);
|
||||
case 6 : b+=((uint32_t)k[5]<<8);
|
||||
case 5 : b+=k[4];
|
||||
case 4 : a+=((uint32_t)k[3]<<24);
|
||||
case 3 : a+=((uint32_t)k[2]<<16);
|
||||
case 2 : a+=((uint32_t)k[1]<<8);
|
||||
case 1 : a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
_c_mix(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash a variable-length key into a 64-bit value
|
||||
*
|
||||
* The best hash table sizes are powers of 2. There is no need to do
|
||||
* mod a prime (mod is sooo slow!). If you need less than 64 bits,
|
||||
* use a bitmask. For example, if you need only 10 bits, do
|
||||
* h = (h & hashmask(10));
|
||||
* In which case, the hash table should have hashsize(10) elements.
|
||||
*
|
||||
* Use for hash table lookup, or anything where one collision in 2^^64
|
||||
* is acceptable. Do NOT use for cryptographic purposes.
|
||||
*
|
||||
* @param k The key (the unaligned variable-length array of bytes).
|
||||
* @param length The length of the key, counting by bytes.
|
||||
* @param intval Initial value, can be any 8-byte value.
|
||||
*
|
||||
* @return A 64-bit value. Every bit of the key affects every bit of
|
||||
* the return value. No funnels. Every 1-bit and 2-bit delta
|
||||
* achieves avalanche. About 41+5len instructions.
|
||||
*/
|
||||
static inline uint64_t c_jhash64(uint8_t *k, uint64_t length, uint64_t intval) {
|
||||
uint64_t a,b,c,len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = intval; /* the previous hash value */
|
||||
c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */
|
||||
|
||||
/* handle most of the key */
|
||||
while (len >= 24)
|
||||
{
|
||||
a += (k[0] +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24)
|
||||
+((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56));
|
||||
b += (k[8] +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24)
|
||||
+((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56));
|
||||
c += (k[16] +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24)
|
||||
+((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56));
|
||||
_c_mix64(a,b,c);
|
||||
k += 24; len -= 24;
|
||||
}
|
||||
|
||||
/* handle the last 23 bytes */
|
||||
c += length;
|
||||
switch(len) {
|
||||
case 23: c+=((uint64_t)k[22]<<56);
|
||||
case 22: c+=((uint64_t)k[21]<<48);
|
||||
case 21: c+=((uint64_t)k[20]<<40);
|
||||
case 20: c+=((uint64_t)k[19]<<32);
|
||||
case 19: c+=((uint64_t)k[18]<<24);
|
||||
case 18: c+=((uint64_t)k[17]<<16);
|
||||
case 17: c+=((uint64_t)k[16]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 16: b+=((uint64_t)k[15]<<56);
|
||||
case 15: b+=((uint64_t)k[14]<<48);
|
||||
case 14: b+=((uint64_t)k[13]<<40);
|
||||
case 13: b+=((uint64_t)k[12]<<32);
|
||||
case 12: b+=((uint64_t)k[11]<<24);
|
||||
case 11: b+=((uint64_t)k[10]<<16);
|
||||
case 10: b+=((uint64_t)k[ 9]<<8);
|
||||
case 9: b+=((uint64_t)k[ 8]);
|
||||
case 8: a+=((uint64_t)k[ 7]<<56);
|
||||
case 7: a+=((uint64_t)k[ 6]<<48);
|
||||
case 6: a+=((uint64_t)k[ 5]<<40);
|
||||
case 5: a+=((uint64_t)k[ 4]<<32);
|
||||
case 4: a+=((uint64_t)k[ 3]<<24);
|
||||
case 3: a+=((uint64_t)k[ 2]<<16);
|
||||
case 2: a+=((uint64_t)k[ 1]<<8);
|
||||
case 1: a+=((uint64_t)k[ 0]);
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
_c_mix64(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_JHASH_H */
|
||||
|
29
src/std/c_lib.h
Normal file
29
src/std/c_lib.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_dir.h"
|
||||
#include "c_file.h"
|
||||
#include "c_path.h"
|
||||
#include "c_rbtree.h"
|
||||
#include "c_string.h"
|
84
src/std/c_macro.h
Normal file
84
src/std/c_macro.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_macro.h
|
||||
*
|
||||
* @brief cynapses libc macro definitions
|
||||
*
|
||||
* @defgroup cynMacroInternals cynapses libc macro definitions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_MACRO_H
|
||||
#define _C_MACRO_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
#define malloc(x) DO_NOT_CALL_MALLOC__USE_C_MALLOC_INSTEAD
|
||||
|
||||
#ifdef calloc
|
||||
#undef calloc
|
||||
#endif
|
||||
#define calloc(x,y) DO_NOT_CALL_CALLOC__USE_C_CALLOC_INSTEAD
|
||||
|
||||
#ifdef realloc
|
||||
#undef realloc
|
||||
#endif
|
||||
#define realloc(x,y) DO_NOT_CALL_REALLOC__USE_C_REALLOC_INSTEAD
|
||||
|
||||
#ifdef dirname
|
||||
#undef dirname
|
||||
#endif
|
||||
#define dirname(x) DO_NOT_CALL_MALLOC__USE_C_DIRNAME_INSTEAD
|
||||
|
||||
#ifdef basename
|
||||
#undef basename
|
||||
#endif
|
||||
#define basename(x) DO_NOT_CALL_MALLOC__USE_C_BASENAME_INSTEAD
|
||||
|
||||
#ifdef strdup
|
||||
#undef strdup
|
||||
#endif
|
||||
#define strdup(x) DO_NOT_CALL_STRDUP__USE_C_STRDUP_INSTEAD
|
||||
|
||||
#define INT_TO_POINTER(i) (void *) i
|
||||
#define POINTER_TO_INT(p) *((int *) (p))
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
/** Zero a structure given a pointer to the structure */
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
|
||||
/** Free memory and zero the pointer */
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_MACRO_H */
|
||||
|
110
src/std/c_path.c
Normal file
110
src/std/c_path.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2007-2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "c_alloc.h"
|
||||
#include "c_path.h"
|
||||
|
||||
/*
|
||||
* dirname - parse directory component.
|
||||
*/
|
||||
char *c_dirname (const char *path) {
|
||||
char *newpath;
|
||||
register int length;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
newpath = c_strdup(".");
|
||||
return newpath;
|
||||
}
|
||||
|
||||
length = strlen(path);
|
||||
/* Remove trailing slashes */
|
||||
while(length > 0 && path[length - 1] == '/') --length;
|
||||
/* We have only slashes */
|
||||
if (length == 0) {
|
||||
newpath = c_strdup("/");
|
||||
return newpath;
|
||||
}
|
||||
/* goto next slash */
|
||||
while(length > 0 && path[length - 1] != '/') --length;
|
||||
if (length == 0) {
|
||||
newpath = c_strdup(".");
|
||||
return newpath;
|
||||
} else if (length == 1) {
|
||||
newpath = c_strdup("/");
|
||||
return newpath;
|
||||
}
|
||||
|
||||
/* Remove slashes again */
|
||||
while(length > 0 && path[length - 1] == '/') --length;
|
||||
|
||||
newpath = (char *) c_malloc(length + 1);
|
||||
if (newpath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(newpath, path, length);
|
||||
newpath[length] = '\0';
|
||||
|
||||
return newpath;
|
||||
}
|
||||
|
||||
char *c_basename (const char *path) {
|
||||
char *newpath;
|
||||
char *slash;
|
||||
register int length;
|
||||
|
||||
if (path == NULL || *path == '\0') {
|
||||
newpath = c_strdup(".");
|
||||
return newpath;
|
||||
}
|
||||
|
||||
length = strlen(path);
|
||||
/* Remove trailing slashes */
|
||||
while(length > 0 && path[length - 1] == '/') --length;
|
||||
/* We have only slashes */
|
||||
if (length == 0) {
|
||||
newpath = c_strdup("/");
|
||||
return newpath;
|
||||
}
|
||||
while(length > 0 && path[length - 1] != '/') --length;
|
||||
|
||||
if (length > 0) {
|
||||
slash = (char *) path + length;
|
||||
length = strlen(slash);
|
||||
while(length > 0 && slash[length - 1] == '/') --length;
|
||||
} else {
|
||||
newpath = c_strdup(path);
|
||||
return newpath;
|
||||
}
|
||||
newpath = (char *) c_malloc(length + 1);
|
||||
if (newpath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(newpath, slash, length);
|
||||
newpath[length] = '\0';
|
||||
|
||||
return newpath;
|
||||
}
|
||||
|
74
src/std/c_path.h
Normal file
74
src/std/c_path.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_path.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc path functions
|
||||
*
|
||||
* @defgroup cynPathInternals cynapses libc path functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _C_PATH_H
|
||||
#define _C_PATH_H
|
||||
|
||||
#include "c_macro.h"
|
||||
|
||||
/**
|
||||
* @brief Parse directory component.
|
||||
*
|
||||
* dirname breaks a null-terminated pathname string into a directory component.
|
||||
* In the usual case, c_dirname() returns the string up to, but not including,
|
||||
* the final '/'. Trailing '/' characters are not counted as part of the
|
||||
* pathname. The caller must free the memory.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The dirname of path or NULL if we can't allocate memory. If path
|
||||
* does not contain a slash, c_dirname() returns the string ".". If
|
||||
* path is the string "/", it returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *c_dirname(const char *path);
|
||||
|
||||
/**
|
||||
* @brief dirname - parse filename component.
|
||||
*
|
||||
* basename breaks a null-terminated pathname string into a filename component.
|
||||
* c_basename() returns the component following the final '/'. Trailing '/'
|
||||
* characters are not counted as part of the pathname.
|
||||
*
|
||||
* @param path The path to parse.
|
||||
*
|
||||
* @return The filename of path or NULL if we can't allocate memory. If path
|
||||
* is a the string "/", basename returns the string "/". If path is
|
||||
* NULL or an empty string, "." is returned.
|
||||
*/
|
||||
char *c_basename (const char *path);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_PATH_H */
|
753
src/std/c_rbtree.c
Normal file
753
src/std/c_rbtree.c
Normal file
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This is based on the red black tree from Y-Windows
|
||||
* http://www.y-windows.org/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/*
|
||||
* static function don't have NULL pointer checks, segfaults are intended.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c_alloc.h"
|
||||
#include "c_rbtree.h"
|
||||
|
||||
#define NIL &_sentinel /* all leafs are sentinels */
|
||||
static c_rbnode_t _sentinel = {NULL, NIL, NIL, NULL, NULL, BLACK};
|
||||
|
||||
int c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare) {
|
||||
c_rbtree_t *tree = NULL;
|
||||
|
||||
if (rbtree == NULL || key_compare == NULL || data_compare == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree = c_malloc(sizeof(*tree));
|
||||
if (tree == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree->root = NIL;
|
||||
tree->key_compare = key_compare;
|
||||
tree->data_compare = data_compare;
|
||||
tree->size = 0;
|
||||
|
||||
*rbtree = tree;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static c_rbnode_t *c_rbtree_subtree_dup(const c_rbnode_t *node, c_rbtree_t *new_tree, c_rbnode_t *new_parent) {
|
||||
c_rbnode_t *new_node = NULL;
|
||||
|
||||
new_node = (c_rbnode_t*) c_malloc(sizeof(c_rbnode_t));
|
||||
|
||||
new_node->tree = new_tree;
|
||||
new_node->data = node->data;
|
||||
new_node->color = node->color;
|
||||
new_node->parent = new_parent;
|
||||
|
||||
if (node->left == NIL) {
|
||||
new_node->left = NIL;
|
||||
} else {
|
||||
new_node->left = c_rbtree_subtree_dup(node->left, new_tree, new_node);
|
||||
}
|
||||
|
||||
if (node->right == NIL) {
|
||||
new_node->right = NIL;
|
||||
} else {
|
||||
new_node->right = c_rbtree_subtree_dup(node->right, new_tree, new_node);
|
||||
}
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree) {
|
||||
c_rbtree_t *new_tree = NULL;
|
||||
|
||||
new_tree = (c_rbtree_t*) c_malloc(sizeof(c_rbtree_t));
|
||||
|
||||
new_tree->key_compare = tree->key_compare;
|
||||
new_tree->data_compare = tree->data_compare;
|
||||
new_tree->size = tree->size;
|
||||
new_tree->root = c_rbtree_subtree_dup(tree->root, new_tree, NULL);
|
||||
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
static int c_rbtree_subtree_free(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node->left != NIL) {
|
||||
if (c_rbtree_subtree_free(node->left) < 0) {
|
||||
/* TODO: set errno? ECANCELED? */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
if (c_rbtree_subtree_free(node->right) < 0) {
|
||||
/* TODO: set errno? ECANCELED? */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_free(c_rbtree_t *tree) {
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tree->root != NIL) {
|
||||
c_rbtree_subtree_free(tree->root);
|
||||
}
|
||||
|
||||
SAFE_FREE(tree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c_rbtree_subtree_walk(c_rbnode_t *node, void *data, c_rbtree_visit_func *visitor) {
|
||||
assert(node);
|
||||
assert(data);
|
||||
assert(visitor);
|
||||
|
||||
if (node == NIL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c_rbtree_subtree_walk(node->left, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*visitor)(node->data, data) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c_rbtree_subtree_walk(node->right, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor) {
|
||||
if (tree == NULL || data == NULL || visitor == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c_rbtree_subtree_walk(tree->root, data, visitor) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static c_rbnode_t *c_rbtree_subtree_head(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return node;
|
||||
}
|
||||
|
||||
while (node->left != NIL) {
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static c_rbnode_t *c_rbtree_subtree_tail(c_rbnode_t *node) {
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return node;
|
||||
}
|
||||
|
||||
while (node->right != NIL) {
|
||||
node = node->right;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_head(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = c_rbtree_subtree_head(tree->root);
|
||||
|
||||
return node != NIL ? node : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = c_rbtree_subtree_tail(tree->root);
|
||||
|
||||
return node != NIL ? node : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node) {
|
||||
c_rbnode_t *parent = NULL;
|
||||
|
||||
if (node == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
c_rbnode_t *next = NULL;
|
||||
next = c_rbtree_subtree_head(node->right);
|
||||
|
||||
return next != NIL ? next : NULL;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
while (parent && node == parent->right) {
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
|
||||
return parent != NULL ? parent : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node) {
|
||||
c_rbnode_t *parent = NULL;
|
||||
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node->left != NIL) {
|
||||
c_rbnode_t *prev = NULL;
|
||||
prev = c_rbtree_subtree_tail(node->left);
|
||||
return prev != NIL ? prev : NULL;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
while (parent && node == parent->left) {
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
|
||||
return parent != NULL ? parent : NULL;
|
||||
}
|
||||
|
||||
c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key) {
|
||||
int cmp = 0;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
node = tree->root;
|
||||
|
||||
while (node != NIL) {
|
||||
cmp = tree->key_compare(key, node->data);
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (cmp < 0) {
|
||||
node = node->left;
|
||||
} else {
|
||||
node = node->right;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void c_rbtree_subtree_left_rotate(c_rbnode_t *x) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
assert(x);
|
||||
|
||||
y = x->right;
|
||||
|
||||
/* establish x-right link */
|
||||
x->right = y->left;
|
||||
|
||||
if (y->left != NIL) {
|
||||
y->left->parent = x;
|
||||
}
|
||||
|
||||
/* establish y->parent link */
|
||||
if (y != NIL) {
|
||||
y->parent = x->parent;
|
||||
}
|
||||
|
||||
if (x->parent) {
|
||||
if (x == x->parent->left) {
|
||||
x->parent->left = y;
|
||||
} else {
|
||||
x->parent->right = y;
|
||||
}
|
||||
} else {
|
||||
x->tree->root = y;
|
||||
}
|
||||
|
||||
/* link x and y */
|
||||
y->left = x;
|
||||
if (x != NIL) {
|
||||
x->parent = y;
|
||||
}
|
||||
}
|
||||
|
||||
/* rotat node x to the right */
|
||||
static void c_rbtree_subtree_right_rotate(c_rbnode_t *x) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
assert(x);
|
||||
|
||||
y = x->left;
|
||||
|
||||
/* establish x->left link */
|
||||
x->left = y->right;
|
||||
|
||||
if (y->right != NIL) {
|
||||
y->right->parent = x;
|
||||
}
|
||||
|
||||
/* establish y->parent link */
|
||||
if (y != NIL) {
|
||||
y->parent = x->parent;
|
||||
}
|
||||
|
||||
if (x->parent) {
|
||||
if (x == x->parent->right) {
|
||||
x->parent->right = y;
|
||||
} else {
|
||||
x->parent->left = y;
|
||||
}
|
||||
} else {
|
||||
x->tree->root = y;
|
||||
}
|
||||
|
||||
/* link x and y */
|
||||
y->right = x;
|
||||
if (x != NIL) {
|
||||
x->parent = y;
|
||||
}
|
||||
}
|
||||
|
||||
int c_rbtree_insert(c_rbtree_t *tree, void *data) {
|
||||
int cmp = 0;
|
||||
c_rbnode_t *current = NULL;
|
||||
c_rbnode_t *parent = NULL;
|
||||
c_rbnode_t *x = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First we do a classic binary tree insert */
|
||||
current = tree->root;
|
||||
parent = NULL;
|
||||
|
||||
while (current != NIL) {
|
||||
cmp = tree->data_compare(data, current->data);
|
||||
parent = current;
|
||||
if (cmp == 0) {
|
||||
return 1;
|
||||
} else if (cmp < 0) {
|
||||
current = current->left;
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
|
||||
x = (c_rbnode_t *) c_malloc(sizeof(c_rbnode_t));
|
||||
if (x == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
x->tree = tree;
|
||||
x->data = data;
|
||||
x->parent = parent;
|
||||
x->left = NIL;
|
||||
x->right = NIL;
|
||||
x->color = RED;
|
||||
|
||||
if (parent) {
|
||||
/* Note that cmp still contains the comparison of data with
|
||||
* parent->data, from the last pass through the loop above
|
||||
*/
|
||||
if (cmp < 0) {
|
||||
parent->left = x;
|
||||
} else {
|
||||
parent->right = x;
|
||||
}
|
||||
} else {
|
||||
tree->root = x;
|
||||
}
|
||||
|
||||
/* Insert fixup - check red-black properties */
|
||||
while (x != tree->root && x->parent->color == RED) {
|
||||
/* we have a violation */
|
||||
if (x->parent == x->parent->parent->left) {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
y = x->parent->parent->right;
|
||||
if (y->color == RED) {
|
||||
x->parent->color = BLACK;
|
||||
y->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
x = x->parent->parent;
|
||||
} else {
|
||||
/* uncle is back */
|
||||
if (x == x->parent->right) {
|
||||
/* make x a left child */
|
||||
x = x->parent;
|
||||
c_rbtree_subtree_left_rotate(x);
|
||||
}
|
||||
x->parent->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
c_rbtree_subtree_right_rotate(x->parent->parent);
|
||||
}
|
||||
} else {
|
||||
c_rbnode_t *y = NULL;
|
||||
|
||||
y = x->parent->parent->left;
|
||||
if (y->color == RED) {
|
||||
x->parent->color = BLACK;
|
||||
y->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
x = x->parent->parent;
|
||||
} else {
|
||||
/* uncle is back */
|
||||
if (x == x->parent->left) {
|
||||
x = x->parent;
|
||||
c_rbtree_subtree_right_rotate(x);
|
||||
}
|
||||
x->parent->color = BLACK;
|
||||
x->parent->parent->color = RED;
|
||||
c_rbtree_subtree_left_rotate(x->parent->parent);
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
tree->root->color = BLACK;
|
||||
|
||||
tree->size++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c_rbtree_node_delete(c_rbnode_t *node) {
|
||||
c_rbtree_t *tree = NULL;
|
||||
c_rbnode_t *y = NULL;
|
||||
c_rbnode_t *x = NULL;
|
||||
|
||||
if (node == NULL || node == NIL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tree = node->tree;
|
||||
|
||||
if (node->left == NIL || node->right == NIL) {
|
||||
/* y has a NIL node as a child */
|
||||
y = node;
|
||||
} else {
|
||||
/* find tree successor with a NIL node as a child */
|
||||
while(y != NIL) {
|
||||
y = y->left;
|
||||
}
|
||||
}
|
||||
|
||||
/* x is y's only child */
|
||||
if (y->left != NIL) {
|
||||
x = y->left;
|
||||
} else {
|
||||
x = y->right;
|
||||
}
|
||||
|
||||
/* remove y from the parent chain */
|
||||
x->parent = y->parent;
|
||||
|
||||
if (y->parent) {
|
||||
if (y == y->parent->left) {
|
||||
y->parent->left = x;
|
||||
} else {
|
||||
y->parent->right = x;
|
||||
}
|
||||
} else {
|
||||
y->tree->root = x;
|
||||
}
|
||||
|
||||
/* If y is not the node we're deleting, splice it in place of that
|
||||
* node
|
||||
*
|
||||
* The traditional code would call for us to simply copy y->data, but
|
||||
* that would invalidate the wrong pointer - there might be external
|
||||
* references to this node, and we must preserve its address.
|
||||
*/
|
||||
if (y != node) {
|
||||
/* Update y */
|
||||
y->parent = node->parent;
|
||||
y->left = node->left;
|
||||
y->right = node->right;
|
||||
|
||||
/* Update the children and the parent */
|
||||
if (y->left != NIL) {
|
||||
y->left->parent = y;
|
||||
}
|
||||
if (y->right != NIL) {
|
||||
y->right->parent = y;
|
||||
}
|
||||
if (y->parent != NULL) {
|
||||
if (node == y->parent->left) {
|
||||
y->parent->left = y;
|
||||
} else {
|
||||
y->parent->right = y;
|
||||
}
|
||||
} else {
|
||||
y->tree->root = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (y->color == BLACK) {
|
||||
while (x != y->tree->root && x->color == BLACK) {
|
||||
if (x == x->parent->left) {
|
||||
c_rbnode_t *w = NULL;
|
||||
|
||||
w = x->parent->right;
|
||||
|
||||
if (w->color == RED) {
|
||||
w->color = BLACK;
|
||||
x->parent->color = RED;
|
||||
c_rbtree_subtree_left_rotate(x->parent);
|
||||
w = x->parent->right;
|
||||
}
|
||||
|
||||
if (w->left->color == BLACK && w->right->color == BLACK) {
|
||||
w->color = RED;
|
||||
x = x->parent;
|
||||
} else {
|
||||
if (w->right->color == BLACK) {
|
||||
w->left->color = BLACK;
|
||||
w->color = RED;
|
||||
c_rbtree_subtree_right_rotate(w);
|
||||
w = x->parent->right;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = BLACK;
|
||||
w->right->color = BLACK;
|
||||
c_rbtree_subtree_left_rotate(x->parent);
|
||||
x = y->tree->root;
|
||||
}
|
||||
} else {
|
||||
c_rbnode_t *w = NULL;
|
||||
|
||||
w = x->parent->left;
|
||||
if (w->color == RED) {
|
||||
w->color = BLACK;
|
||||
x->parent->color = RED;
|
||||
c_rbtree_subtree_right_rotate(x->parent);
|
||||
w = x->parent->left;
|
||||
}
|
||||
|
||||
if (w->right->color == BLACK && w->left->color == BLACK) {
|
||||
w->color = RED;
|
||||
x = x->parent;
|
||||
} else {
|
||||
if (w->left->color == BLACK) {
|
||||
w->right->color = BLACK;
|
||||
w->color = RED;
|
||||
c_rbtree_subtree_left_rotate(w);
|
||||
w = x->parent->left;
|
||||
}
|
||||
w->color = x->parent->color;
|
||||
x->parent->color = BLACK;
|
||||
w->left->color = BLACK;
|
||||
c_rbtree_subtree_right_rotate(x->parent);
|
||||
x = y->tree->root;
|
||||
}
|
||||
}
|
||||
}
|
||||
x->color = BLACK;
|
||||
} /* end if: y->color == BLACK */
|
||||
|
||||
/* node has now been spliced out of the tree */
|
||||
SAFE_FREE(y);
|
||||
tree->size--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c_rbtree_subtree_check_black_height(c_rbnode_t *node) {
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
assert(node);
|
||||
|
||||
if (node == NIL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
left = c_rbtree_subtree_check_black_height(node->left);
|
||||
right = c_rbtree_subtree_check_black_height(node->right);
|
||||
if (left != right) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return left + (node->color == BLACK);
|
||||
}
|
||||
|
||||
int c_rbtree_check_sanity(c_rbtree_t *tree) {
|
||||
c_rbnode_t *node = NULL;
|
||||
c_rbnode_t *prev = NULL;
|
||||
c_rbnode_t *next = NULL;
|
||||
c_rbnode_t *tail = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (tree == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! tree->key_compare || ! tree->data_compare) {
|
||||
errno = EINVAL;
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Iterate the tree */
|
||||
tail = c_rbtree_tail(tree);
|
||||
for (node = c_rbtree_head(tree); node; node = next) {
|
||||
if (node->tree != tree) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* We should never see a nil while iterating */
|
||||
if (node == NIL) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* node == tree-root iff node->parent == NIL */
|
||||
if (node == tree->root) {
|
||||
if (node->parent != NULL) {
|
||||
return -6;
|
||||
}
|
||||
} else {
|
||||
if (node->parent == NULL) {
|
||||
return -7;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invertability of the iterate functions */
|
||||
if (prev != c_rbtree_node_prev(node)) {
|
||||
return -8;
|
||||
}
|
||||
|
||||
/* Check the iteration sequence */
|
||||
if (prev) {
|
||||
if (tree->data_compare(prev->data, node->data) > 0) {
|
||||
return -9;
|
||||
}
|
||||
|
||||
/* And the other way around, to make sure data_compare is stable */
|
||||
if (tree->data_compare(node->data, prev->data) < 0) {
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
|
||||
/* The binary tree property */
|
||||
if (node->left != NIL) {
|
||||
if (tree->data_compare(node->left->data, node->data) > 0) {
|
||||
return -11;
|
||||
}
|
||||
|
||||
if (tree->data_compare(node->data, node->left->data) < 0) {
|
||||
return -11;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->right != NIL) {
|
||||
if (tree->data_compare(node->data, node->right->data) > 0) {
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (tree->data_compare(node->right->data, node->data) < 0) {
|
||||
return -13;
|
||||
}
|
||||
}
|
||||
|
||||
/* Red-black tree property 3: red nodes have black children */
|
||||
if (node->color == RED) {
|
||||
if (node->left->color == RED) {
|
||||
return -14;
|
||||
}
|
||||
if (node->right->color == RED) {
|
||||
return -15;
|
||||
}
|
||||
}
|
||||
|
||||
/* next == NULL if node == tail */
|
||||
next = c_rbtree_node_next(node);
|
||||
if (next) {
|
||||
if (node == tail) {
|
||||
return -16;
|
||||
}
|
||||
} else {
|
||||
if (node != tail) {
|
||||
return -17;
|
||||
}
|
||||
}
|
||||
|
||||
prev = node;
|
||||
size++;
|
||||
} /* end for loop */
|
||||
|
||||
if (size != tree->size) {
|
||||
return -18;
|
||||
}
|
||||
|
||||
if (c_rbtree_subtree_check_black_height(tree->root) < 0) {
|
||||
return -19;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
313
src/std/c_rbtree.h
Normal file
313
src/std/c_rbtree.h
Normal file
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
* libcsync -- a library to sync a directory with another
|
||||
*
|
||||
* Copyright (c) 2003-2004 by Andrew Suffield <asuffield@debian.org>
|
||||
* Copyright (c) 2007 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ft=c.doxygen ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_rbtree.h
|
||||
*
|
||||
* @brief Interface of the cynapses libc red-black tree implementation
|
||||
*
|
||||
* A red-black tree is a type of self-balancing binary search tree. It is
|
||||
* complex, but has good worst-case running time for its operations and is
|
||||
* efficient in practice: it can search, insert, and delete in O(log n)
|
||||
* time, where n is the number of elements in the tree.
|
||||
*
|
||||
* In red-black trees, the leaf nodes are not relevant and do not contain
|
||||
* data. Therefore we use a sentinal node to save memory. All references
|
||||
* from internal nodes to leaf nodes instead point to the sentinel node.
|
||||
*
|
||||
* In a red-black tree each node has a color attribute, the value of which
|
||||
* is either red or black. In addition to the ordinary requirements imposed
|
||||
* on binary search trees, the following additional requirements of any
|
||||
* valid red-black tree apply:
|
||||
*
|
||||
* 1. A node is either red or black.
|
||||
* 2. The root is black.
|
||||
* 3. All leaves are black, even when the parent is black
|
||||
* (The leaves are the null children.)
|
||||
* 4. Both children of every red node are black.
|
||||
* 5. Every simple path from a node to a descendant leaf contains the same
|
||||
* number of black nodes, either counting or not counting the null black
|
||||
* nodes. (Counting or not counting the null black nodes does not affect
|
||||
* the structure as long as the choice is used consistently.).
|
||||
*
|
||||
* These constraints enforce a critical property of red-black trees: that the
|
||||
* longest path from the root to a leaf is no more than twice as long as the
|
||||
* shortest path from the root to a leaf in that tree. The result is that the
|
||||
* tree is roughly balanced. Since operations such as inserting, deleting, and
|
||||
* finding values requires worst-case time proportional to the height of the
|
||||
* tree, this theoretical upper bound on the height allows red-black trees to
|
||||
* be efficient in the worst-case, unlike ordinary binary search trees.
|
||||
*
|
||||
* http://en.wikipedia.org/wiki/Red-black_tree
|
||||
*
|
||||
* @defgroup cynRBTreeInternals cynapses libc red-black tree functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_RBTREE_H
|
||||
#define _C_RBTREE_H
|
||||
|
||||
/* Forward declarations */
|
||||
struct c_rbtree_s; typedef struct c_rbtree_s c_rbtree_t;
|
||||
struct c_rbnode_s; typedef struct c_rbnode_s c_rbnode_t;
|
||||
|
||||
/**
|
||||
* Define the two colors for the red-black tree
|
||||
*/
|
||||
enum xrbcolor_e { BLACK = 0, RED }; typedef enum xrbcolor_e xrbcolor_t;
|
||||
|
||||
/**
|
||||
* @brief Callback function to compare a key with the data from a
|
||||
* red-black tree node.
|
||||
*
|
||||
* @param key key as a generic pointer
|
||||
* @param data data as a generic pointer
|
||||
*
|
||||
* @return It returns an integer less than, equal to, or greater than zero
|
||||
* depending on the key or data you use. The function is similar
|
||||
* to strcmp().
|
||||
*/
|
||||
typedef int c_rbtree_compare_func(const void *key, const void *data);
|
||||
|
||||
/**
|
||||
* @brief Visit function for the c_rbtree_walk() function.
|
||||
*
|
||||
* This function will be called by c_rbtree_walk() for every node. It is up to
|
||||
* the developer what the function does. The fist parameter is a node object
|
||||
* the second can be of any kind.
|
||||
*
|
||||
* @param obj The node data that will be passed by c_rbtree_walk().
|
||||
* @param data Generic data pointer.
|
||||
*
|
||||
* @return 0 on success, < 0 on error. You should set errno.
|
||||
*
|
||||
*/
|
||||
typedef int c_rbtree_visit_func(void *obj, void *data);
|
||||
|
||||
/**
|
||||
* Structure that represents a red-black tree
|
||||
*/
|
||||
struct c_rbtree_s {
|
||||
c_rbnode_t *root;
|
||||
c_rbtree_compare_func *key_compare;
|
||||
c_rbtree_compare_func *data_compare;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure that represents a node of a red-black tree
|
||||
*/
|
||||
struct c_rbnode_s {
|
||||
c_rbtree_t *tree;
|
||||
c_rbnode_t *left;
|
||||
c_rbnode_t *right;
|
||||
c_rbnode_t *parent;
|
||||
void *data;
|
||||
xrbcolor_t color;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create the red-black tree
|
||||
*
|
||||
* @param rbtree The pointer to assign the allocated memory.
|
||||
*
|
||||
* @param key_compare Callback function to compare a key with the data
|
||||
* inside a reb-black tree node.
|
||||
*
|
||||
* @param data_compare Callback function to compare a key as data with thee
|
||||
* data inside a red-black tree node.
|
||||
*
|
||||
* @return 0 on success, -1 if an error occured with errno set.
|
||||
*/
|
||||
int c_rbtree_create(c_rbtree_t **rbtree, c_rbtree_compare_func *key_compare, c_rbtree_compare_func *data_compare);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a red-black tree.
|
||||
*
|
||||
* @param tree Tree to duplicate.
|
||||
*
|
||||
* @return Pointer to a new allocated duplicated rbtree. NULL if an error
|
||||
* occured.
|
||||
*/
|
||||
c_rbtree_t *c_rbtree_dup(const c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Free the structure of a red-black tree.
|
||||
*
|
||||
* You should call c_rbtree_destroy() before you call this function.
|
||||
*
|
||||
* @param tree The tree to free.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int c_rbtree_free(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Destroy the content and the nodes of an red-black tree.
|
||||
*
|
||||
* This is far from the most efficient way to walk a tree, but it is
|
||||
* the *safest* way to destroy a tree - the destructor can do almost
|
||||
* anything (as long as it does not create an infinite loop) to the
|
||||
* tree structure without risk.
|
||||
*
|
||||
* If for some strange reason you need a faster destructor (think
|
||||
* twice - speed and memory deallocation don't mix well) then consider
|
||||
* stashing an llist of dataects and destroying that instead, and just
|
||||
* using c_rbtree_free() on your tree.
|
||||
*
|
||||
* @param T The tree to destroy.
|
||||
* @param DESTRUCTOR The destructor to call on a node to destroy.
|
||||
*/
|
||||
#define c_rbtree_destroy(T, DESTRUCTOR) \
|
||||
do { \
|
||||
if (T) { \
|
||||
c_rbnode_t *_c_rbtree_temp; \
|
||||
while ((_c_rbtree_temp = c_rbtree_head(T))) { \
|
||||
(DESTRUCTOR)(_c_rbtree_temp->data); \
|
||||
if (_c_rbtree_temp == c_rbtree_head(T)) { \
|
||||
c_rbtree_node_delete(_c_rbtree_temp); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
SAFE_FREE(T); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Inserts a node into a red black tree.
|
||||
*
|
||||
* @param tree The red black tree to insert the node.
|
||||
* @param data The data to insert into the tree.
|
||||
*
|
||||
* @return 0 on success, 1 if a duplicate has been found and < 0 if an error
|
||||
* occured with errno set.
|
||||
* EINVAL if a null pointer has been passed as the tree.
|
||||
* ENOMEM if there is no memory left.
|
||||
*/
|
||||
int c_rbtree_insert(c_rbtree_t *tree, void *data);
|
||||
|
||||
/**
|
||||
* @brief Find a node in a red-black tree.
|
||||
*
|
||||
* c_rbtree_find() is searching for the given key in a red-black tree and
|
||||
* returns the node if the key has been found.
|
||||
*
|
||||
* @param tree The tree to search.
|
||||
* @param key The key to search for.
|
||||
*
|
||||
* @return If the key was found the node will be returned. On error NULL
|
||||
* will be returned.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_find(c_rbtree_t *tree, const void *key);
|
||||
|
||||
/**
|
||||
* @brief Get the head of the red-black tree.
|
||||
*
|
||||
* @param tree The tree to get the head for.
|
||||
*
|
||||
* @return The head node. NULL if an error occured.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_head(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Get the tail of the red-black tree.
|
||||
*
|
||||
* @param tree The tree to get the tail for.
|
||||
*
|
||||
* @return The tail node. NULL if an error occured.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_tail(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* @brief Get the size of the red-black tree.
|
||||
*
|
||||
* @param T The tree to get the size from.
|
||||
*
|
||||
* @return The size of the red-black tree.
|
||||
*/
|
||||
#define c_rbtree_size(T) ((T)->size)
|
||||
|
||||
/**
|
||||
* @brief Walk over a red-black tree.
|
||||
*
|
||||
* Walk over a red-black tree calling a visitor function for each node found.
|
||||
*
|
||||
* @param tree Tree to walk.
|
||||
* @param data Data which should be passed to the visitor function.
|
||||
* @param visitor Visitor function. This will be called for each node passed.
|
||||
*
|
||||
* @return 0 on sucess, less than 0 if an error occured.
|
||||
*/
|
||||
int c_rbtree_walk(c_rbtree_t *tree, void *data, c_rbtree_visit_func *visitor);
|
||||
|
||||
/**
|
||||
* @brief Delete a node in a red-black tree.
|
||||
*
|
||||
* @param node Node which should be deleted.
|
||||
*
|
||||
* @return 0 on success, -1 if an error occured.
|
||||
*/
|
||||
int c_rbtree_node_delete(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the next node.
|
||||
*
|
||||
* @param node The node of which you want the next node.
|
||||
*
|
||||
* @return The next node, NULL if an error occured.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_node_next(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the previous node.
|
||||
*
|
||||
* @param node The node of which you want the previous node.
|
||||
*
|
||||
* @return The previous node, NULL if an error occured.
|
||||
*/
|
||||
c_rbnode_t *c_rbtree_node_prev(c_rbnode_t *node);
|
||||
|
||||
/**
|
||||
* @brief Get the data of a node.
|
||||
*
|
||||
* @param N The node to get the data from.
|
||||
*
|
||||
* @return The data, NULL if an error occured.
|
||||
*/
|
||||
#define c_rbtree_node_data(N) ((N) ? ((N)->data) : NULL)
|
||||
|
||||
/**
|
||||
* @brief Perform a sanity check for a red-black tree.
|
||||
*
|
||||
* This is mostly for testing purposes.
|
||||
*
|
||||
* @param tree The tree to check.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int c_rbtree_check_sanity(c_rbtree_t *tree);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_RBTREE_H */
|
100
src/std/c_string.c
Normal file
100
src/std/c_string.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "c_string.h"
|
||||
#include "c_alloc.h"
|
||||
#include "c_macro.h"
|
||||
|
||||
int c_streq(const char *a, const char *b) {
|
||||
register const char *s1 = a;
|
||||
register const char *s2 = b;
|
||||
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*s1 == *s2++) {
|
||||
if (*s1++ == '\0') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
c_strlist_t *c_strlist_new(size_t size) {
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlist = c_malloc(sizeof(c_strlist_t));
|
||||
if (strlist == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlist->vector = c_malloc(size * sizeof(char *));
|
||||
if (strlist->vector == NULL) {
|
||||
SAFE_FREE(strlist);
|
||||
return NULL;
|
||||
}
|
||||
strlist->count = 0;
|
||||
strlist->size = size;
|
||||
|
||||
return strlist;
|
||||
}
|
||||
|
||||
int c_strlist_add(c_strlist_t *strlist, char *string) {
|
||||
if (strlist == NULL || string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlist->count < strlist->size) {
|
||||
strlist->vector[strlist->count] = c_strdup(string);
|
||||
if (strlist->vector[strlist->count] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
strlist->count++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void c_strlist_destroy(c_strlist_t *strlist) {
|
||||
size_t i = 0;
|
||||
|
||||
if (strlist == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < strlist->count; i++) {
|
||||
SAFE_FREE(strlist->vector[i]);
|
||||
}
|
||||
SAFE_FREE(strlist->vector);
|
||||
SAFE_FREE(strlist);
|
||||
}
|
||||
|
102
src/std/c_string.h
Normal file
102
src/std/c_string.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* cynapses libc functions
|
||||
*
|
||||
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* vim: ts=2 sw=2 et cindent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file c_string.h
|
||||
*
|
||||
* @brief Interface of the cynapses string implementations
|
||||
*
|
||||
* @defgroup cynStringInternals cynapses libc string functions
|
||||
* @ingroup cynLibraryAPI
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#ifndef _C_STR_H
|
||||
#define _C_STR_H
|
||||
|
||||
struct c_strlist_s; typedef struct c_strlist_s c_strlist_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for a stringlist
|
||||
*
|
||||
* Using a for loop you can access the strings saved in the vector.
|
||||
*
|
||||
* c_strlist_t strlist;
|
||||
* int i;
|
||||
* for (i = 0; i < strlist->count; i++) {
|
||||
* printf("value: %s", strlist->vector[i];
|
||||
* }
|
||||
*/
|
||||
struct c_strlist_s {
|
||||
/** The string vector */
|
||||
char **vector;
|
||||
/** The count of the strings saved in the vector */
|
||||
size_t count;
|
||||
/** Size of strings allocated */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare to strings if they are equal.
|
||||
*
|
||||
* @param a First string to compare.
|
||||
* @param b Second string to compare.
|
||||
*
|
||||
* @return 1 if they are equal, 0 if not.
|
||||
*/
|
||||
int c_streq(const char *a, const char *b);
|
||||
|
||||
/**
|
||||
* @brief Create a new stringlist.
|
||||
*
|
||||
* @param size Size to allocate.
|
||||
*
|
||||
* @return Pointer to the newly allocated stringlist. NULL if an error occured.
|
||||
*/
|
||||
c_strlist_t *c_strlist_new(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Add a string to the stringlist.
|
||||
*
|
||||
* Duplicates the string and stores it in the stringlist.
|
||||
*
|
||||
* @param strlist Stringlist to add the string.
|
||||
* @param string String to add.
|
||||
*
|
||||
* @return 0 on success, less than 0 if an error occured.
|
||||
*/
|
||||
int c_strlist_add(c_strlist_t *strlist, char *string);
|
||||
|
||||
/**
|
||||
* @brief Destroy the memory of the stringlist.
|
||||
*
|
||||
* Frees the strings and the stringlist.
|
||||
*
|
||||
* @param strlist Stringlist to destroy
|
||||
*/
|
||||
void c_strlist_destroy(c_strlist_t *strlist);
|
||||
|
||||
/**
|
||||
* }@
|
||||
*/
|
||||
#endif /* _C_STR_H */
|
||||
|
36
tests/CMakeLists.txt
Normal file
36
tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
project(tests)
|
||||
|
||||
set(SUPPORT_LIBRARY support)
|
||||
|
||||
include_directories(
|
||||
${CSYNC_PUBLIC_INCLUDE_DIRS}
|
||||
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
|
||||
${CHECK_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
# create test library
|
||||
add_library(${SUPPORT_LIBRARY} STATIC support.c)
|
||||
target_link_libraries(${SUPPORT_LIBRARY} ${CHECK_LIBRARIES} ${CSYNC_LIBRARY} ${CSTDLIB_LIBRARY})
|
||||
|
||||
set(TEST_TARGET_LIBRARIES ${SUPPORT_LIBRARY})
|
||||
|
||||
add_definitions(-DSOURCEDIR='\"${CMAKE_SOURCE_DIR}\"')
|
||||
|
||||
# create tests
|
||||
|
||||
# std
|
||||
macro_add_check_test(check_std_c_alloc std_tests/check_std_c_alloc.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_dir std_tests/check_std_c_dir.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_file std_tests/check_std_c_file.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_jhash std_tests/check_std_c_jhash.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_path std_tests/check_std_c_path.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_rbtree std_tests/check_std_c_rbtree.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_std_c_str std_tests/check_std_c_str.c ${TEST_TARGET_LIBRARIES})
|
||||
|
||||
# csync
|
||||
macro_add_check_test(check_logger log_tests/check_log.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_csync csync_tests/check_csync.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_csync_lock csync_tests/check_csync_lock.c ${TEST_TARGET_LIBRARIES})
|
||||
macro_add_check_test(check_csync_journal csync_tests/check_csync_journal.c ${TEST_TARGET_LIBRARIES})
|
||||
|
61
tests/csync_tests/check_csync.c
Normal file
61
tests/csync_tests/check_csync.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
CSYNC *csync;
|
||||
|
||||
static void setup(void) {
|
||||
csync_create(&csync);
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
csync_destroy(csync);
|
||||
}
|
||||
|
||||
START_TEST (csync_create_test)
|
||||
{
|
||||
fail_unless(csync_create(&csync) == 0, NULL);
|
||||
|
||||
fail_unless(csync->options.max_depth == MAX_DEPTH, NULL);
|
||||
fail_unless(csync->options.max_time_difference == MAX_TIME_DIFFERENCE, NULL);
|
||||
fail_unless(strcmp(csync->options.config_dir, CSYNC_CONF_DIR) > 0, NULL);
|
||||
|
||||
csync->destroy(csync);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (csync_init_test)
|
||||
{
|
||||
fail_unless(csync->init(csync) == 0, NULL);
|
||||
|
||||
fail_unless(csync->internal->_initialized == 1, NULL);
|
||||
|
||||
fail_unless(csync->init(csync) == 1, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *csync_suite(void) {
|
||||
Suite *s = suite_create("csync");
|
||||
|
||||
create_case(s, "csync_create_test", csync_create_test);
|
||||
create_case_fixture(s, "csync_init_test", csync_init_test, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = csync_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
60
tests/csync_tests/check_csync_journal.c
Normal file
60
tests/csync_tests/check_csync_journal.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
#include "csync_journal.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
CSYNC *csync;
|
||||
|
||||
static void setup(void) {
|
||||
csync_create(&csync);
|
||||
SAFE_FREE(csync->options.config_dir);
|
||||
csync->options.config_dir = c_strdup("/tmp/check_csync/");
|
||||
csync_init(csync);
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
csync_destroy(csync);
|
||||
system("rm -rf /tmp/check_csync");
|
||||
}
|
||||
|
||||
START_TEST (check_csync_journal_query_create_and_insert_table)
|
||||
{
|
||||
c_strlist_t *result = NULL;
|
||||
result = csync_journal_query(csync, "CREATE TABLE test(key INTEGER, text VARCHAR(10));");
|
||||
c_strlist_destroy(result);
|
||||
fail_unless(csync_journal_insert(csync, "INSERT INTO test (key, text) VALUES (42, 'hello');"), NULL);
|
||||
result = csync_journal_query(csync, "SELECT * FROM test;");
|
||||
fail_unless(result->count == 2, NULL);
|
||||
fail_unless(strcmp(result->vector[0], "42") == 0, NULL);
|
||||
fail_unless(strcmp(result->vector[1], "hello") == 0, NULL);
|
||||
c_strlist_destroy(result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
static Suite *csync_suite(void) {
|
||||
Suite *s = suite_create("csync_journal");
|
||||
|
||||
create_case_fixture(s, "check_csync_journal_query_create_and_insert_table", check_csync_journal_query_create_and_insert_table, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = csync_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_set_fork_status(sr, CK_NOFORK);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
88
tests/csync_tests/check_csync_lock.c
Normal file
88
tests/csync_tests/check_csync_lock.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_file.h"
|
||||
#include "csync_lock.h"
|
||||
|
||||
#define TEST_LOCK "/tmp/csync_lock/test"
|
||||
|
||||
static void setup(void) {
|
||||
system("mkdir -p /tmp/csync_lock");
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
system("rm -rf /tmp/csync_lock");
|
||||
}
|
||||
|
||||
START_TEST (check_csync_lock)
|
||||
{
|
||||
fail_unless(csync_lock(TEST_LOCK) == 0, NULL);
|
||||
fail_unless(c_isfile(TEST_LOCK) == 1, NULL);
|
||||
fail_unless(csync_lock(TEST_LOCK) < 0, NULL);
|
||||
|
||||
csync_lock_remove(TEST_LOCK);
|
||||
fail_unless(c_isfile(TEST_LOCK) == 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_csync_lock_content)
|
||||
{
|
||||
char buf[8] = {0};
|
||||
int fd, pid;
|
||||
|
||||
fail_unless(csync_lock(TEST_LOCK) == 0, NULL);
|
||||
fail_unless(c_isfile(TEST_LOCK) == 1, NULL);
|
||||
|
||||
/* open lock file */
|
||||
fd = open(TEST_LOCK, O_RDONLY);
|
||||
fail_if(fd < 0, NULL);
|
||||
|
||||
/* read content */
|
||||
pid = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
|
||||
fail_if(pid < 0, NULL);
|
||||
|
||||
/* get pid */
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
pid = strtol(buf, NULL, 10);
|
||||
|
||||
fail_unless(pid == getpid(), NULL);
|
||||
|
||||
csync_lock_remove(TEST_LOCK);
|
||||
fail_unless(c_isfile(TEST_LOCK) == 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
static Suite *csync_suite(void) {
|
||||
Suite *s = suite_create("csync_lock");
|
||||
|
||||
create_case_fixture(s, "check_csync_lock", check_csync_lock, setup, teardown);
|
||||
create_case_fixture(s, "check_csync_lock_content", check_csync_lock_content, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = csync_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
/* srunner_set_fork_status(sr, CK_NOFORK); */
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
78
tests/log_tests/check_log.c
Normal file
78
tests/log_tests/check_log.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
static void setup(void) {
|
||||
csync_log_init();
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
csync_log_fini();
|
||||
}
|
||||
|
||||
START_TEST (log_create)
|
||||
{
|
||||
fail_unless((csync_log_init() == 0), NULL);
|
||||
fail_unless((csync_log_fini() == 0), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_load)
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, (size_t) 256 - 1, "%s/%s", SOURCEDIR, "config/csync_log.conf");
|
||||
fail_unless(csync_log_load(buf) == 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_prio)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ALERT, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTSET, "log %s", "test");
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", "test");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (log_null)
|
||||
{
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_UNKNOWN, "log %s", NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *log_suite(void) {
|
||||
Suite *s = suite_create("Logger");
|
||||
|
||||
create_case(s, "log_create", log_create);
|
||||
create_case_fixture(s, "log_load", log_load, setup, teardown);
|
||||
create_case_fixture(s, "log_prio", log_prio, setup, teardown);
|
||||
create_case_fixture(s, "log_null", log_null, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = log_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
74
tests/std_tests/check_std_c_alloc.c
Normal file
74
tests/std_tests/check_std_c_alloc.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "support.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "std/c_alloc.h"
|
||||
|
||||
struct test_s {
|
||||
int answer;
|
||||
};
|
||||
|
||||
START_TEST (check_c_malloc)
|
||||
{
|
||||
struct test_s *p = NULL;
|
||||
p = c_malloc(sizeof(struct test_s));
|
||||
fail_unless(p != NULL, NULL);
|
||||
fail_unless(p->answer == 0, NULL);
|
||||
p->answer = 42;
|
||||
fail_unless(p->answer == 42, NULL);
|
||||
free(p);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_malloc_zero)
|
||||
{
|
||||
void *p;
|
||||
p = c_malloc((size_t) 0);
|
||||
fail_unless(p == NULL, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_strdup)
|
||||
{
|
||||
char *str = "test";
|
||||
char *dup;
|
||||
|
||||
dup = c_strdup(str);
|
||||
fail_unless(strcmp(dup, str) == 0, NULL);
|
||||
free(dup);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *make_c_malloc_suite(void) {
|
||||
Suite *s = suite_create("std:path:c_malloc");
|
||||
|
||||
create_case(s, "check_c_malloc", check_c_malloc);
|
||||
create_case(s, "check_c_malloc_zero", check_c_malloc_zero);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static Suite *make_c_strdup_suite(void) {
|
||||
Suite *s = suite_create("std:path:c_malloc");
|
||||
|
||||
create_case(s, "check_c_strdup", check_c_strdup);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_c_malloc_suite();
|
||||
Suite *s2 = make_c_strdup_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_add_suite (sr, s2);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
130
tests/std_tests/check_std_c_dir.c
Normal file
130
tests/std_tests/check_std_c_dir.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_dir.h"
|
||||
|
||||
const char *check_dir = "/tmp/check/c_mkdirs//with/check//";
|
||||
const char *check_file = "/tmp/check/c_mkdirs/with/check/foobar.txt";
|
||||
|
||||
static void setup(void) {
|
||||
c_mkdirs(check_dir, 0755);
|
||||
system("touch /tmp/check/c_mkdirs/with/check/foobar.txt");
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
system("rm -rf /tmp/check");
|
||||
}
|
||||
|
||||
static int test_dir(const char *path, mode_t mode) {
|
||||
struct stat sb;
|
||||
if (lstat(path, &sb) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! S_ISDIR(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME */
|
||||
if ((sb.st_mode & mode) == mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
START_TEST (check_c_mkdirs_new)
|
||||
{
|
||||
fail_unless(c_mkdirs(check_dir, 0755) == 0, NULL);
|
||||
fail_unless(test_dir(check_dir, 0755) == 0, NULL);
|
||||
system("rm -rf /tmp/check");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_mkdirs_mode)
|
||||
{
|
||||
fail_unless(c_mkdirs(check_dir, 0700) == 0, NULL);
|
||||
fail_unless(test_dir(check_dir, 0700) == 0, NULL);
|
||||
system("rm -rf /tmp/check");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_mkdirs_existing_path)
|
||||
{
|
||||
fail_unless(c_mkdirs(check_dir, 0755) == 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_mkdirs_file)
|
||||
{
|
||||
fail_unless(c_mkdirs(check_file, 0755) == -1 && errno == ENOTDIR, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_mkdirs_null)
|
||||
{
|
||||
fail_unless(c_mkdirs(NULL, 0755) == -1, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_isdir)
|
||||
{
|
||||
fail_unless(c_isdir(check_dir), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_isdir_on_file)
|
||||
{
|
||||
fail_unless(! c_isdir(check_file), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_isdir_null)
|
||||
{
|
||||
fail_unless(! c_isdir(NULL), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *make_std_c_mkdirs_suite(void) {
|
||||
Suite *s = suite_create("std:dir:c_mkdirs");
|
||||
|
||||
create_case(s, "check_c_mkdirs_new", check_c_mkdirs_new);
|
||||
create_case(s, "check_c_mkdirs_mode", check_c_mkdirs_mode);
|
||||
create_case_fixture(s, "check_c_mkdirs_existing_path", check_c_mkdirs_existing_path, setup, teardown);
|
||||
create_case_fixture(s, "check_c_mkdirs_file", check_c_mkdirs_file, setup, teardown);
|
||||
create_case(s, "check_c_mkdirs_null", check_c_mkdirs_null);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static Suite *make_std_c_isdir_suite(void) {
|
||||
Suite *s = suite_create("std:dir:c_isdir");
|
||||
|
||||
create_case_fixture(s, "check_c_isdir", check_c_isdir, setup, teardown);
|
||||
create_case_fixture(s, "check_c_isdir_on_file", check_c_isdir_on_file, setup, teardown);
|
||||
create_case(s, "check_c_isdir_null", check_c_isdir_null);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_std_c_mkdirs_suite();
|
||||
Suite *s2 = make_std_c_isdir_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_add_suite (sr, s2);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
86
tests/std_tests/check_std_c_file.c
Normal file
86
tests/std_tests/check_std_c_file.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_file.h"
|
||||
|
||||
const char *check_dir = "/tmp/check";
|
||||
const char *check_src_file = "/tmp/check/foo.txt";
|
||||
const char *check_dst_file = "/tmp/check/bar.txt";
|
||||
|
||||
static int test_file(const char *path, mode_t mode) {
|
||||
struct stat sb;
|
||||
if (lstat(path, &sb) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! S_ISREG(sb.st_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sb.st_mode & mode) == mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setup(void) {
|
||||
system("mkdir -p /tmp/check");
|
||||
system("echo 42 > /tmp/check/foo.txt");
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
system("rm -rf /tmp/check");
|
||||
}
|
||||
|
||||
START_TEST (check_c_copy)
|
||||
{
|
||||
fail_unless(c_copy(check_src_file, check_dst_file, 0644) == 0, NULL);
|
||||
fail_unless(test_file(check_dst_file, 0644) == 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_copy_same_file)
|
||||
{
|
||||
fail_unless(c_copy(check_src_file, check_src_file, 0644) == -1, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_copy_isdir)
|
||||
{
|
||||
fail_unless((c_copy(check_src_file, check_dir, 0644) == -1) && (errno == EISDIR), NULL);
|
||||
fail_unless((c_copy(check_dir, check_dst_file, 0644) == -1) && (errno == EISDIR), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *make_c_copy_suite(void) {
|
||||
Suite *s = suite_create("std:file:c_copy");
|
||||
|
||||
create_case_fixture(s, "check_c_copy", check_c_copy, setup, teardown);
|
||||
create_case(s, "check_c_copy_same_file", check_c_copy_same_file);
|
||||
create_case_fixture(s, "check_c_copy_isdir", check_c_copy_isdir, setup, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_c_copy_suite();
|
||||
/* Suite *s2 = make_std_is_dir_suite(); */
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
/* srunner_add_suite (sr, s2); */
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
280
tests/std_tests/check_std_c_jhash.c
Normal file
280
tests/std_tests/check_std_c_jhash.c
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* Tests are taken form lookup2.c and lookup8.c
|
||||
* by Bob Jenkins, December 1996, Public Domain.
|
||||
*
|
||||
* See http://burtleburtle.net/bob/hash/evahash.html
|
||||
*/
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_jhash.h"
|
||||
|
||||
#define HASHSTATE 1
|
||||
#define HASHLEN 1
|
||||
#define MAXPAIR 80
|
||||
#define MAXLEN 70
|
||||
|
||||
START_TEST (check_c_jhash_trials)
|
||||
{
|
||||
uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
|
||||
uint32_t c[HASHSTATE], d[HASHSTATE], i, j=0, k, l, m, z;
|
||||
uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
|
||||
uint32_t x[HASHSTATE],y[HASHSTATE];
|
||||
uint32_t hlen;
|
||||
|
||||
for (hlen=0; hlen < MAXLEN; ++hlen) {
|
||||
z=0;
|
||||
for (i=0; i<hlen; ++i) { /*----------------------- for each input byte, */
|
||||
for (j=0; j<8; ++j) { /*------------------------ for each input bit, */
|
||||
for (m=1; m<8; ++m) { /*------------ for serveral possible initvals, */
|
||||
for (l=0; l<HASHSTATE; ++l) e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
|
||||
|
||||
/*---- check that every output bit is affected by that input bit */
|
||||
for (k=0; k<MAXPAIR; k+=2) {
|
||||
uint32_t finished=1;
|
||||
/* keys have one bit different */
|
||||
for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
|
||||
/* have a and b be two keys differing in only one bit */
|
||||
a[i] ^= (k<<j);
|
||||
a[i] ^= (k>>(8-j));
|
||||
c[0] = c_jhash(a, hlen, m);
|
||||
b[i] ^= ((k+1)<<j);
|
||||
b[i] ^= ((k+1)>>(8-j));
|
||||
d[0] = c_jhash(b, hlen, m);
|
||||
/* check every bit is 1, 0, set, and not set at least once */
|
||||
for (l=0; l<HASHSTATE; ++l) {
|
||||
e[l] &= (c[l]^d[l]);
|
||||
f[l] &= ~(c[l]^d[l]);
|
||||
g[l] &= c[l];
|
||||
h[l] &= ~c[l];
|
||||
x[l] &= d[l];
|
||||
y[l] &= ~d[l];
|
||||
if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
|
||||
}
|
||||
if (finished) break;
|
||||
}
|
||||
if (k>z) z=k;
|
||||
if (k==MAXPAIR) {
|
||||
printf("Some bit didn't change: ");
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
|
||||
e[0], f[0], g[0], h[0], x[0], y[0]);
|
||||
printf("i %d j %d m %d len %d\n",i,j,m,hlen);
|
||||
}
|
||||
if (z==MAXPAIR) goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (z < MAXPAIR) {
|
||||
fail_unless(z < MAXPAIR, "%ld trials needed, should be less than 40", z/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_jhash_alignment_problems)
|
||||
{
|
||||
uint32_t test;
|
||||
uint8_t buf[MAXLEN+20], *b;
|
||||
uint32_t len;
|
||||
uint8_t q[] = "This is the time for all good men to come to the aid of their country";
|
||||
uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country";
|
||||
uint32_t h,i,j,ref,x,y;
|
||||
|
||||
test = c_jhash(q, sizeof(q)-1, (uint32_t)0);
|
||||
fail_unless(test == c_jhash(qq+1, sizeof(q)-1, (uint32_t)0), NULL);
|
||||
fail_unless(test == c_jhash(qq+1, sizeof(q)-1, (uint32_t)0), NULL);
|
||||
fail_unless(test == c_jhash(qqq+2, sizeof(q)-1, (uint32_t)0), NULL);
|
||||
fail_unless(test == c_jhash(qqqq+3, sizeof(q)-1, (uint32_t)0), NULL);
|
||||
for (h=0, b=buf+1; h<8; ++h, ++b) {
|
||||
for (i=0; i<MAXLEN; ++i) {
|
||||
len = i;
|
||||
for (j=0; j<i; ++j) *(b+j)=0;
|
||||
|
||||
/* these should all be equal */
|
||||
ref = c_jhash(b, len, (uint32_t)1);
|
||||
*(b+i)=(uint8_t)~0;
|
||||
*(b-1)=(uint8_t)~0;
|
||||
x = c_jhash(b, len, (uint32_t)1);
|
||||
y = c_jhash(b, len, (uint32_t)1);
|
||||
fail_if((ref != x) || (ref != y), "alignment error: %.8lx %.8lx %.8lx %ld %ld\n", ref, x, y, h, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_jhash_null_strings)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
uint32_t h, i, t, state[HASHSTATE];
|
||||
|
||||
buf[0] = ~0;
|
||||
for (i=0; i<HASHSTATE; ++i) state[i] = 1;
|
||||
for (i=0, h=0; i<8; ++i) {
|
||||
t = h;
|
||||
h = c_jhash(buf, (uint32_t)0, h);
|
||||
fail_if(t == h, "0-byte-string check failed: t = %.8lx, h = %.8lx", t, h);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_jhash64_trials)
|
||||
{
|
||||
uint8_t qa[MAXLEN + 1], qb[MAXLEN + 2];
|
||||
uint8_t *a, *b;
|
||||
uint64_t c[HASHSTATE], d[HASHSTATE], i, j=0, k, l, m, z;
|
||||
uint64_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
|
||||
uint64_t x[HASHSTATE],y[HASHSTATE];
|
||||
uint64_t hlen;
|
||||
|
||||
a = &qa[0];
|
||||
b = &qb[1];
|
||||
|
||||
for (hlen=0; hlen < MAXLEN; ++hlen) {
|
||||
z=0;
|
||||
for (i=0; i<hlen; ++i) { /*----------------------- for each byte, */
|
||||
for (j=0; j<8; ++j) { /*------------------------ for each bit, */
|
||||
for (m=0; m<8; ++m) { /*-------- for serveral possible levels, */
|
||||
for (l=0; l<HASHSTATE; ++l) e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint64_t)0);
|
||||
|
||||
/*---- check that every input bit affects every output bit */
|
||||
for (k=0; k<MAXPAIR; k+=2) {
|
||||
uint64_t finished=1;
|
||||
/* keys have one bit different */
|
||||
for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
|
||||
/* have a and b be two keys differing in only one bit */
|
||||
a[i] ^= (k<<j);
|
||||
a[i] ^= (k>>(8-j));
|
||||
c[0] = c_jhash64(a, hlen, m);
|
||||
b[i] ^= ((k+1)<<j);
|
||||
b[i] ^= ((k+1)>>(8-j));
|
||||
d[0] = c_jhash64(b, hlen, m);
|
||||
/* check every bit is 1, 0, set, and not set at least once */
|
||||
for (l=0; l<HASHSTATE; ++l)
|
||||
{
|
||||
e[l] &= (c[l]^d[l]);
|
||||
f[l] &= ~(c[l]^d[l]);
|
||||
g[l] &= c[l];
|
||||
h[l] &= ~c[l];
|
||||
x[l] &= d[l];
|
||||
y[l] &= ~d[l];
|
||||
if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
|
||||
}
|
||||
if (finished) break;
|
||||
}
|
||||
if (k>z) z=k;
|
||||
if (k==MAXPAIR) {
|
||||
printf("Some bit didn't change: ");
|
||||
printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ",
|
||||
e[0],f[0],g[0],h[0],x[0],y[0]);
|
||||
printf("i %d j %d m %d len %d\n",
|
||||
(uint32_t)i,(uint32_t)j,(uint32_t)m,(uint32_t)hlen);
|
||||
}
|
||||
if (z==MAXPAIR) goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (z < MAXPAIR) {
|
||||
fail_unless(z < MAXPAIR, "%ld trials needed, should be less than 40", z/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_jhash64_alignment_problems)
|
||||
{
|
||||
uint8_t buf[MAXLEN+20], *b;
|
||||
uint64_t len;
|
||||
uint8_t q[] = "This is the time for all good men to come to the aid of their country";
|
||||
uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t o[] = "xxxxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t oo[] = "xxxxxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t ooo[] = "xxxxxxThis is the time for all good men to come to the aid of their country";
|
||||
uint8_t oooo[] = "xxxxxxxThis is the time for all good men to come to the aid of their country";
|
||||
uint64_t h,i,j,ref,t,x,y;
|
||||
|
||||
h = c_jhash64(q+0, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
t = h;
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(qq+1, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(qqq+2, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(qqqq+3, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(o+4, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(oo+5, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(ooo+6, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
h = c_jhash64(oooo+7, (uint64_t)(sizeof(q)-1), (uint64_t)0);
|
||||
fail_unless(t == h, "%.8lx%.8lx\n", (uint32_t)h, (uint32_t)(h>>32));
|
||||
for (h=0, b=buf+1; h<8; ++h, ++b) {
|
||||
for (i=0; i<MAXLEN; ++i) {
|
||||
len = i;
|
||||
for (j=0; j<i; ++j) *(b+j)=0;
|
||||
|
||||
/* these should all be equal */
|
||||
ref = c_jhash64(b, len, (uint64_t)1);
|
||||
*(b+i)=(uint8_t)~0;
|
||||
*(b-1)=(uint8_t)~0;
|
||||
x = c_jhash64(b, len, (uint64_t)1);
|
||||
y = c_jhash64(b, len, (uint64_t)1);
|
||||
fail_if((ref != x) || (ref != y), "alignment error: %.8lx %.8lx %.8lx %ld %ld\n", ref, x, y, h, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_jhash64_null_strings)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
uint64_t h, i, t, state[HASHSTATE];
|
||||
|
||||
|
||||
buf[0] = ~0;
|
||||
for (i=0; i<HASHSTATE; ++i) state[i] = 1;
|
||||
for (i=0, h=0; i<8; ++i) {
|
||||
t = h;
|
||||
h = c_jhash64(buf, (uint64_t)0, h);
|
||||
fail_if(t == h, "0-byte-string check failed: t = %.8lx, h = %.8lx", t, h);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
static Suite *make_c_jhash_suite(void) {
|
||||
Suite *s = suite_create("std:path:xsrbtree");
|
||||
|
||||
create_case(s, "check_c_jhash_trials", check_c_jhash_trials);
|
||||
create_case(s, "check_c_jhash_alignment_problems", check_c_jhash_alignment_problems);
|
||||
create_case(s, "check_c_jhash_null_strings", check_c_jhash_null_strings);
|
||||
|
||||
create_case(s, "check_c_jhash64_trials", check_c_jhash64_trials);
|
||||
create_case(s, "check_c_jhash64_alignment_problems", check_c_jhash64_alignment_problems);
|
||||
create_case(s, "check_c_jhash64_null_strings", check_c_jhash64_null_strings);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_c_jhash_suite();
|
||||
/* Suite *s2 = make_xstrdup_suite(); */
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
/* srunner_add_suite (sr, s2); */
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
119
tests/std_tests/check_std_c_path.c
Normal file
119
tests/std_tests/check_std_c_path.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_path.h"
|
||||
|
||||
START_TEST (check_c_basename)
|
||||
{
|
||||
char *bname;
|
||||
|
||||
bname = c_basename("/usr/lib");
|
||||
fail_unless((strcmp(bname, "lib") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("/usr//");
|
||||
fail_unless((strcmp(bname, "usr") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("usr");
|
||||
fail_unless((strcmp(bname, "usr") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("///");
|
||||
fail_unless((strcmp(bname, "/") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("/");
|
||||
fail_unless((strcmp(bname, "/") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename(".");
|
||||
fail_unless((strcmp(bname, ".") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("..");
|
||||
fail_unless((strcmp(bname, "..") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename("");
|
||||
fail_unless((strcmp(bname, ".") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
bname = c_basename(NULL);
|
||||
fail_unless((strcmp(bname, ".") == 0), NULL);
|
||||
SAFE_FREE(bname);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_dirname)
|
||||
{
|
||||
char *dname;
|
||||
|
||||
dname = c_dirname("/usr/lib");
|
||||
fail_unless((strcmp(dname, "/usr") == 0), "c_dirname = %s\n", dname);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname("/usr//");
|
||||
fail_unless((strcmp(dname, "/") == 0), "c_dirname = %s\n", dname);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname("usr");
|
||||
fail_unless((strcmp(dname, ".") == 0), "c_dirname = %s\n", dname);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname("/");
|
||||
fail_unless((strcmp(dname, "/") == 0), NULL);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname("///");
|
||||
fail_unless((strcmp(dname, "/") == 0), NULL);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname(".");
|
||||
fail_unless((strcmp(dname, ".") == 0), NULL);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname("..");
|
||||
fail_unless((strcmp(dname, ".") == 0), NULL);
|
||||
SAFE_FREE(dname);
|
||||
|
||||
dname = c_dirname(NULL);
|
||||
fail_unless((strcmp(dname, ".") == 0), NULL);
|
||||
SAFE_FREE(dname);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *make_std_c_basename_suite(void) {
|
||||
Suite *s = suite_create("std:path:c_basename");
|
||||
|
||||
create_case(s, "check_c_basename", check_c_basename);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static Suite *make_std_c_dirname_suite(void) {
|
||||
Suite *s = suite_create("std:path:c_dirname");
|
||||
|
||||
create_case(s, "check_c_dirname", check_c_dirname);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_std_c_basename_suite();
|
||||
Suite *s2 = make_std_c_dirname_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_add_suite (sr, s2);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
286
tests/std_tests/check_std_c_rbtree.c
Normal file
286
tests/std_tests/check_std_c_rbtree.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_alloc.h"
|
||||
#include "std/c_rbtree.h"
|
||||
|
||||
typedef struct test_s {
|
||||
int key;
|
||||
int number;
|
||||
} test_t;
|
||||
|
||||
static c_rbtree_t *tree = NULL;
|
||||
|
||||
static int data_cmp(const void *key, const void *data) {
|
||||
test_t *a, *b;
|
||||
|
||||
a = (test_t *) key;
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a->key < b->key) {
|
||||
return -1;
|
||||
} else if (a->key > b->key) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int key_cmp(const void *key, const void *data) {
|
||||
int a;
|
||||
test_t *b;
|
||||
|
||||
a = POINTER_TO_INT(key);
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a < b->key) {
|
||||
return -1;
|
||||
} else if (a > b->key) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int visitor(void *obj, void *data) {
|
||||
test_t *a = NULL;
|
||||
test_t *b = NULL;
|
||||
|
||||
a = (test_t *) obj;
|
||||
b = (test_t *) data;
|
||||
|
||||
if (a->key == b->key) {
|
||||
a->number = 42;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void destructor(void *data) {
|
||||
test_t *freedata = NULL;
|
||||
|
||||
freedata = (void *) data;
|
||||
SAFE_FREE(freedata);
|
||||
}
|
||||
|
||||
static void setup(void) {
|
||||
c_rbtree_create(&tree, key_cmp, data_cmp);
|
||||
}
|
||||
|
||||
static void setup_complete_tree(void) {
|
||||
int i = 0;
|
||||
|
||||
fail_unless(c_rbtree_create(&tree, key_cmp, data_cmp) == 0, NULL);
|
||||
for (i = 0; i < 100; i++) {
|
||||
test_t *testdata = NULL;
|
||||
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
fail_if(testdata == NULL, NULL);
|
||||
|
||||
testdata->key = i;
|
||||
|
||||
c_rbtree_insert(tree, (void *) testdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void teardown(void) {
|
||||
c_rbtree_destroy(tree, destructor);
|
||||
c_rbtree_free(tree);
|
||||
tree = NULL;
|
||||
}
|
||||
|
||||
START_TEST (check_c_rbtree_create_free)
|
||||
{
|
||||
fail_unless(c_rbtree_create(&tree, key_cmp, data_cmp) == 0, NULL);
|
||||
fail_unless(tree->size == 0, NULL);
|
||||
|
||||
fail_unless(c_rbtree_free(tree) == 0, NULL);
|
||||
tree = NULL;
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_create_null)
|
||||
{
|
||||
fail_unless(c_rbtree_create(NULL, key_cmp, data_cmp) < 0, NULL);
|
||||
fail_unless(c_rbtree_create(&tree, NULL, data_cmp) < 0, NULL);
|
||||
fail_unless(c_rbtree_create(&tree, key_cmp, NULL) < 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_free_null)
|
||||
{
|
||||
fail_unless(c_rbtree_free(NULL) < 0, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_insert_delete)
|
||||
{
|
||||
c_rbnode_t *node = NULL;
|
||||
test_t *testdata = NULL;
|
||||
|
||||
fail_unless(c_rbtree_create(&tree, key_cmp, data_cmp) == 0, NULL);
|
||||
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
testdata->key = 42;
|
||||
|
||||
fail_unless(c_rbtree_insert(tree, (void *) testdata) == 0, NULL);
|
||||
|
||||
node = c_rbtree_head(tree);
|
||||
fail_if(node == NULL, NULL);
|
||||
|
||||
fail_unless(c_rbtree_node_delete(node) == 0, NULL);
|
||||
|
||||
c_rbtree_free(tree);
|
||||
tree = NULL;
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_insert_random)
|
||||
{
|
||||
int i = 0, rc = -1;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
test_t *testdata = NULL;
|
||||
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
fail_if(testdata == NULL, NULL);
|
||||
|
||||
testdata->key = i;
|
||||
|
||||
rc = c_rbtree_insert(tree, testdata);
|
||||
fail_unless(rc == 0, "c_rbtree_insert failed for %d with return code %d", i, rc);
|
||||
|
||||
}
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_insert_duplicate)
|
||||
{
|
||||
test_t *testdata = NULL;
|
||||
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
fail_if(testdata == NULL, NULL);
|
||||
|
||||
testdata->key = 42;
|
||||
|
||||
fail_unless(c_rbtree_insert(tree, (void *) testdata) == 0, NULL);
|
||||
|
||||
/* add again */
|
||||
testdata = c_malloc(sizeof(test_t));
|
||||
fail_if(testdata == NULL, NULL);
|
||||
|
||||
testdata->key = 42;
|
||||
|
||||
/* check for duplicate */
|
||||
fail_unless(c_rbtree_insert(tree, (void *) testdata) == 1, NULL);
|
||||
SAFE_FREE(testdata);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_find)
|
||||
{
|
||||
int rc = -1, i = 42;
|
||||
c_rbnode_t *node = NULL;
|
||||
test_t *testdata = NULL;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
|
||||
/* find the node with the key 42 */
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
fail_if(node == NULL, NULL);
|
||||
|
||||
testdata = (test_t *) c_rbtree_node_data(node);
|
||||
fail_unless(testdata->key == 42, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_delete)
|
||||
{
|
||||
int rc = -1, i = 42;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
fail_if(node == NULL, NULL);
|
||||
|
||||
fail_unless(c_rbtree_node_delete(node) == 0, NULL);
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_rbtree_walk)
|
||||
{
|
||||
int rc = -1, i = 42;
|
||||
test_t *testdata = NULL;
|
||||
c_rbnode_t *node = NULL;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
|
||||
testdata = (test_t *) c_malloc(sizeof(test_t));
|
||||
testdata->key = 42;
|
||||
|
||||
rc = c_rbtree_walk(tree, testdata, visitor);
|
||||
fail_unless(rc == 0, NULL);
|
||||
|
||||
/* find the node with the key 42 */
|
||||
node = c_rbtree_find(tree, (void *) &i);
|
||||
fail_if(node == NULL, NULL);
|
||||
|
||||
testdata = (test_t *) c_rbtree_node_data(node);
|
||||
fail_unless(testdata->number == 42, NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#if 0
|
||||
START_TEST (check_c_rbtree_x)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
rc = c_rbtree_check_sanity(tree);
|
||||
fail_unless(rc == 0, "c_rbtree_check_sanity failed with return code %d", rc);
|
||||
}
|
||||
END_TEST
|
||||
#endif
|
||||
|
||||
static Suite *make_c_rbtree_suite(void) {
|
||||
Suite *s = suite_create("std:path:c_rbtree");
|
||||
|
||||
create_case(s, "check_c_rbtree_create_free", check_c_rbtree_create_free);
|
||||
create_case(s, "check_c_rbtree_create_null", check_c_rbtree_create_null);
|
||||
create_case(s, "check_c_rbtree_free_null", check_c_rbtree_free_null);
|
||||
create_case(s, "check_c_rbtree_insert_delete", check_c_rbtree_insert_delete);
|
||||
create_case_fixture(s, "check_c_rbtree_insert_random", check_c_rbtree_insert_random, setup, teardown);
|
||||
create_case_fixture(s, "check_c_rbtree_insert_duplicate", check_c_rbtree_insert_duplicate, setup, teardown);
|
||||
create_case_fixture(s, "check_c_rbtree_find", check_c_rbtree_find, setup_complete_tree, teardown);
|
||||
create_case_fixture(s, "check_c_rbtree_delete", check_c_rbtree_delete, setup_complete_tree, teardown);
|
||||
create_case_fixture(s, "check_c_rbtree_walk", check_c_rbtree_walk, setup_complete_tree, teardown);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_c_rbtree_suite();
|
||||
/* Suite *s2 = make_xstrdup_suite(); */
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
/* srunner_set_fork_status(sr, CK_NOFORK); */
|
||||
/* srunner_add_suite(sr, s2); */
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
101
tests/std_tests/check_std_c_str.c
Normal file
101
tests/std_tests/check_std_c_str.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include "std/c_string.h"
|
||||
|
||||
START_TEST (check_c_streq_equal)
|
||||
{
|
||||
fail_unless(c_streq("test", "test"), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_streq_not_equal)
|
||||
{
|
||||
fail_if(c_streq("test", "test2"), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_streq_null)
|
||||
{
|
||||
fail_if(c_streq(NULL, "test"), NULL);
|
||||
fail_if(c_streq("test", NULL), NULL);
|
||||
fail_if(c_streq(NULL, NULL), NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
static Suite *make_std_c_streq_suite(void) {
|
||||
Suite *s = suite_create("std:string:c_streq");
|
||||
|
||||
create_case(s, "check_c_streq_equal", check_c_streq_equal);
|
||||
create_case(s, "check_c_streq_not_equal", check_c_streq_not_equal);
|
||||
create_case(s, "check_c_streq_null", check_c_streq_null);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
START_TEST (check_c_strlist_new)
|
||||
{
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
strlist = c_strlist_new(42);
|
||||
fail_if(strlist == NULL, NULL);
|
||||
fail_unless(strlist->size == 42, NULL);
|
||||
fail_unless(strlist->count == 0, NULL);
|
||||
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (check_c_strlist_add)
|
||||
{
|
||||
size_t i = 0;
|
||||
c_strlist_t *strlist = NULL;
|
||||
|
||||
strlist = c_strlist_new(42);
|
||||
fail_if(strlist == NULL, NULL);
|
||||
fail_unless(strlist->size == 42, NULL);
|
||||
fail_unless(strlist->count == 0, NULL);
|
||||
|
||||
for (i = 0; i < strlist->size; i++) {
|
||||
fail_unless(c_strlist_add(strlist, "foobar") == 0, NULL);
|
||||
}
|
||||
|
||||
fail_unless(strlist->count == 42, NULL);
|
||||
fail_unless(strcmp(strlist->vector[0], "foobar") == 0, NULL);
|
||||
fail_unless(strcmp(strlist->vector[41], "foobar") == 0, NULL);
|
||||
|
||||
c_strlist_destroy(strlist);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *make_std_c_strlist_suite(void) {
|
||||
Suite *s = suite_create("std:str:c_stringlist");
|
||||
|
||||
create_case(s, "check_c_strlist_new", check_c_strlist_new);
|
||||
create_case(s, "check_c_strlist_add", check_c_strlist_add);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int nf;
|
||||
|
||||
Suite *s = make_std_c_streq_suite();
|
||||
Suite *s2 = make_std_c_strlist_suite();
|
||||
|
||||
SRunner *sr;
|
||||
sr = srunner_create(s);
|
||||
srunner_add_suite (sr, s2);
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
nf = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue