Initial commit

This commit is contained in:
Andreas Schneider 2008-02-27 18:56:47 +01:00
commit 1b29a420bc
102 changed files with 11603 additions and 0 deletions

1
AUTHORS Normal file
View file

@ -0,0 +1 @@
Andreas Schneider <mail@cynapses.org>

43
CMakeLists.txt Normal file
View 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
View 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
View 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
View file

@ -0,0 +1 @@
option(WITH_LOG4C "Build csync without log4c" ON)

80
INSTALL Normal file
View 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
View file

148
build/build_make.sh Executable file
View 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
View 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
View 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;
}

View 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.

View 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)

View 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)

View 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)

View 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)

View 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 )

View 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)

View 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)

View 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)

View 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 )

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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")

View 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
View 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
View file

@ -0,0 +1,6 @@
INSTALL(
FILES
csync_log.conf
DESTINATION
${DATA_INSTALL_PREFIX}
)

7
config/csync.conf Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

5
iniparser/AUTHORS Normal file
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View 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>
&nbsp;
<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
View 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>

View 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&nbsp;</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">&nbsp;</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 *&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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 *&nbsp;</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">&nbsp;</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 *&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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 *&nbsp;</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">&nbsp;</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&nbsp;</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">&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>f</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to dump. </td></tr>
<tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>f</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to dump </td></tr>
<tr><td valign="top"></td><td valign="top"><em>f</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>entry</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</td>
<td class="mdname1" valign="top" nowrap> <em>d</em> </td>
<td class="md" valign="top">&nbsp;)&nbsp;</td>
<td class="md" nowrap></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</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&nbsp;</td>
<td class="mdname" nowrap> <em>notfound</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</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&nbsp;</td>
<td class="mdname" nowrap> <em>notfound</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</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&nbsp;</td>
<td class="mdname" nowrap> <em>notfound</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>notfound</em>&nbsp;</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" -&gt; 42</li><li>"042" -&gt; 34 (octal -&gt; decimal)</li><li>"0x42" -&gt; 66 (hexa -&gt; 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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</td>
<td class="mdname1" valign="top" nowrap> <em>d</em> </td>
<td class="md" valign="top">&nbsp;)&nbsp;</td>
<td class="md" nowrap></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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&nbsp;</td>
<td class="mdname" nowrap> <em>n</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to examine </td></tr>
<tr><td valign="top"></td><td valign="top"><em>n</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>key</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>def</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to search </td></tr>
<tr><td valign="top"></td><td valign="top"><em>key</em>&nbsp;</td><td>Key string to look for </td></tr>
<tr><td valign="top"></td><td valign="top"><em>def</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">const char *&nbsp;</td>
<td class="mdname1" valign="top" nowrap> <em>ininame</em> </td>
<td class="md" valign="top">&nbsp;)&nbsp;</td>
<td class="md" nowrap></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>val</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to modify. </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</td><td>Entry to modify (entry name) </td></tr>
<tr><td valign="top"></td><td valign="top"><em>val</em>&nbsp;</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">(&nbsp;</td>
<td class="md" nowrap valign="top">dictionary *&nbsp;</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 *&nbsp;</td>
<td class="mdname" nowrap> <em>entry</em></td>
</tr>
<tr>
<td class="md"></td>
<td class="md">)&nbsp;</td>
<td class="md" colspan="2"></td>
</tr>
</table>
</td>
</tr>
</table>
<table cellspacing="5" cellpadding="0" border="0">
<tr>
<td>
&nbsp;
</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>&nbsp;</td><td>Dictionary to modify </td></tr>
<tr><td valign="top"></td><td valign="top"><em>entry</em>&nbsp;</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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

102
iniparser/html/tabs.css Normal file
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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})

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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