[
  {
    "path": ".buzzy/links.yaml",
    "content": "- git://github.com/dcreager/buzzy-core.git\n"
  },
  {
    "path": ".buzzy/package.yaml",
    "content": "name: libcork\nbuild_dependencies:\n  - pkg-config\n  - check >= 0.9.4\nlicense: BSD\n"
  },
  {
    "path": ".clang-format",
    "content": "Language: Cpp\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Right\nAlignOperands: true\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: Inline\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: TopLevel\nAlwaysBreakAfterReturnType: TopLevel\nAlwaysBreakBeforeMultilineStrings: true\nAlwaysBreakTemplateDeclarations: true\nBinPackArguments: true\nBinPackParameters: true\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: WebKit\nBreakBeforeTernaryOperators: false\nBreakStringLiterals: false\nColumnLimit: 80\nContinuationIndentWidth: 8\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nDerivePointerAlignment: false\nDisableFormat: false\nExperimentalAutoDetectBinPacking: false\nIncludeCategories:\n  - Regex:    '^<.*\\.h>'\n    Priority: 1\n  - Regex:    '^<.*'\n    Priority: 2\n  - Regex:    '.*'\n    Priority: 3\nIncludeIsMainRegex: '([-_](test|unittest))?$'\nIndentCaseLabels: true\nIndentWidth: 4\nIndentWrappedFunctionNames: false\nKeepEmptyLinesAtTheStartOfBlocks: false\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 2\nNamespaceIndentation: None\nPenaltyBreakBeforeFirstCallParameter: 1\nPenaltyBreakComment: 300\nPenaltyBreakString: 1000\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 0\nPointerAlignment: Left\nReflowComments: false\nSortIncludes: true\nSpaceAfterCStyleCast: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeParens: ControlStatements\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 2\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nTabWidth: 8\nUseTab: Never\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Continuous integration\non:\n  push:\n    branches:\n      - master\n  pull_request:\n  schedule:\n    - cron: \"0 0 1,15 * *\"\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        arch: [amd64, i386]\n        compiler: [clang, gcc]\n        flavor:\n          - autotools\n          - cmake\n          - shared-cmake\n          - fallback-u128\n          - cmake-from-dist\n\n    env:\n      ARCH: ${{ matrix.arch }}\n      COMPILER: ${{ matrix.compiler }}\n      FLAVOR: ${{ matrix.flavor }}\n      OS_NAME: ${{ matrix.os }}\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n\n      - name: Fetch everything (for automatic version detection)\n        run: git fetch --prune --unshallow\n\n      - name: Install dependencies\n        run: scripts/install\n\n      - name: Test harness\n        run: scripts/test\n"
  },
  {
    "path": ".gitignore",
    "content": "# autotools stuff\n/aclocal.m4\n/autom4te.cache/\n/build-aux/compile\n/build-aux/config.guess\n/build-aux/config.sub\n/build-aux/depcomp\n/build-aux/install-sh\n/build-aux/ltmain.sh\n/build-aux/missing\n/build-aux/test-driver\n/config.h.in\n/configure\n/Makefile.in\n/m4/libtool.m4\n/m4/lt*.m4\n\n# Dist tarballs\nlibcork-*.tar.xz\n\n# In-source build artefacts\n*.a\n*.o\n*.la\n*.lo\n.deps\n.dirstamp\n.libs/\n/config.h\n/config.log\n/config.status\n/cork-*\n/libcork.la\n/libtool\n/Makefile\n/stamp-h1\ntest*.log\ntest*.trs\n/tests/test-*\n!/tests/test-*.c\n\n# Common out-of-source build locations\n/.build*\n/build*\n!/build-aux\n"
  },
  {
    "path": "AUTHORS",
    "content": "# This is the list of libcork authors for copyright purposes.\n#\n# This does not necessarily list everyone who has contributed code, since in\n# some cases, their employer may be the copyright holder.  To see the full list\n# of contributors, see the revision history in source control.\nDDoSolitary <DDoSolitary@gmail.com>\nGoogle Inc.\nJan Weiß <jan@geheimwerk.de>\nNathan French <nate@cl0d.com>\nRedjack, LLC\nRoger Shimizu <rogershimizu@gmail.com>\nToby DiPasquale <toby@cbcg.net>\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\ncmake_minimum_required(VERSION 2.6)\nset(PROJECT_NAME libcork)\nset(RELEASE_DATE 2015-09-03)\nproject(${PROJECT_NAME})\nenable_testing()\n\nset(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake\")\nfind_package(ParseArguments)\nfind_package(Prereqs)\nfind_package(CTargets)\n\n#-----------------------------------------------------------------------\n# Retrieve the current version number\n\nexecute_process(\n    COMMAND\n      ${CMAKE_SOURCE_DIR}/build-aux/calculate version\n        ${CMAKE_SOURCE_DIR} .version-stamp\n    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n    RESULT_VARIABLE VERSION_RESULT\n    OUTPUT_VARIABLE VERSION\n    OUTPUT_STRIP_TRAILING_WHITESPACE\n)\nif(VERSION_RESULT)\n    message(FATAL_ERROR\n            \"Cannot determine version number: \" ${VERSION_RESULT})\nendif(VERSION_RESULT)\nmessage(STATUS \"Current version: \" ${VERSION})\n\nstring(REGEX REPLACE \"-.*\" \"-dev\" BASE_VERSION \"${VERSION}\")\n\nif(BASE_VERSION MATCHES \"^([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)(-dev)?$\")\n    set(CORK_VERSION_MAJOR \"${CMAKE_MATCH_1}\")\n    set(CORK_VERSION_MINOR \"${CMAKE_MATCH_2}\")\n    set(CORK_VERSION_PATCH \"${CMAKE_MATCH_3}\")\nelse(BASE_VERSION MATCHES \"^([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)(-dev)?$\")\n    message(FATAL_ERROR \"Invalid version number: ${VERSION}\")\nendif(BASE_VERSION MATCHES \"^([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)(-dev)?$\")\nset(CORK_VERSION \"${VERSION}\")\n\nexecute_process(\n    COMMAND\n      ${CMAKE_SOURCE_DIR}/build-aux/calculate commit\n        ${CMAKE_SOURCE_DIR} .commit-stamp\n    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n    RESULT_VARIABLE GIT_SHA1_RESULT\n    OUTPUT_VARIABLE CORK_GIT_SHA1\n    OUTPUT_STRIP_TRAILING_WHITESPACE\n)\nif(GIT_SHA1_RESULT)\n    message(FATAL_ERROR\n            \"Cannot determine git commit: \" ${GIT_SHA1_RESULT})\nendif(GIT_SHA1_RESULT)\nmessage(STATUS \"Current revision: \" ${CORK_GIT_SHA1})\n\ninclude(GNUInstallDirs)\n\n#-----------------------------------------------------------------------\n# Set some options\n\nif(APPLE)\n    if (NOT CMAKE_INSTALL_NAME_DIR)\n        set(CMAKE_INSTALL_NAME_DIR \"${CMAKE_INSTALL_PREFIX}/lib\")\n    endif (NOT CMAKE_INSTALL_NAME_DIR)\nendif(APPLE)\n\nif(NOT CMAKE_BUILD_TYPE)\n    set(CMAKE_BUILD_TYPE Release CACHE STRING\n        \"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel.\"\n        FORCE)\nendif(NOT CMAKE_BUILD_TYPE)\n\nset(ENABLE_SHARED YES CACHE BOOL \"Whether to build a shared library\")\nset(ENABLE_SHARED_EXECUTABLES NO CACHE BOOL\n    \"Whether to link executables using shared libraries\")\nset(ENABLE_SHARED_TESTS NO CACHE BOOL\n    \"Whether to link test cases using shared libraries\")\nset(ENABLE_STATIC YES CACHE BOOL \"Whether to build a static library\")\n\nif(NOT CMAKE_INSTALL_LIBDIR)\n    set(CMAKE_INSTALL_LIBDIR lib CACHE STRING\n        \"The base name of the installation directory for libraries\")\nendif(NOT CMAKE_INSTALL_LIBDIR)\n\nif(CMAKE_C_COMPILER_ID STREQUAL \"GNU\")\n    add_definitions(-Wall -Werror)\nelseif(CMAKE_C_COMPILER_ID STREQUAL \"Clang\")\n    add_definitions(-Wall -Werror)\nelseif(CMAKE_C_COMPILER_ID STREQUAL \"Intel\")\n    add_definitions(-Wall -Werror)\nendif(CMAKE_C_COMPILER_ID STREQUAL \"GNU\")\n\n#-----------------------------------------------------------------------\n# Check for prerequisite libraries\n\nfind_package(Threads)\nset(THREADS_LDFLAGS \"${CMAKE_THREAD_LIBS_INIT}\")\nset(THREADS_STATIC_LDFLAGS \"${CMAKE_THREAD_LIBS_INIT}\")\nset(PTHREAD_LIBS \"${CMAKE_THREAD_LIBS_INIT}\")\n\n#-----------------------------------------------------------------------\n# Include our subdirectories\n\nadd_subdirectory(include)\nadd_subdirectory(share)\nadd_subdirectory(src)\nadd_subdirectory(tests)\nadd_subdirectory(docs/old)\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright © 2011-2017, libcork authors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n  • Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n  • Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n  • Neither the names of the libcork authors nor the names of its\n    contributors may be used to endorse or promote products derived\n    from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "INSTALL",
    "content": "Installation instructions\n=========================\n\nThe libcork library is written in ANSI C.  It uses cmake as its build\nmanager.\n\n\nPrerequisite libraries\n----------------------\n\nTo build libcork, you need the following libraries installed on your\nsystem:\n\n  * pkg-config\n  * check (http://libcheck.github.io/check)\n\n\nBuilding from source\n--------------------\n\nThe libcork library uses cmake as its build manager.  In most cases, you\nshould be able to build the source code using the following:\n\n    $ mkdir build\n    $ cd build\n    $ cmake .. -DCMAKE_INSTALL_PREFIX=$PREFIX\n    $ make\n    $ make test\n    $ make install\n\nYou might have to run the last command using sudo, if you need\nadministrative privileges to write to the $PREFIX directory.\n\n\nShared and static libraries\n---------------------------\n\nYou can use the `ENABLE_SHARED` and `ENABLE_STATIC` cmake options to control\nwhether or not to install shared and static versions of libcork, respectively.\nBy default, both are installed.\n\nYou can use the `ENABLE_SHARED_EXECUTABLE` cmake option to control whether the\nprograms that we install link with libcork's shared library or static library.\n(Note that this can override the value of `ENABLE_SHARED`; if you ask for the\nprograms to link with the shared library, then we have to install that shared\nlibrary for the programs to work properly.)  By default, we link with libcork\nstatically.\n\nSo, as an example, if you wanted to only build and install the shared library,\nand to have our programs link with that shared library, you'd replace the cmake\ncommand with the following:\n\n    $ cmake .. \\\n        -DCMAKE_INSTALL_PREFIX=$PREFIX \\\n        -DENABLE_SHARED=YES \\\n        -DENABLE_STATIC=NO \\\n        -DENABLE_SHARED_EXECUTABLES=YES\n"
  },
  {
    "path": "Makefile.am",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n# Copyright © 2018, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ------------------------------------------------------------------------------\n\n#-------------------------------------------------------------------------------\n# Dist hooks\n\ndist-hook: dist-check-git-version dist-stamps\n\n#-------------------------------------------------------------------------------\n# .commit-stamp and .version-stamp\n\ndist-check-git-version:\n\t: # Verify that the version that configure.ac recorded matches the\n\t: # current calculated version.\n\t@git_ver=`$(top_srcdir)/build-aux/calculate version $(top_srcdir) $(top_srcdir)/.version-stamp`; \\\n\tif test \"x$${git_ver}\" != \"x$(PACKAGE_VERSION)\"; then \\\n\t    echo \"ERROR: PACKAGE_VERSION and 'git describe' version do not match:\"; \\\n\t    echo \"     current 'git describe' version: $${git_ver}\"; \\\n\t    echo \"     current PACKAGE_VERSION:        $(PACKAGE_VERSION)\"; \\\n\t    echo \"Update PACKAGE_VERSION by running $(top_srcdir)/autogen.sh.\"; \\\n\t    rm -rf \"$(top_srcdir)/autom4te.cache\"; \\\n\t    exit 1; \\\n\tfi\n\ndist-stamps:\n\t@: # Generate version stamps for dist tarball.\n\t@echo $(CORK_GIT_SHA1) > $(distdir)/.commit-stamp\n\t@echo $(VERSION) > $(distdir)/.version-stamp\n\n#-------------------------------------------------------------------------------\n# Preliminaries\n\nACLOCAL_AMFLAGS = -I m4\nAM_CPPFLAGS = \\\n    -I$(srcdir)/include \\\n    -I$(builddir)/include\n\nlib_LTLIBRARIES = libcork.la\nbin_PROGRAMS = cork-hash\ncheck_PROGRAMS =\nCLEANFILES =\nEXTRA_DIST =\nEXTRA_PROGRAMS =\nTESTS =\n\n#-------------------------------------------------------------------------------\n# Extras\n\nEXTRA_DIST += \\\n    CMakeLists.txt \\\n    README.markdown \\\n    build-aux/calculate \\\n    cmake \\\n    docs \\\n    extras \\\n    share \\\n    include/CMakeLists.txt \\\n    src/CMakeLists.txt \\\n    src/libcork.pc.in \\\n    tests/CMakeLists.txt\n\n#-------------------------------------------------------------------------------\n# libcork\n\nlibcork_includedir = $(includedir)/libcork\ncli_includedir = $(includedir)/libcork/cli\nconfig_includedir = $(includedir)/libcork/config\ncore_includedir = $(includedir)/libcork/core\nds_includedir = $(includedir)/libcork/ds\nhelpers_includedir = $(includedir)/libcork/helpers\nos_includedir = $(includedir)/libcork/os\nthreads_includedir = $(includedir)/libcork/threads\n\nlibcork_include_HEADERS = \\\n    include/libcork/cli.h \\\n    include/libcork/config.h \\\n    include/libcork/core.h \\\n    include/libcork/ds.h \\\n    include/libcork/os.h \\\n    include/libcork/threads.h\n\ncli_include_HEADERS = \\\n    include/libcork/cli/commands.h\n\nconfig_include_HEADERS = \\\n    include/libcork/config/arch.h \\\n    include/libcork/config/gcc.h \\\n    include/libcork/config/macosx.h \\\n    include/libcork/config/bsd.h \\\n    include/libcork/config/linux.h \\\n    include/libcork/config/config.h \\\n    include/libcork/config/version.h\n\ncore_include_HEADERS = \\\n    include/libcork/core/hash.h \\\n    include/libcork/core/error.h \\\n    include/libcork/core/allocator.h \\\n    include/libcork/core/u128.h \\\n    include/libcork/core/attributes.h \\\n    include/libcork/core/byte-order.h \\\n    include/libcork/core/callbacks.h \\\n    include/libcork/core/timestamp.h \\\n    include/libcork/core/gc.h \\\n    include/libcork/core/net-addresses.h \\\n    include/libcork/core/types.h \\\n    include/libcork/core/id.h \\\n    include/libcork/core/api.h \\\n    include/libcork/core/mempool.h\n\nds_include_HEADERS = \\\n    include/libcork/ds/hash-table.h \\\n    include/libcork/ds/array.h \\\n    include/libcork/ds/managed-buffer.h \\\n    include/libcork/ds/ring-buffer.h \\\n    include/libcork/ds/stream.h \\\n    include/libcork/ds/bitset.h \\\n    include/libcork/ds/buffer.h \\\n    include/libcork/ds/slice.h \\\n    include/libcork/ds/dllist.h\n\nhelpers_include_HEADERS = \\\n    include/libcork/helpers/posix.h \\\n    include/libcork/helpers/errors.h \\\n    include/libcork/helpers/gc.h\n\nos_include_HEADERS = \\\n    include/libcork/os/files.h \\\n    include/libcork/os/process.h \\\n    include/libcork/os/subprocess.h\n\nthreads_include_HEADERS = \\\n    include/libcork/threads/atomics.h \\\n    include/libcork/threads/basics.h\n\nlibcork_la_SOURCES = \\\n    src/libcork/cli/commands.c \\\n    src/libcork/core/allocator.c \\\n    src/libcork/core/error.c \\\n    src/libcork/core/gc.c \\\n    src/libcork/core/hash.c \\\n    src/libcork/core/id.c \\\n    src/libcork/core/ip-address.c \\\n    src/libcork/core/mempool.c \\\n    src/libcork/core/timestamp.c \\\n    src/libcork/core/u128.c \\\n    src/libcork/core/version.c \\\n    src/libcork/ds/array.c \\\n    src/libcork/ds/bitset.c \\\n    src/libcork/ds/buffer.c \\\n    src/libcork/ds/dllist.c \\\n    src/libcork/ds/file-stream.c \\\n    src/libcork/ds/hash-table.c \\\n    src/libcork/ds/managed-buffer.c \\\n    src/libcork/ds/ring-buffer.c \\\n    src/libcork/ds/slice.c \\\n    src/libcork/ds/stream.c \\\n    src/libcork/posix/directory-walker.c \\\n    src/libcork/posix/env.c \\\n    src/libcork/posix/exec.c \\\n    src/libcork/posix/files.c \\\n    src/libcork/posix/process.c \\\n    src/libcork/posix/subprocess.c \\\n    src/libcork/pthreads/thread.c\n\npkgconfig_DATA = src/libcork.pc\n\nlibcork_la_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -DCORK_API=CORK_EXPORT\nlibcork_la_CFLAGS = $(AM_CFLAGS) $(CFLAGS) -DCORK_API=CORK_EXPORT\nlibcork_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS) -version-info 17:0:1\n\n#-----------------------------------------------------------------------\n# Utility commands\n\ncork_hash_SOURCES = src/cork-hash/cork-hash.c\ncork_hash_LDADD = libcork.la\n\n#-----------------------------------------------------------------------\n# Tests\n\n# Standalone tests\n\nstandalone_tests = \\\n    test-array \\\n    test-bitset \\\n    test-buffer \\\n    test-core \\\n    test-dllist \\\n    test-files \\\n    test-gc \\\n    test-hash-table \\\n    test-managed-buffer \\\n    test-mempool \\\n    test-ring-buffer \\\n    test-slice \\\n    test-subprocess \\\n    test-threads \\\n    test-u128\n\nEXTRA_DIST += tests/create-u128-test-cases.py\nEXTRA_PROGRAMS += $(standalone_tests)\n\nif RUN_TESTS\n\ncheck_PROGRAMS += $(standalone_tests)\nTESTS += $(standalone_tests)\n\ntests_LDADD_ = libcork.la $(CHECK_LIBS)\ntests_LDFLAGS_ = $(LDFLAGS) -static\n\ntest_array_SOURCES = tests/test-array.c tests/helpers.h\ntest_array_LDADD = $(tests_LDADD_)\ntest_array_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_bitset_SOURCES = tests/test-bitset.c tests/helpers.h\ntest_bitset_LDADD = $(tests_LDADD_)\ntest_bitset_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_buffer_SOURCES = tests/test-buffer.c tests/helpers.h\ntest_buffer_LDADD = $(tests_LDADD_)\ntest_buffer_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_core_SOURCES = tests/test-core.c tests/helpers.h\ntest_core_LDADD = $(tests_LDADD_)\ntest_core_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_dllist_SOURCES = tests/test-dllist.c tests/helpers.h\ntest_dllist_LDADD = $(tests_LDADD_)\ntest_dllist_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_files_SOURCES = tests/test-files.c tests/helpers.h\ntest_files_LDADD = $(tests_LDADD_)\ntest_files_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_gc_SOURCES = tests/test-gc.c tests/helpers.h\ntest_gc_LDADD = $(tests_LDADD_)\ntest_gc_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_hash_table_SOURCES = tests/test-hash-table.c tests/helpers.h\ntest_hash_table_LDADD = $(tests_LDADD_)\ntest_hash_table_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_managed_buffer_SOURCES = tests/test-managed-buffer.c tests/helpers.h\ntest_managed_buffer_LDADD = $(tests_LDADD_)\ntest_managed_buffer_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_mempool_SOURCES = tests/test-mempool.c tests/helpers.h\ntest_mempool_LDADD = $(tests_LDADD_)\ntest_mempool_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_ring_buffer_SOURCES = tests/test-ring-buffer.c tests/helpers.h\ntest_ring_buffer_LDADD = $(tests_LDADD_)\ntest_ring_buffer_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_slice_SOURCES = tests/test-slice.c tests/helpers.h\ntest_slice_LDADD = $(tests_LDADD_)\ntest_slice_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_subprocess_SOURCES = tests/test-subprocess.c tests/helpers.h\ntest_subprocess_LDADD = $(tests_LDADD_)\ntest_subprocess_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_threads_SOURCES = tests/test-threads.c tests/helpers.h\ntest_threads_LDADD = $(tests_LDADD_)\ntest_threads_LDFLAGS = $(tests_LDFLAGS_)\n\ntest_u128_SOURCES = tests/test-u128.c tests/helpers.h\ntest_u128_CPPFLAGS = -I$(builddir)/tests $(AM_CPPFLAGS)\ntest_u128_LDADD = $(tests_LDADD_)\ntest_u128_LDFLAGS = $(tests_LDFLAGS_)\n\nu128_tests = \\\n    tests/u128-tests-eq.c.in \\\n    tests/u128-tests-ne.c.in \\\n    tests/u128-tests-lt.c.in \\\n    tests/u128-tests-le.c.in \\\n    tests/u128-tests-gt.c.in \\\n    tests/u128-tests-ge.c.in \\\n    tests/u128-tests-shl.c.in \\\n    tests/u128-tests-shr.c.in \\\n    tests/u128-tests-add.c.in \\\n    tests/u128-tests-sub.c.in\n\nCLEANFILES += $(u128_tests)\n\ntests/u128-tests-eq.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< eq $@\ntests/u128-tests-ne.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< ne $@\ntests/u128-tests-lt.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< lt $@\ntests/u128-tests-le.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< le $@\ntests/u128-tests-gt.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< gt $@\ntests/u128-tests-ge.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< ge $@\ntests/u128-tests-shl.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< shl $@\ntests/u128-tests-shr.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< shr $@\ntests/u128-tests-add.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< add $@\ntests/u128-tests-sub.c.in: tests/create-u128-test-cases.py\n\t$(AM_V_GEN) $(PYTHON) $< sub $@\n\ntests/test-u128.c: $(u128_tests)\n\nendif RUN_TESTS\n\n# Cram tests\n\nTEST_EXTENSIONS = .t\nEXTRA_DIST += \\\n    tests/ccram \\\n    tests/cram.py \\\n    tests/test-input.txt\n\ncram_tests = \\\n    tests/cork-hash.t \\\n    tests/cork-initializer.t \\\n    tests/cork-test/cleanup.t \\\n    tests/cork-test/directory-watcher.t \\\n    tests/cork-test/help1-c1-s1.t \\\n    tests/cork-test/help1-c1-s2.t \\\n    tests/cork-test/help1-c1.t \\\n    tests/cork-test/help1-c2.t \\\n    tests/cork-test/help1-root.t \\\n    tests/cork-test/help2-c1-s1.t \\\n    tests/cork-test/help2-c1-s2.t \\\n    tests/cork-test/help2-c1.t \\\n    tests/cork-test/help2-c2.t \\\n    tests/cork-test/help2-root.t \\\n    tests/cork-test/help3-c1-s1.t \\\n    tests/cork-test/help3-c1-s2.t \\\n    tests/cork-test/help3-c1.t \\\n    tests/cork-test/help3-c2.t \\\n    tests/cork-test/help3-root.t \\\n    tests/cork-test/no-command-c1.t \\\n    tests/cork-test/no-command-root.t \\\n    tests/cork-test/run-c1-s1-f.t \\\n    tests/cork-test/run-c1-s1-f-t.t \\\n    tests/cork-test/run-c1-s1.t \\\n    tests/cork-test/run-c1-s1-test.t \\\n    tests/cork-test/run-c1-s1-t.t \\\n    tests/cork-test/run-c1-s2-file.t \\\n    tests/cork-test/run-c1-s2-f.t \\\n    tests/cork-test/run-c1-s2.t \\\n    tests/cork-test/run-c2.t \\\n    tests/cork-test/run-find-01.t \\\n    tests/cork-test/run-find-all-01.t \\\n    tests/cork-test/run-mkdir-01.t \\\n    tests/cork-test/run-paths-01.t \\\n    tests/cork-test/run-pwd-01.t \\\n    tests/cork-test/run-rm-01.t \\\n    tests/cork-test/run-sub-01.t \\\n    tests/cork-test/run-sub-02.t \\\n    tests/cork-test/run-sub-03.t \\\n    tests/cork-test/run-sub-04.t \\\n    tests/cork-test/run-sub-05.t \\\n    tests/cork-test/run-sub-06.t\n\nEXTRA_DIST += $(cram_tests)\n\nif RUN_TESTS\n\nTESTS += $(cram_tests)\n\nT_LOG_COMPILER = $(srcdir)/tests/ccram\nAM_T_LOG_FLAGS = \\\n    --python $(PYTHON) \\\n    --root $(srcdir) \\\n    --cram $(srcdir)/tests/cram.py \\\n    --tests\n\ncheck_PROGRAMS += cork-initializer\ncork_initializer_SOURCES = \\\n    src/cork-initializer/init1.c \\\n    src/cork-initializer/init2.c \\\n    src/cork-initializer/main.c\ncork_initializer_LDADD = libcork.la\n\ncheck_PROGRAMS += cork-test\ncork_test_SOURCES = src/cork-test/cork-test.c\ncork_test_LDADD = libcork.la\n\nendif\n\n# If you have test failures during distcheck, cram won't be able to print out\n# the diff, since `make distcheck` causes the unpacked distribution tarball to\n# be read-only.  Uncomment the following to (temporarily) make the unpacked\n# tests directory writeable, so that you can see what caused the test failure.\n#distcheck-hook:\n#\tchmod -R ug+w $(distdir)/tests\n\n# Test harness\n\n@VALGRIND_CHECK_RULES@\n\nif !RUN_TESTS\ncheck-local:\n\t$(error Cannot run test suite without check and Python installed!)\nendif\n"
  },
  {
    "path": "README.markdown",
    "content": "# libcork\n\n[![Build Status](https://travis-ci.org/dcreager/libcork.svg?branch=master)](https://travis-ci.org/dcreager/libcork)\n\nSo what is libcork, exactly?  It's a “simple, easily embeddable,\ncross-platform C library”.  It falls roughly into the same category as\n[glib](http://library.gnome.org/devel/glib/) or\n[APR](http://apr.apache.org/) in the C world; the STL,\n[POCO](http://pocoproject.org/), or [QtCore](http://qt.nokia.com/)\nin the C++ world; or the standard libraries of any decent dynamic\nlanguage.\n\nSo if libcork has all of these comparables, why a new library?  Well,\nnone of the C++ options are really applicable here.  And none of the C\noptions work, because one of the main goals is to have the library be\nhighly modular, and useful in resource-constrained systems.  Once we\ndescribe some of the design decisions that we've made in libcork, you'll\nhopefully see how this fits into an interesting niche of its own.\n\n## Using libcork\n\nThere are two primary ways to use libcork in your own software project:\nas a _shared library_, or _embedded_.\n\nWhen you use libcork as a shared library, you install it just like you\nwould any other C library.  We happen to use CMake as our build system,\nso you follow the usual CMake recipe to install the library.  (See the\n[INSTALL](INSTALL) file for details.)  All of the libcork code is\ncontained within a single shared library (called libcork.so,\nlibcork.dylib, or cork.dll, depending on the system).  We also install a\npkg-config file that makes it easy to add the appropriate compiler flags\nin your own build scripts.  So, you use pkg-config to find libcork's\ninclude and library files, link with libcork, and you're good to go.\n\nThe alternative is to embed libcork into your own software project's\ndirectory structure.  In this case, your build scripts compile the\nlibcork source along with the rest of your code.  This has some\nadvantages for resource-constrained systems, since (assuming your\ncompiler and linker are any good), you only include the libcork routines\nthat you actually use.  And if your toolchain supports link-time\noptimization, the libcork routines can be optimized into the rest of\nyour code.\n\nWhich should you use?  That's really up to you.  Linking against the\nshared library adds a runtime dependency, but gives you the usual\nbenefits of shared libraries: the library in memory is shared across\neach program that uses it; you can install a single bug-fix update and\nall libcork programs automatically take advantage of the new release;\netc.  The embedding option is great if you really need to make your\nlibrary as small as possible, or if you don't want to add that runtime\ndependency.\n\n## Design decisions\n\nNote that having libcork be **easily** embeddable has some ramifications\non the library's design.  In particular, we don't want to make any\nassumptions about which build system you're embedding libcork into.  We\nhappen to use CMake, but you might be using autotools, waf, scons, or\nany number of others.  Most cross-platform libraries follow the\nautotools model of performing some checks at compile time (maybe during\na separate “configure” phase, maybe not) to choose the right API\nimplementation for the current platform.  Since we can't assume a build\nsystem, we have to take a different approach, and do as many checks as\nwe can using the C preprocessor.  Any check that we can't make in the\npreprocessor has to be driven by a C preprocessor macro definition,\nwhich you (the libcork user) are responsible for checking for and\ndefining.  So we need to have as few of those as possible.\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh\n# ------------------------------------------------------------------------------\n# Copyright © 2020, libcork authors.\n# Please see the COPYING file in this distribution for license details.\n# ------------------------------------------------------------------------------\n\nset -e\n\ncd \"$(dirname \"$0\")\"\n\nAUTORECONF=${AUTORECONF:-autoreconf}\nACLOCAL=${ACLOCAL:-aclocal}\nAUTOCONF=${AUTOCONF:-autoconf}\nAUTOHEADER=${AUTOHEADER:-autoheader}\nAUTOMAKE=${AUTOMAKE:-automake}\n\n\"${AUTORECONF}\" --verbose --install --force -I m4\n"
  },
  {
    "path": "build-aux/calculate",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n# Usage:\n#   calculate version|commit [top_srcdir] [path to stamp file]\n#\n# Calculates the current version number.  When run from a distribution tarball,\n# we get the version number from the .version-stamp file (that our `make dist`\n# target ensures that it creates).  When run from a local git repository, we get\n# the version number via `git describe`.\n\nset -e\n\nWHAT=\"$1\"\ncase \"$WHAT\" in\n  version) ;;\n  commit) ;;\n  *) echo \"Unknown option $WHAT\" >&2; exit 1;;\nesac\n\ntop_srcdir=\"${2-.}\"\nexport GIT_DIR=\"${top_srcdir}/.git\"\n\n# First try the stamp file\nSTAMP_FILE=\"$3\"\nif [ -f \"$STAMP_FILE\" ]; then\n  version=$(cat \"$STAMP_FILE\")\n  if [ -z \"$version\" ]; then\n    echo \"Invalid stamp file\" >&2\n    exit 1\n  fi\n  printf \"%s\" \"$version\"\n  exit 0\nfi\n\n# Fall back on `git describe`\ncase \"$WHAT\" in\n  version)\n    closest_tag=$(git describe --abbrev=0)\n    full_version=$(git describe --abbrev=7 --dirty)\n    if test \"$closest_tag\" = \"$full_version\"; then\n        version=\"$closest_tag\"\n    else\n        version=\"$closest_tag-git\"\n    fi\n    ;;\n  commit)\n    version=$(git rev-parse HEAD);;\nesac\nif [ -z \"$version\" ]; then\n  echo \"Cannot find the version from git\" >&2\n  exit 1\nfi\nprintf \"%s\" \"$version\"\n"
  },
  {
    "path": "cmake/FindCTargets.cmake",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2015, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n\n#-----------------------------------------------------------------------\n# Configuration options that control all of the below\n\nset(ENABLE_SHARED YES CACHE BOOL \"Whether to build a shared library\")\nset(ENABLE_SHARED_EXECUTABLES YES CACHE BOOL\n    \"Whether to link executables using shared libraries\")\nset(ENABLE_STATIC YES CACHE BOOL \"Whether to build a static library\")\n\n\n#-----------------------------------------------------------------------\n# Library, with options to build both shared and static versions\n\nfunction(target_add_shared_libraries TARGET_NAME LIBRARIES LOCAL_LIBRARIES)\n    foreach(lib ${LIBRARIES})\n        string(REPLACE \"-\" \"_\" lib ${lib})\n        string(TOUPPER ${lib} upperlib)\n        target_link_libraries(\n            ${TARGET_NAME}\n            ${${upperlib}_LDFLAGS}\n        )\n    endforeach(lib)\n    foreach(lib ${LOCAL_LIBRARIES})\n        target_link_libraries(${TARGET_NAME} ${lib}-shared)\n    endforeach(lib)\nendfunction(target_add_shared_libraries)\n\nfunction(target_add_static_libraries TARGET_NAME LIBRARIES LOCAL_LIBRARIES)\n    foreach(lib ${LIBRARIES})\n        string(REPLACE \"-\" \"_\" lib ${lib})\n        string(TOUPPER ${lib} upperlib)\n        target_link_libraries(\n            ${TARGET_NAME}\n            ${${upperlib}_STATIC_LDFLAGS}\n        )\n    endforeach(lib)\n    foreach(lib ${LOCAL_LIBRARIES})\n        target_link_libraries(${TARGET_NAME} ${lib}-static)\n    endforeach(lib)\nendfunction(target_add_static_libraries)\n\nset_property(GLOBAL PROPERTY ALL_LOCAL_LIBRARIES \"\")\n\nfunction(add_c_library __TARGET_NAME)\n    set(options)\n    set(one_args OUTPUT_NAME PKGCONFIG_NAME VERSION_INFO)\n    set(multi_args LIBRARIES LOCAL_LIBRARIES SOURCES)\n    cmake_parse_arguments(_ \"${options}\" \"${one_args}\" \"${multi_args}\" ${ARGN})\n\n    if (__VERSION_INFO MATCHES \"^([0-9]+):([0-9]+):([0-9]+)(-dev)?$\")\n        set(__VERSION_CURRENT  \"${CMAKE_MATCH_1}\")\n        set(__VERSION_REVISION \"${CMAKE_MATCH_2}\")\n        set(__VERSION_AGE      \"${CMAKE_MATCH_3}\")\n    else (__VERSION_INFO MATCHES \"^([0-9]+):([0-9]+):([0-9]+)(-dev)?$\")\n        message(FATAL_ERROR \"Invalid library version info: ${__VERSION_INFO}\")\n    endif (__VERSION_INFO MATCHES \"^([0-9]+):([0-9]+):([0-9]+)(-dev)?$\")\n\n    # Mimic libtool's behavior in calculating SONAME and VERSION from\n    # version-info.\n    # http://git.savannah.gnu.org/cgit/libtool.git/tree/build-aux/ltmain.in?id=722b6af0fad19b3d9f21924ae5aa6dfae5957378#n7042\n    math(EXPR __SOVERSION \"${__VERSION_CURRENT} - ${__VERSION_AGE}\")\n    set(__VERSION \"${__SOVERSION}.${__VERSION_AGE}.${__VERSION_REVISION}\")\n\n    get_property(ALL_LOCAL_LIBRARIES GLOBAL PROPERTY ALL_LOCAL_LIBRARIES)\n    list(APPEND ALL_LOCAL_LIBRARIES ${__TARGET_NAME})\n    set_property(GLOBAL PROPERTY ALL_LOCAL_LIBRARIES \"${ALL_LOCAL_LIBRARIES}\")\n\n    if (ENABLE_SHARED OR ENABLE_SHARED_EXECUTABLES)\n        add_library(${__TARGET_NAME}-shared SHARED ${__SOURCES})\n        set_target_properties(\n            ${__TARGET_NAME}-shared PROPERTIES\n            OUTPUT_NAME ${__OUTPUT_NAME}\n            CLEAN_DIRECT_OUTPUT 1\n            VERSION ${__VERSION}\n            SOVERSION ${__SOVERSION}\n        )\n\n        if (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n            target_include_directories(\n                ${__TARGET_NAME}-shared PUBLIC\n                ${CMAKE_SOURCE_DIR}/include\n                ${CMAKE_BINARY_DIR}/include\n            )\n        else (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n            include_directories(\n                ${CMAKE_SOURCE_DIR}/include\n                ${CMAKE_BINARY_DIR}/include\n            )\n        endif (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n\n        target_add_shared_libraries(\n            ${__TARGET_NAME}-shared\n            \"${__LIBRARIES}\"\n            \"${__LOCAL_LIBRARIES}\"\n        )\n\n        # We have to install the shared library if the user asked us to, or if\n        # the user asked us to link our programs with the shared library.\n        install(TARGETS ${__TARGET_NAME}-shared\n                LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})\n    endif (ENABLE_SHARED OR ENABLE_SHARED_EXECUTABLES)\n\n    if (ENABLE_STATIC OR NOT ENABLE_SHARED_EXECUTABLES)\n        add_library(${__TARGET_NAME}-static STATIC ${__SOURCES})\n        set_target_properties(\n            ${__TARGET_NAME}-static PROPERTIES\n            OUTPUT_NAME ${__OUTPUT_NAME}\n            CLEAN_DIRECT_OUTPUT 1\n        )\n\n        if (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n            target_include_directories(\n                ${__TARGET_NAME}-static PUBLIC\n                ${CMAKE_SOURCE_DIR}/include\n                ${CMAKE_BINARY_DIR}/include\n            )\n        else (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n            include_directories(\n                ${CMAKE_SOURCE_DIR}/include\n                ${CMAKE_BINARY_DIR}/include\n            )\n        endif (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n\n        target_add_static_libraries(\n            ${__TARGET_NAME}-static\n            \"${__LIBRARIES}\"\n            \"${__LOCAL_LIBRARIES}\"\n        )\n    endif (ENABLE_STATIC OR NOT ENABLE_SHARED_EXECUTABLES)\n\n    if (ENABLE_STATIC)\n        # We DON'T have to install the static library if the user asked us to\n        # link our programs statically.\n        install(TARGETS ${__TARGET_NAME}-static\n                ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})\n    endif (ENABLE_STATIC)\n\n    set(PACKAGE_TARNAME \"${PROJECT_NAME}\")\n    set(prefix ${CMAKE_INSTALL_PREFIX})\n    set(exec_prefix \"\\${prefix}\")\n    set(datarootdir \"\\${prefix}/share\")\n    set(includedir \"\\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\")\n    set(libdir \"\\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}\")\n    string(REPLACE\n      \"${CMAKE_INSTALL_DATAROOTDIR}/\" \"\"\n      base_docdir\n      \"${CMAKE_INSTALL_DOCDIR}\")\n    set(docdir \"\\${datarootdir}/${base_docdir}\")\n    configure_file(\n        ${CMAKE_CURRENT_SOURCE_DIR}/${__PKGCONFIG_NAME}.pc.in\n        ${CMAKE_CURRENT_BINARY_DIR}/${__PKGCONFIG_NAME}.pc\n        @ONLY\n    )\n    install(\n        FILES ${CMAKE_CURRENT_BINARY_DIR}/${__PKGCONFIG_NAME}.pc\n        DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig\n    )\nendfunction(add_c_library)\n\n\n#-----------------------------------------------------------------------\n# Executable\n\nfunction(add_c_executable __TARGET_NAME)\n    set(options SKIP_INSTALL)\n    set(one_args OUTPUT_NAME)\n    set(multi_args LIBRARIES LOCAL_LIBRARIES SOURCES)\n    cmake_parse_arguments(_ \"${options}\" \"${one_args}\" \"${multi_args}\" ${ARGN})\n\n    add_executable(${__TARGET_NAME} ${__SOURCES})\n\n    if (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n        target_include_directories(\n            ${__TARGET_NAME} PUBLIC\n            ${CMAKE_SOURCE_DIR}/include\n            ${CMAKE_BINARY_DIR}/include\n        )\n    else (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n        include_directories(\n            ${CMAKE_SOURCE_DIR}/include\n            ${CMAKE_BINARY_DIR}/include\n        )\n    endif (CMAKE_VERSION VERSION_GREATER \"2.8.11\")\n\n    if (ENABLE_SHARED_EXECUTABLES)\n        target_add_shared_libraries(\n            ${__TARGET_NAME}\n            \"${__LIBRARIES}\"\n            \"${__LOCAL_LIBRARIES}\"\n        )\n    else (ENABLE_SHARED_EXECUTABLES)\n        target_add_static_libraries(\n            ${__TARGET_NAME}\n            \"${__LIBRARIES}\"\n            \"${__LOCAL_LIBRARIES}\"\n        )\n    endif (ENABLE_SHARED_EXECUTABLES)\n\n    if (NOT __SKIP_INSTALL)\n        install(TARGETS ${__TARGET_NAME} RUNTIME DESTINATION bin)\n    endif (NOT __SKIP_INSTALL)\nendfunction(add_c_executable)\n\n\n#-----------------------------------------------------------------------\n# Test case\n\npkgconfig_prereq(check OPTIONAL)\n\nfunction(add_c_test TEST_NAME)\n    get_property(ALL_LOCAL_LIBRARIES GLOBAL PROPERTY ALL_LOCAL_LIBRARIES)\n    add_c_executable(\n        ${TEST_NAME}\n        SKIP_INSTALL\n        OUTPUT_NAME ${TEST_NAME}\n        SOURCES ${TEST_NAME}.c\n        LIBRARIES check\n        LOCAL_LIBRARIES ${ALL_LOCAL_LIBRARIES}\n    )\n    add_test(${TEST_NAME} ${TEST_NAME})\nendfunction(add_c_test)\n"
  },
  {
    "path": "cmake/FindParseArguments.cmake",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2015, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n\n# CMake 2.8.4 and higher gives us cmake_parse_arguments out of the box.  For\n# earlier versions (RHEL5!) we have to define it ourselves.  (The definition\n# comes from <http://www.cmake.org/Wiki/CMakeMacroParseArguments>.)\n\nif (CMAKE_VERSION VERSION_LESS \"2.8.4\")\n\nMACRO(CMAKE_PARSE_ARGUMENTS prefix arg_names option_names)\n  SET(DEFAULT_ARGS)\n  FOREACH(arg_name ${arg_names})\n    SET(${prefix}_${arg_name})\n  ENDFOREACH(arg_name)\n  FOREACH(option ${option_names})\n    SET(${prefix}_${option} FALSE)\n  ENDFOREACH(option)\n\n  SET(current_arg_name DEFAULT_ARGS)\n  SET(current_arg_list)\n  FOREACH(arg ${ARGN})\n    SET(larg_names ${arg_names})\n    LIST(FIND larg_names \"${arg}\" is_arg_name)\n    IF (is_arg_name GREATER -1)\n      SET(${prefix}_${current_arg_name} ${current_arg_list})\n      SET(current_arg_name ${arg})\n      SET(current_arg_list)\n    ELSE (is_arg_name GREATER -1)\n      SET(loption_names ${option_names})\n      LIST(FIND loption_names \"${arg}\" is_option)\n      IF (is_option GREATER -1)\n          SET(${prefix}_${arg} TRUE)\n      ELSE (is_option GREATER -1)\n          SET(current_arg_list ${current_arg_list} ${arg})\n      ENDIF (is_option GREATER -1)\n    ENDIF (is_arg_name GREATER -1)\n  ENDFOREACH(arg)\n  SET(${prefix}_${current_arg_name} ${current_arg_list})\nENDMACRO(CMAKE_PARSE_ARGUMENTS)\n\nelse (CMAKE_VERSION VERSION_LESS \"2.8.4\")\n\n    include(CMakeParseArguments)\n\nendif (CMAKE_VERSION VERSION_LESS \"2.8.4\")\n"
  },
  {
    "path": "cmake/FindPrereqs.cmake",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2015, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n\n#-----------------------------------------------------------------------\n# Configuration options that control all of the below\n\nset(PKG_CONFIG_PATH CACHE STRING \"pkg-config search path\")\nif (PKG_CONFIG_PATH)\n    set(ENV{PKG_CONFIG_PATH} \"${PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH}\")\nendif (PKG_CONFIG_PATH)\n\n\n#-----------------------------------------------------------------------\n# pkg-config prerequisites\n\nfind_package(PkgConfig)\n\nfunction(pkgconfig_prereq DEP)\n    set(options OPTIONAL)\n    set(one_args)\n    set(multi_args)\n    cmake_parse_arguments(_ \"${options}\" \"${one_args}\" \"${multi_args}\" ${ARGN})\n\n    string(REGEX REPLACE \"[<>=].*\" \"\" SHORT_NAME \"${DEP}\")\n    string(REPLACE \"-\" \"_\" SHORT_NAME \"${SHORT_NAME}\")\n    string(TOUPPER ${SHORT_NAME} UPPER_SHORT_NAME)\n    string(TOLOWER ${SHORT_NAME} LOWER_SHORT_NAME)\n\n    set(USE_CUSTOM_${UPPER_SHORT_NAME} NO CACHE BOOL\n        \"Whether you want to provide custom details for ${LOWER_SHORT_NAME}\")\n\n    if (NOT USE_CUSTOM_${UPPER_SHORT_NAME})\n        set(PKG_CHECK_ARGS)\n        if (NOT __OPTIONAL)\n            list(APPEND PKG_CHECK_ARGS REQUIRED)\n        endif (NOT __OPTIONAL)\n        list(APPEND PKG_CHECK_ARGS ${DEP})\n\n        pkg_check_modules(${UPPER_SHORT_NAME} ${PKG_CHECK_ARGS})\n    endif (NOT USE_CUSTOM_${UPPER_SHORT_NAME})\n\n    include_directories(${${UPPER_SHORT_NAME}_INCLUDE_DIRS})\n    link_directories(${${UPPER_SHORT_NAME}_LIBRARY_DIRS})\nendfunction(pkgconfig_prereq)\n\n\n#-----------------------------------------------------------------------\n# find_library prerequisites\n\nfunction(library_prereq LIB_NAME)\n    set(options OPTIONAL)\n    set(one_args)\n    set(multi_args)\n    cmake_parse_arguments(_ \"${options}\" \"${one_args}\" \"${multi_args}\" ${ARGN})\n\n    string(REPLACE \"-\" \"_\" SHORT_NAME \"${LIB_NAME}\")\n    string(TOUPPER ${SHORT_NAME} UPPER_SHORT_NAME)\n    string(TOLOWER ${SHORT_NAME} LOWER_SHORT_NAME)\n\n    set(USE_CUSTOM_${UPPER_SHORT_NAME} NO CACHE BOOL\n        \"Whether you want to provide custom details for ${LOWER_SHORT_NAME}\")\n\n    if (USE_CUSTOM_${UPPER_SHORT_NAME})\n        include_directories(${${UPPER_SHORT_NAME}_INCLUDE_DIRS})\n        link_directories(${${UPPER_SHORT_NAME}_LIBRARY_DIRS})\n        if (NOT ${UPPER_SHORT_NAME}_STATIC_LDFLAGS)\n            set(${UPPER_SHORT_NAME}_STATIC_LDFLAGS\n                ${${UPPER_SHORT_NAME}_LDFLAGS}\n                PARENT_SCOPE)\n        endif (NOT ${UPPER_SHORT_NAME}_STATIC_LDFLAGS)\n    else (USE_CUSTOM_${UPPER_SHORT_NAME})\n        find_library(${UPPER_SHORT_NAME}_LDFLAGS ${LIB_NAME})\n        set(${UPPER_SHORT_NAME}_STATIC_LDFLAGS\n            ${${UPPER_SHORT_NAME}_LDFLAGS}\n            PARENT_SCOPE)\n    endif (USE_CUSTOM_${UPPER_SHORT_NAME})\n\nendfunction(library_prereq)\n"
  },
  {
    "path": "configure.ac",
    "content": "# -*- coding: utf-8 -*-\n# ------------------------------------------------------------------------------\n# Copyright © 2018, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ------------------------------------------------------------------------------\n\nAC_INIT([libcork],\n        m4_esyscmd([build-aux/calculate version . .version-stamp]),\n        [info@libcork.io])\nAC_CONFIG_AUX_DIR([build-aux])\nAC_CONFIG_MACRO_DIR([m4])\nAC_CONFIG_SRCDIR([src/libcork/core/version.c])\nAM_INIT_AUTOMAKE([foreign no-dist-gzip dist-xz subdir-objects])\nAM_MAINTAINER_MODE([enable])  # Allow packagers to disable if they want\nAM_SILENT_RULES([yes])\nLT_INIT\n\n# Generating version-stamp files\nAC_PATH_PROG(GIT, [git])\nif test -z \"$GIT\" ; then\n  AC_MSG_FAILURE([cannot find 'git'])\nfi\n\n# Versions\nAC_PROG_AWK\nAC_PROG_SED\nBASE_VERSION=`AS_ECHO([$VERSION]) | sed -e 's/\\-.*//'`\nAC_SUBST(CORK_VERSION_MAJOR, [`AS_ECHO([$BASE_VERSION]) | $AWK -F. '{print $1}'`])\nAC_SUBST(CORK_VERSION_MINOR, [`AS_ECHO([$BASE_VERSION]) | $AWK -F. '{print $2}'`])\nAC_SUBST(CORK_VERSION_PATCH, [`AS_ECHO([$BASE_VERSION]) | $AWK -F. '{print $3}'`])\nAC_SUBST(CORK_VERSION, [\"$VERSION\"])\nAC_SUBST(CORK_GIT_SHA1, m4_esyscmd([build-aux/calculate commit . .commit-stamp]))\nAC_CONFIG_FILES([include/libcork/config/version.h])\nAC_PROG_CC\nAC_PROG_CC_C99\n\n# TAP support\nAC_PROG_AWK\n\n# Threads\nAX_PTHREAD\nLIBS=\"$PTHREAD_LIBS $LIBS\"\nCFLAGS=\"$CFLAGS $PTHREAD_CFLAGS\"\nCC=\"$PTHREAD_CC\"\n\n# pkg-config\nPKG_INSTALLDIR\nAC_CONFIG_FILES([src/libcork.pc])\n\n# Tests\nAM_PATH_PYTHON([2.3], , [:])\nPKG_CHECK_MODULES(CHECK, [check], [check=yes], [check=no])\nAM_CONDITIONAL(RUN_TESTS, [test \"$PYTHON\" != : -a $check = yes])\n\n# Valgrind support\nAX_VALGRIND_DFLT([memcheck], [on])\nAX_VALGRIND_DFLT([helgrind], [off])\nAX_VALGRIND_DFLT([drd], [off])\nAX_VALGRIND_DFLT([sgcheck], [off])\nAX_VALGRIND_CHECK()\n\n# Turn on fatal warnings by default; you can override this by setting CPPFLAGS\n# to something else when running configure.\n: ${CPPFLAGS=\"-Wall -Werror\"}\n\nAC_OUTPUT([Makefile])\n\ncat <<EOF\n\n------------------ Summary ------------------\n $PACKAGE_NAME version $PACKAGE_VERSION\n  Prefix.........: $prefix\n  C Compiler.....: $CC $CFLAGS $CPPFLAGS\n  Linker.........: $LD $LDFLAGS $LIBS\n---------------------------------------------\n\nCheck the above options and compile with:\n ${MAKE-make}\n\nEOF\n"
  },
  {
    "path": "docs/.gitattributes",
    "content": "*.graffle      -diff -whitespace\n/*.[1-9]       -diff -whitespace\n"
  },
  {
    "path": "docs/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n# Fill in this with the text that you want to include in the header and footer\n# of each man page.\n\nset(MAN_HEADER \"${PROJECT_NAME} documentation\")\nset(MAN_FOOTER \"${PROJECT_NAME}\")\n\n# Fill this in with any man pages that should be built from a pandoc source\n# file.  For a man page called foo.5, there should be a pandoc source file\n# called foo.5.md.\n\nset(MAN_PAGES\n)\n\n#-----------------------------------------------------------------------\n# Everything below is boilerplate!\n\nfind_program(\n    PANDOC_EXECUTABLE\n    NAMES pandoc\n    HINTS ENV PANDOC_DIR\n    PATH_SUFFIXES bin\n    DOC \"Pandoc man page generator\"\n)\n\nset(GENERATE_DOC TRUE CACHE BOOL\n    \"Whether to rebuild documentation\")\n\nif (NOT PANDOC_EXECUTABLE)\n    message(WARNING \"Unable to find pandoc documentation generator\")\n    set(GENERATE_DOC FALSE)\nendif (NOT PANDOC_EXECUTABLE)\n\n\n# Link man pages go in docs/links\n\nmacro(install_links section)\n    file(GLOB links \"links/*.${section}\")\n    if (links)\n        install(\n            FILES ${links}\n            DESTINATION \"share/man/man${section}\"\n        )\n    endif (links)\nendmacro(install_links section)\n\ninstall_links(1)   # commands\ninstall_links(3)   # library API\ninstall_links(4)   # special files and drivers\ninstall_links(5)   # file formats and conventions\ninstall_links(7)   # miscellaneous\ninstall_links(8)   # system commands\n\n\n# Man pages with actual content go in docs\n\nset(ALL_MANS)\n\nmacro(pandocify name)\n    set(src \"${CMAKE_CURRENT_SOURCE_DIR}/${name}.md\")\n    set(dest \"${CMAKE_CURRENT_SOURCE_DIR}/${name}\")\n    get_filename_component(section \"${name}\" EXT)\n    string(REPLACE \".\" \"\" section \"${section}\")\n\n    # Only compile the markdown source into groff man pages if requested.\n    if (GENERATE_DOC)\n        add_custom_command(\n            OUTPUT ${dest}\n            COMMAND ${PANDOC_EXECUTABLE}\n                -f markdown -t man -s --smart\n                -V header=\"${MAN_HEADER}\"\n                -V footer=\"${MAN_FOOTER}\"\n                -V date=${RELEASE_DATE}\n                -o ${dest} ${src}\n            MAIN_DEPENDENCY ${src}\n            COMMENT \"Building ${name}\"\n        )\n        list(APPEND ALL_MANS ${dest})\n    endif (GENERATE_DOC)\n\n    # We should always have an already-compiled copy of each man page in the\n    # source tree, which we can install even if we didn't build fresh new\n    # copies.\n    install(\n        FILES ${dest}\n        DESTINATION \"share/man/man${section}\"\n    )\nendmacro(pandocify)\n\nforeach(MAN_PAGE ${MAN_PAGES})\n    pandocify(${MAN_PAGE})\nendforeach(MAN_PAGE)\n\nadd_custom_target(doc ALL DEPENDS ${ALL_MANS})\n"
  },
  {
    "path": "docs/old/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\nfind_program(\n  SPHINX_EXECUTABLE\n  NAMES sphinx-build\n  HINTS ENV SPHINX_DIR\n  PATH_SUFFIXES bin\n  DOC \"Sphinx documentation generator\"\n)\n\nset(GENERATE_DOC TRUE)\n\nif (NOT SPHINX_EXECUTABLE)\n  message(WARNING \"Unable to find Sphinx documentation generator\")\n  set(GENERATE_DOC FALSE)\nendif (NOT SPHINX_EXECUTABLE)\n\nset(INTERSPHINX_OVERRIDES \"\")\n\nmacro(find_prereq_doc LIB_NAME)\n  execute_process(\n    COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=sphinxdir ${LIB_NAME}\n    OUTPUT_VARIABLE LIB_SPHINX_DIR\n    OUTPUT_STRIP_TRAILING_WHITESPACE\n  )\n\n  if (LIB_SPHINX_DIR)\n    message(STATUS \"Using ${LIB_NAME} docs in ${LIB_SPHINX_DIR}\")\n    set(\n      INTERSPHINX_OVERRIDES\n      \"${INTERSPHINX_OVERRIDES}\\nintersphinx_mapping['${LIB_NAME}'] = ('${LIB_SPHINX_DIR}', None)\"\n    )\n  endif (LIB_SPHINX_DIR)\nendmacro(find_prereq_doc)\n\nif (GENERATE_DOC)\n  set(SPHINX_SRC_CONF_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/conf.py\")\n  set(SPHINX_CONF_FILE \"${CMAKE_CURRENT_BINARY_DIR}/conf.py\")\n  set(SPHINX_CACHE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/_doctrees\")\n  set(SPHINX_HTML_DIR \"${CMAKE_CURRENT_BINARY_DIR}/html\")\n\n  # If your Sphinx documentation references the Sphinx documentation of\n  # any of your prerequisite libraries, add some calls to\n  # find_prereq_doc here:\n  #\n  # find_prereq_doc(libcork)\n\n  set(\n    VERSION_FOR_CONF_PY\n    \"\\nrelease=\\\"${VERSION}\\\"\\nversion=\\\"${BASE_VERSION}\\\"\"\n  )\n  configure_file(${SPHINX_SRC_CONF_FILE} ${SPHINX_CONF_FILE} @ONLY)\n  file(COPY _static DESTINATION ${CMAKE_CURRENT_BINARY_DIR})\n  file(COPY _templates DESTINATION ${CMAKE_CURRENT_BINARY_DIR})\n\n  add_custom_target(old-doc ALL\n    ${SPHINX_EXECUTABLE}\n      -b html\n      -d \"${SPHINX_CACHE_DIR}\"\n      -c \"${CMAKE_CURRENT_BINARY_DIR}\"\n      \"${CMAKE_CURRENT_SOURCE_DIR}\"\n      \"${SPHINX_HTML_DIR}\"\n    COMMENT \"Building HTML documentation with Sphinx\"\n  )\n\n  list(APPEND CLEAN_FILES \"${SPHINX_CACHE_DIR}\" \"${SPHINX_HTML_DIR}\")\n  set_directory_properties(\n    PROPERTIES\n    ADDITIONAL_MAKE_CLEAN_FILES \"${CLEAN_FILES}\"\n  )\n\n  install(\n    DIRECTORY \"${SPHINX_HTML_DIR}\"\n    DESTINATION \"${CMAKE_INSTALL_DOCDIR}\"\n  )\nendif (GENERATE_DOC)\n"
  },
  {
    "path": "docs/old/_static/.keep",
    "content": ""
  },
  {
    "path": "docs/old/_static/docco-sphinx.css",
    "content": "@import url(\"basic.css\");\n\n/* -- page layout ----------------------------------------------------------- */\n\nbody {\n    font-family: 'Palatino Linotype', Palatino, 'URW Palladio L', 'Book Antiqua', FreeSerif, serif;\n    /*font-size: 95%;*/\n    font-size: 95%;\n    color: #252519;\n    margin: 0;\n    padding: 0;\n}\n\ndiv.document {\n}\n\ndiv.documentwrapper {\n    float: left;\n    width: 100%;\n}\n\ndiv.bodywrapper {\n    margin: 0 0 0 19em;\n    background-color: #ffffff;\n}\n\ndiv.body {\n    color: #252519;\n    padding: 30px 0px 30px 60px;\n    width: 40em;\n}\n\ndiv.footer {\n    width: 100%;\n    padding: 9px 0 9px 0;\n    text-align: center;\n    font-size: 75%;\n}\n\ndiv.footer a {\n    color: #261a3b;\n    text-decoration: underline;\n}\n\ndiv.related {\n    background-color: #eee;\n    border: 1px solid #ccc;\n    line-height: 30px;\n}\n\ndiv.related a {\n    color: #261a3b;\n}\n\ndiv.sphinxsidebar {\n    padding: 30px 0px 0 20px;\n    width: 19em;\n    color: #555;\n}\n\ndiv.sphinxsidebar a {\n    color: #555;\n}\n\ndiv.sphinxsidebar h3 {\n    font-size: 1.4em;\n    margin: 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar h4 {\n    font-size: 1.3em;\n    margin: 5px 0 0 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar p {\n}\n\ndiv.sphinxsidebar p.topless {\n    margin: 5px 10px 10px 10px;\n}\n\ndiv.sphinxsidebar ul {\n    margin: 10px;\n    padding: 0;\n    color: #ffffff;\n}\n\ndiv.sphinxsidebar li {\n    padding-top: 5px;\n    line-height: 115%;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #ccc;\n    font-family: sans-serif;\n    font-size: 1em;\n}\n\n\n\n/* -- hyperlink styles ------------------------------------------------------ */\n\na {\n    color: #306060;\n    text-decoration: none;\n}\n\na:visited {\n    color: #306060;\n    text-decoration: none;\n}\n\na:hover {\n    text-decoration: underline;\n}\n\n\n\n/* -- body styles ----------------------------------------------------------- */\n\ndiv.body h1,\ndiv.body h2 {\n    border-top: 1px solid #ccc;\n    margin: 40px -20px 10px -20px;\n    padding: 3px 0 3px 0;\n}\n\ndiv.body h3,\ndiv.body h4,\ndiv.body h5,\ndiv.body h6 {\n    margin: 20px 0px -10px 0px;\n}\n\ndiv.body h1 { margin-top: 0; font-size: 200%; border: 0px; }\ndiv.body h2 { font-size: 160%; }\ndiv.body h3 { font-size: 140%; }\ndiv.body h4 { font-size: 120%; }\ndiv.body h5 { font-size: 110%; }\ndiv.body h6 { font-size: 100%; }\n\na.headerlink {\n    color: #c60f0f;\n    font-size: 0.8em;\n    padding: 0 4px 0 4px;\n    text-decoration: none;\n}\n\na.headerlink:hover {\n    background-color: #c60f0f;\n    color: white;\n}\n\ndiv.body p, div.body dd, div.body li {\n    line-height: 130%;\n}\n\np.admonition-title {\n    margin-right: 0.3em;\n}\n\ndiv.admonition p.admonition-title + p {\n    display: inline;\n}\n\ndiv.admonition p {\n    margin-bottom: 5px;\n}\n\ndiv.admonition pre {\n    margin-bottom: 5px;\n}\n\ndiv.admonition ul, div.admonition ol {\n    margin-bottom: 5px;\n}\n\ndiv.note {\n    background-color: #eee;\n    border: 1px solid #ccc;\n}\n\ndiv.seealso {\n    background-color: #ffc;\n    border: 1px solid #ff6;\n}\n\ndiv.tip {\n    background-color: #e4e4ff;\n    border: 1px solid #ccc;\n}\n\ndiv.topic {\n    background-color: #eee;\n}\n\ndiv.warning {\n    background-color: #ffe4e4;\n    border: 1px solid #f66;\n}\n\np.admonition-title {\n    display: inline;\n}\n\np.admonition-title:after {\n    content: \":\";\n}\n\npre {\n    font-family: Menlo, Monaco, Consolas, \"Lucida Console\", monospace;\n    font-size: 80%;\n    padding: 5px;\n    background-color: #f5f5ff;\n    color: #333333;\n    line-height: 130%;\n    border: 1px solid #e5e5ee;\n    border-left: none;\n    border-right: none;\n}\n\ntt {\n    font-family: Menlo, Monaco, Consolas, \"Lucida Console\", monospace;\n    background-color: #f8f8ff;\n    border: 1px solid #dedede;\n    padding: 0 0.2em;\n    font-size: 85%;\n}\n\na tt {\n    background-color: transparent;\n    border: 0px;\n}\n\ndt {\n    font-family: Menlo, Monaco, Consolas, \"Lucida Console\", monospace;\n    font-size: 90%;\n    line-height: 130%;\n}\n\ntable.indextable dt {\n    font-family: 'Palatino Linotype', Palatino, 'URW Palladio L', 'Book Antiqua', FreeSerif, serif;\n    font-size: 100%;\n}\n\nem.property {\n    font-size: 90%;\n}\n\ntt.descclassname {\n    background-color: transparent;\n    border: 0px;\n    padding: 0px;\n}\n\ntt.descname {\n    background-color: transparent;\n    border: 0px;\n    font-size: 100%;\n    padding: 0px;\n}\n\ndt big {\n    font-family: 'Palatino Linotype', Palatino, 'URW Palladio L', 'Book Antiqua', FreeSerif, serif;\n    font-size: 140%;\n    padding: 0 2px;\n}\n\ndt big.param_start_brace {\n    padding: 0 6px;\n}\n\ndt big.param_end_brace {\n    padding: 0 6px;\n}\n\ndt span.optional {\n    font-family: 'Palatino Linotype', Palatino, 'URW Palladio L', 'Book Antiqua', FreeSerif, serif;\n    font-size: 140%;\n    padding: 0 2px;\n}\n\nth {\n    background-color: #ede;\n}\n\n.warning tt {\n    background: #efc2c2;\n}\n\n.note tt {\n    background: #d6d6d6;\n}\n\n.viewcode-back {\n    font-family: sans-serif;\n}\n\ndiv.viewcode-block:target {\n    background-color: #f4debf;\n    border-top: 1px solid #ac9;\n    border-bottom: 1px solid #ac9;\n}\n"
  },
  {
    "path": "docs/old/_static/pygments.css",
    "content": ".highlight .hll { background-color: #ffffcc }\n.highlight .c { color: #408080; font-style: italic }  /* Comment */\n.highlight .err { border: 1px solid #FF0000 }         /* Error */\n.highlight .k { color: #954121 }                      /* Keyword */\n.highlight .o { color: #666666 }                      /* Operator */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 }                     /* Comment.Preproc */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 }                     /* Generic.Deleted */\n.highlight .ge { font-style: italic }                 /* Generic.Emph */\n.highlight .gr { color: #FF0000 }                     /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold }  /* Generic.Heading */\n.highlight .gi { color: #00A000 }                     /* Generic.Inserted */\n.highlight .go { color: #808080 }                     /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold }  /* Generic.Prompt */\n.highlight .gs { font-weight: bold }                  /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold }  /* Generic.Subheading */\n.highlight .gt { color: #0040D0 }                     /* Generic.Traceback */\n.highlight .kc { color: #954121 }                     /* Keyword.Constant */\n.highlight .kd { color: #954121; font-weight: bold }  /* Keyword.Declaration */\n.highlight .kn { color: #954121; font-weight: bold }  /* Keyword.Namespace */\n.highlight .kp { color: #954121 }                     /* Keyword.Pseudo */\n.highlight .kr { color: #954121; font-weight: bold }  /* Keyword.Reserved */\n.highlight .kt { color: #B00040 }                     /* Keyword.Type */\n.highlight .m { color: #666666 }                      /* Literal.Number */\n.highlight .s { color: #219161 }                      /* Literal.String */\n.highlight .na { color: #7D9029 }                     /* Name.Attribute */\n.highlight .nb { color: #954121 }                     /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold }  /* Name.Class */\n.highlight .no { color: #880000 }                     /* Name.Constant */\n.highlight .nd { color: #AA22FF }                     /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold }  /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold }  /* Name.Exception */\n.highlight .nf { color: #0000FF }                     /* Name.Function */\n.highlight .nl { color: #A0A000 }                     /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold }  /* Name.Namespace */\n.highlight .nt { color: #954121; font-weight: bold }  /* Name.Tag */\n.highlight .nv { color: #19469D }                     /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold }  /* Operator.Word */\n.highlight .w { color: #bbbbbb }                      /* Text.Whitespace */\n.highlight .mf { color: #666666 }                     /* Literal.Number.Float */\n.highlight .mh { color: #666666 }                     /* Literal.Number.Hex */\n.highlight .mi { color: #666666 }                     /* Literal.Number.Integer */\n.highlight .mo { color: #666666 }                     /* Literal.Number.Oct */\n.highlight .sb { color: #219161 }                     /* Literal.String.Backtick */\n.highlight .sc { color: #219161 }                     /* Literal.String.Char */\n.highlight .sd { color: #219161; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #219161 }                     /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold }  /* Literal.String.Escape */\n.highlight .sh { color: #219161 }                     /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold }  /* Literal.String.Interpol */\n.highlight .sx { color: #954121 }                     /* Literal.String.Other */\n.highlight .sr { color: #BB6688 }                     /* Literal.String.Regex */\n.highlight .s1 { color: #219161 }                     /* Literal.String.Single */\n.highlight .ss { color: #19469D }                     /* Literal.String.Symbol */\n.highlight .bp { color: #954121 }                     /* Name.Builtin.Pseudo */\n.highlight .vc { color: #19469D }                     /* Name.Variable.Class */\n.highlight .vg { color: #19469D }                     /* Name.Variable.Global */\n.highlight .vi { color: #19469D }                     /* Name.Variable.Instance */\n.highlight .il { color: #666666 }                     /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "docs/old/_templates/.keep",
    "content": ""
  },
  {
    "path": "docs/old/allocation.rst",
    "content": ".. _allocation:\n\n*****************\nMemory allocation\n*****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nOne of the biggest hassles in writing C code is memory management.  libcork's\nmemory allocation API tries to simplify this task as much as possible.  This is\nstill C, so you still have to manage allocated memory manually — for instance,\nby keeping careful track of which section of code \"owns\" any memory that you've\nallocated from heap, and is therefore responsible for freeing it.  But we *can*\nmake it easier to handle memory allocation failures, and provide helper macros\nfor certain common allocation tasks.\n\nThere is another `important use case`_ that we also want to support: giving\napplication writers complete control over how the libraries they use allocate\nand deallocate memory.  libcork :ref:`provides <libcork-allocators>` this\ncapability, giving you control over how, for instance, a hash table allocates\nits internal buckets.  If you're writing a library that links with libcork as a\nshared library, you'll get this behavior for free; if the application writer\ncustomizes how libcork allocates memory, your library will pick up that\ncustomization as well.  If you're embedding libcork, so that your library's\nclients can't tell (or care) that you're using libcork, then you'll want to\nexpose your own similar customization interface.\n\n.. _important use case: https://blog.mozilla.org/nnethercote/2013/11/08/libraries-should-permit-custom-allocators/\n\n\n.. _allocation-api:\n\nAllocating memory\n=================\n\nThe simplest part of the API is the part responsible for actually allocating and\ndeallocating memory.  When using this part of the API, you don't have to worry\nabout customization at all; the functions described here will automatically \"do\nthe right thing\" based on how your library or application is configured.  The\nbiggest thing to worry about is how to handle memory allocation failures.  We\nprovide two strategies, \"guaranteed\" and \"recoverable\".\n\nThe most common use case is that running out of memory is a Really Bad Thing,\nand there's nothing we can do to recover.  In this case, it doesn't make sense\nto check for memory allocation failures throughout your code, since you can't\nreally do anything if it does happen.  The \"guaranteed\" family of functions\nhandles that error checking for you, and guarantees that if the allocation\nfunction returns, it will return a valid piece of memory.  If the allocation\nfails, the function will never return.  That allows you to right simple and safe\ncode like the following::\n\n    struct my_type  *instance = cork_new(struct my_type);\n    /* Just start using instance; don't worry about verifying that it's\n     * not NULL! */\n\nOn the other hand, you might be writing some code that can gracefully handle a\nmemory allocation failure.  You might try to allocate a super-huge cache, for\ninstance; if you can't allocate the cache, your code will still work, it will\njust be a bit slower.  In this case, you *want* to be able to detect memory\nallocation failures, and handle them in whatever way is appropriate.  The\n\"recoverable\" family of functions will return a ``NULL`` pointer if allocation\nfails.\n\n.. note::\n\n   libcork itself uses the guaranteed functions for all internal memory\n   allocation.\n\n\nGuaranteed allocation\n---------------------\n\nThe functions in this section are guaranteed to return a valid newly allocated\npointer.  If memory allocation fails, the functions will not return.\n\n.. function:: void \\*cork_malloc(size_t size)\n              void \\*cork_calloc(size_t count, size_t size)\n              void \\*cork_realloc(void \\*ptr, size_t old_size, size_t new_size)\n              type \\*cork_new(TYPE type)\n\n   The first three functions mimic the standard ``malloc``, ``calloc``, and\n   ``realloc`` functions to allocate (or reallocate) some memory, with the added\n   guarantee that they will always return a valid newly allocated pointer.\n   ``cork_new`` is a convenience function for allocating an instance of a\n   particular type; it is exactly equivalent to::\n\n       cork_malloc(sizeof(type))\n\n   Note that with ``cork_realloc``, unlike the standard ``realloc`` function,\n   you must provide the old size of the memory region, in addition to the\n   requested new size.\n\n   Each allocation function has a corresponding deallocation function that you\n   must use to free the memory when you are done with it: use\n   :c:func:`cork_free` to free memory allocated using ``cork_malloc`` or\n   ``cork_realloc``; use :c:func:`cork_cfree` to free memory allocated using\n   ``cork_calloc``; and use :c:func:`cork_delete` to free memory allocated using\n   ``cork_new``.\n\n   .. note::\n\n      Note that the possible memory leak in the standard ``realloc``\n      function doesn't apply here, since we're going to abort the whole\n      program if the reallocation fails.\n\n\nRecoverable allocation\n----------------------\n\nThe functions in this section will return a ``NULL`` pointer if any memory\nallocation fails, allowing you to recover from the error condition, if possible.\n\n.. function:: void \\*cork_xmalloc(size_t size)\n              void \\*cork_xcalloc(size_t count, size_t size)\n              void \\*cork_xrealloc(void \\*ptr, size_t old_size, size_t new_size)\n              void \\*cork_xreallocf(void \\*ptr, size_t old_size, size_t new_size)\n              type \\*cork_xnew(TYPE type)\n\n   The first three functions mimic the standard ``malloc``, ``calloc``,\n   ``realloc`` functions.  ``cork_xreallocf`` mimics the common ``reallocf``\n   function from BSD.  These functions return ``NULL`` if the memory allocation\n   fails.  (Note that unlike the standard functions, they do **not** set\n   ``errno`` to ``ENOMEM``; the only indication you have of an error condition\n   is a ``NULL`` return value.)\n\n   Note that with ``cork_xrealloc`` and ``cork_xreallocf``, unlike the standard\n   ``realloc`` function, you must provide the old size of the memory region, in\n   addition to the requested new size.\n\n   ``cork_xreallocf`` is more safe than the standard ``realloc`` function.  A\n   common idiom when calling ``realloc`` is::\n\n       void  *ptr = /* from somewhere */;\n       /* UNSAFE!  Do not do this! */\n       ptr = realloc(ptr, new_size);\n\n   This is unsafe!  The ``realloc`` function returns a ``NULL`` pointer if the\n   reallocation fails.  By assigning directly into *ptr*, you'll get a memory\n   leak in these situations.  The ``cork_xreallocf`` function, on the other\n   hand, will automatically free the existing pointer if the reallocation fails,\n   eliminating the memory leak::\n\n       void  *ptr = /* from somewhere */;\n       /* This is safe.  Do this. */\n       ptr = cork_xreallocf(ptr, new_size);\n       /* Check whether ptr is NULL before using it! */\n\n   Each allocation function has a corresponding deallocation function that you\n   must use to free the memory when you are done with it: use\n   :c:func:`cork_free` to free memory allocated using ``cork_xmalloc``,\n   ``cork_xrealloc``, or ``cork_xreallocf``; use :c:func:`cork_cfree` to free\n   memory allocated using ``cork_xcalloc``; and use :c:func:`cork_delete` to\n   free memory allocated using ``cork_xnew``.\n\n\nDeallocation\n------------\n\nSince this is C, you must free any memory region once you're done with it.\nYou must use one of the functions from this section to free any memory that you\ncreated using any of the allocation functions described previously.\n\n.. function:: void cork_free(void \\*ptr, size_t size)\n              void cork_cfree(void \\*ptr, size_t count, size_t size)\n              void cork_delete(TYPE type, void \\*ptr)\n\n   Frees a region of memory allocated by one of libcork's allocation functions.\n\n   Note that unlike the standard ``free`` function, you must provide the size of\n   the allocated region when it's freed, as well as when it's created.  Most of\n   the time this isn't an issue, since you're either freeing a region whose size\n   is known at compile time, or you're already keeping track of the size of a\n   dynamically sized memory region for some other reason.\n\n   You should use ``cork_free`` to free memory allocated using\n   :c:func:`cork_malloc`, :c:func:`cork_realloc`, :c:func:`cork_xmalloc`,\n   :c:func:`cork_xrealloc`, or :c:func:`cork_xreallocf`.  You should use\n   ``cork_cfree`` to free memory allocated using :c:func:`cork_calloc` or\n   :c:func:`cork_xcalloc`.  You should use ``cork_delete`` to free memory\n   allocated using :c:func:`cork_new` or :c:func:`cork_xnew`.\n\n\nDuplicating strings\n-------------------\n\n.. function:: const char \\*cork_strdup(const char \\*str)\n              const char \\*cork_strndup(const char \\*str, size_t size)\n              const char \\*cork_xstrdup(const char \\*str)\n              const char \\*cork_xstrndup(const char \\*str, size_t size)\n\n   These functions mimic the standard ``strdup`` function.  They create a copy\n   of an existing C string, allocating exactly as much memory is needed to hold\n   the copy.\n\n   The ``strdup`` variants calculate the size of *str* using ``strlen``.  For\n   the ``strndup`` variants, *str* does not need to be ``NUL``-terminated, and\n   you must pass in its *size*.  (Note that is different than the standard\n   ``strndup``, where *str* must be ``NUL``-terminated, and which copies **at\n   most** *size* bytes.  Our version always copies **exactly** *size* bytes.)\n   The result is guaranteed to be ``NUL``-terminated, even if the source *str*\n   is not.\n\n   You shouldn't modify the contents of the copied string.  You must use\n   :c:func:`cork_strfree()` to free the string when you're done with it.  The\n   ``x`` variant returns a ``NULL`` pointer if the allocation fails; the non-\\\n   ``x`` variant is guaranteed to return a valid pointer to a copied string.\n\n.. function:: void cork_strfree(const char \\*str)\n\n   Frees *str*, which must have been created using\n   :c:func:`cork_strdup()` or :c:func:`cork_xstrdup()`.\n\n\n.. _libcork-allocators:\n\nCustomizing how libcork allocates\n=================================\n\nThe ``cork_alloc`` type encapsulates a particular memory allocation scheme.  To\ncustomize how libcork allocates memory, you create a new instance of this type,\nand then use :c:func:`cork_set_allocator` to register it with libcork.\n\n.. function:: void cork_set_allocator(const struct cork_alloc \\*alloc)\n\n   Override which :ref:`allocator instance <allocators>` libcork will use to\n   create and free memory.  We will take control of *alloc*; you must not free\n   it yourself after passing it to this function.\n\n   You can only call this function at most once.  This function is **not**\n   thread-safe; it's only safe to call before you've called **any** other\n   libcork function (or any function from any other library that uses libcork.\n   (The only exceptions are libcork functions that take in a\n   :c:type:`cork_alloc` parameter or return a :c:type:`cork_alloc` result; these\n   functions are safe to call before calling ``cork_set_allocator``.)\n\n.. var:: const struct cork_alloc \\*cork_allocator\n\n   The current :ref:`allocator instance <allocators>` that libcork will use to\n   create and free memory.\n\n\n.. _allocators:\n\nWriting a custom allocator\n--------------------------\n\n.. type:: struct cork_alloc\n\n   The ``cork_alloc`` type contains several methods for performing different\n   allocation and deallocation operations.\n\n   You are only required to provide implementations of ``xmalloc`` and ``free``;\n   we can provide default implementations of all of the other methods in terms\n   of those two.  You can provide optimized versions of the other methods, if\n   appropriate.\n\n\n.. function:: struct cork_alloc \\*cork_alloc_new_alloc(const struct cork_alloc \\*parent)\n\n   ``cork_alloc_new`` creates a new allocator instance.  The new instance will\n   itself be allocated using *parent*.  You must provide implementations of at\n   least the ``xmalloc`` and ``free`` methods.  You can also override our\n   default implementations of any of the other methods.\n\n   This function is **not** thread-safe; it's only safe to call before you've\n   called **any** other libcork function (or any function from any other library\n   that uses libcork.  (The only exceptions are libcork functions that take in a\n   :c:type:`cork_alloc` parameter or return a :c:type:`cork_alloc` result; these\n   functions are safe to call before calling ``cork_set_allocator``.)\n\n   The new allocator instance will automatically be freed when the process\n   exits.  If you registered a *user_data* pointer for your allocation methods\n   (via :c:func:`cork_alloc_set_user_data`), it will be freed using the\n   *free_user_data* method you provided.  If you create more than one\n   ``cork_alloc`` instance in the process, they will be freed in the reverse\n   order that they were created.\n\n   .. note::\n\n      In your allocator implementation, you cannot assume that the rest of the\n      libcork allocation framework has been set up yet.  So if your allocator\n      needs to allocate, you must not use the usual :c:func:`cork_malloc` family\n      of functions; instead you should use the ``cork_alloc_malloc`` variants to\n      explicitly allocate memory using your new allocator's *parent*.\n\n\n.. function:: void cork_alloc_set_user_data(struct cork_alloc \\*alloc, void \\*user_data, cork_free_f free_user_data)\n\n   Provide a *user_data* pointer, which will be passed unmodified to each\n   allocation method that you register.  You can also provide an optional\n   *free_user_data* method, which we will use to free the *user_data* instance\n   when the allocator itself is freed.\n\n\n.. function:: void cork_alloc_set_calloc(struct cork_alloc \\*alloc, cork_alloc_calloc_f calloc)\n              void cork_alloc_set_xcalloc(struct cork_alloc \\*alloc, cork_alloc_calloc_f calloc)\n\n   .. type:: void \\*(\\*cork_alloc_calloc_f)(const struct cork_alloc \\*alloc, size_t count, size_t size)\n\n      These methods are used to implement the :c:func:`cork_calloc` and\n      :c:func:`cork_xcalloc` functions.  Your must allocate and return ``count *\n      size`` bytes of memory.  You must ensure that every byte in this region is\n      initialized to ``0``.  The ``calloc`` variant must always return a valid\n      pointer; if memory allocation fails, it must not return.  The ``xcalloc``\n      variant should return ``NULL`` if allocation fails.\n\n\n.. function:: void cork_alloc_set_malloc(struct cork_alloc \\*alloc, cork_alloc_malloc_f malloc)\n              void cork_alloc_set_xmalloc(struct cork_alloc \\*alloc, cork_alloc_malloc_f malloc)\n\n   .. type:: void \\*(\\*cork_alloc_malloc_f)(const struct cork_alloc \\*alloc, size_t size)\n\n      These methods are used to implement the :c:func:`cork_malloc` and\n      :c:func:`cork_xmalloc` functions.  You must allocate and return *size*\n      bytes of memory.  The ``malloc`` variant must always return a valid\n      pointer; if memory allocation fails, it must not return.  The ``xmalloc``\n      variant should return ``NULL`` if allocation fails.\n\n\n.. function:: void cork_alloc_set_realloc(struct cork_alloc \\*alloc, cork_alloc_realloc_f realloc)\n              void cork_alloc_set_xrealloc(struct cork_alloc \\*alloc, cork_alloc_realloc_f realloc)\n\n   .. type:: void \\*(\\*cork_alloc_realloc_f)(const struct cork_alloc \\*alloc, void \\*ptr, size_t old_size, size_t new_size)\n\n      These methods are used to implement the :c:func:`cork_realloc`,\n      :c:func:`cork_xrealloc`, and :c:func:`cork_xreallocf` functions.  You\n      must reallocate *ptr* to contain *new_size* bytes of memory and return the\n      reallocated pointer.  *old_size* will be the previously allocated size of\n      *ptr*.  The ``realloc`` variant must always return a valid pointer; if\n      memory reallocation fails, it must not return.  The ``xrealloc`` variant\n      should return ``NULL`` if reallocation fails.\n\n\n.. function:: void cork_alloc_set_free(struct cork_alloc \\*alloc, cork_alloc_free_f free)\n\n   .. type:: void \\*(\\*cork_alloc_free_f)(const struct cork_alloc \\*alloc, void \\*ptr, size_t size)\n\n      These methods are used to implement the :c:func:`cork_free`,\n      :c:func:`cork_cfree`, and :c:func:`cork_delete` functions.  You must\n      deallocate *ptr*.  *size* will be the allocated size of *ptr*.\n"
  },
  {
    "path": "docs/old/array.rst",
    "content": ".. _array:\n\n****************\nResizable arrays\n****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines a resizable array class, similar to C++'s\n``std::vector`` or Java's ``ArrayList`` classes.  Our arrays can store\nany fixed-size element.  The arrays automatically resize themselves as\nnecessary to store the elements that you add.\n\n\n.. type:: cork_array(element_type)\n\n   A resizable array that contains elements of type *element_type*.\n\n.. function:: void cork_array_init(cork_array(T) \\*array)\n\n   Initializes a new array.  You should allocate *array* yourself,\n   presumably on the stack or directly within some other data type.  The\n   array will start empty.\n\n.. function:: void cork_array_done(cork_array(T) \\*array)\n\n   Finalizes an array, freeing any storage that was allocated to hold\n   the arrays elements.\n\n.. function:: size_t cork_array_size(cork_array(T) \\*array)\n\n   Returns the number of elements in *array*.\n\n.. function:: bool cork_array_is_empty(cork_array(T) \\*array)\n\n   Returns whether *array* has any elements.\n\n.. function:: void cork_array_void(cork_array(T) \\*array)\n\n   Removes all elements from *array*.\n\n.. function:: T* cork_array_elements(cork_array(T) \\*array)\n\n   Returns a pointer to the underlying array of elements in *array*.  The\n   elements are guaranteed to be contiguous, just like in a normal C array, but\n   the particular pointer that is returned in **not** guaranteed to be\n   consistent across function calls that modify the contents of the array.\n\n.. function:: T cork_array_at(cork_array(T) \\*array, size_t index)\n\n   Returns the element in *array* at the given *index*.  Like accessing\n   a normal C array, we don't do any bounds checking.  The result is a\n   valid lvalue, so it can be directly assigned to::\n\n     cork_array(int64_t)  array;\n     cork_array_append(array, 5, err);\n     cork_array_at(array, 0) = 12;\n\n.. function:: void cork_array_append(cork_array(T) \\*array, T element)\n\n   Appends *element* to the end of *array*, reallocating the array's\n   storage if necessary.  If you have an ``init`` or ``reset`` callback for\n   *array*, it will be used to initialize the space that was allocated for the\n   new element, and then *element* will be directly copied into that space\n   (using ``memcpy`` or an equivalent).  If that is not the right copy behavior\n   for the elements of *array*, then you should use\n   :c:func:`cork_array_append_get` instead, and fill in the allocated element\n   directly.\n\n.. function:: T \\*cork_array_append_get(cork_array(T) \\*array)\n\n   Appends a new element to the end of *array*, reallocating the array's storage\n   if necessary, returning a pointer to the new element.\n\n.. function:: int cork_array_ensure_size(cork_array(T) \\*array, size_t desired_count)\n\n   Ensures that *array* has enough allocated space to store *desired_count*\n   elements, reallocating the array's storage if needed.  The actual size and\n   existing contents of the array aren't changed.\n\n.. function:: int cork_array_copy(cork_array(T) \\*dest, cork_array(T) \\*src, cork_copy_f \\*copy, void \\*user_data)\n\n   Copy elements from *src* to *dest*.  If you provide a *copy* function, it\n   will be called on each element to perform the copy.  If not, we'll use\n   ``memcpy`` to bulk-copy the elements.\n\n   If you've provided :ref:`callbacks <array-callbacks>` for *dest*, then those\n   callbacks will be called appropriately.  We'll call the ``remove`` callback\n   for any existing entries (will be overwritten by the copy).  We'll call\n   ``init`` or ``reuse`` on each element entry before it's copied.\n\n   .. type:: typedef int (\\*cork_copy_f)(void \\*user_data, void \\*dest, const void \\*src)\n\n.. function:: size_t cork_array_element_size(cork_array(T) \\*array)\n\n   Returns the size of the elements that are stored in *array*.  You\n   won't normally need to call this, since you can just use\n   ``sizeof(T)``.\n\n\n.. _array-callbacks:\n\nInitializing and finalizing elements\n------------------------------------\n\nYou can provide callback functions that will be used to automatically initialize\nand finalize the elements of a resizable array.\n\n\n.. function:: void cork_array_set_init(cork_array(T) \\*array, cork_init_f init)\n              void cork_array_set_done(cork_array(T) \\*array, cork_done_f done)\n              void cork_array_set_reuse(cork_array(T) \\*array, cork_init_f reuse)\n              void cork_array_set_remove(cork_array(T) \\*array, cork_done_f remove)\n              void cork_array_set_callback_data(cork_array(T) \\*array, void \\*user_data, cork_free_f free_user_data)\n\n   Set one of the callback functions for *array*.  There are two pairs of\n   callbacks: ``init`` and ``done``, and ``reuse`` and ``remove``.  Within each\n   pair, one callback is used to initialize an element of the array, while the\n   other is used to finalize it.\n\n   The ``init`` callback is used to initialize an element when its array entry\n   is used for the first time.  If you then shrink the array (via\n   :c:func:`cork_array_clear`, for instance), and then append elements again,\n   you will reuse array entries; in this case, the ``reset`` callback is used\n   instead.  (Having separate ``init`` and ``reuse`` callbacks can be useful\n   when the elements are complex objects with deep memory requirements.  If you\n   use the ``init`` callback to allocate that memory, and use the ``reset``\n   callback to \"clear\" it, then you can reduce some of the memory allocation\n   overhead.)\n\n   Similarly, the ``remove`` callback is used when an element is removed from\n   the array, but the space that the element used isn't being reclaimed yet.\n   The ``done`` callback, on the other hand, is used when the array entry is\n   reclaimed and freed.\n\n   All of the callbacks take in an additional *user_data* parameter, in addition\n   to the array entries themselves.  You provide that parameter by calling the\n   :c:func:`cork_array_set_callback_data` function.  If you pass in a\n   *free_user_data* function, then we will use that function to free the\n   *user_data* when the array itself is finalized.\n\n   .. type:: typedef void (\\*cork_init_f)(void \\*user_data, void \\*value)\n             typedef void (\\*cork_done_f)(void \\*user_data, void \\*value)\n             typedef void (\\*cork_free_f)(void \\*value)\n"
  },
  {
    "path": "docs/old/attributes.rst",
    "content": ".. _attributes:\n\n*******************\nCompiler attributes\n*******************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThe macros in this section define compiler-agnostic versions of several\ncommon compiler attributes.\n\n\n.. function:: CORK_LIKELY(expression)\n              CORK_UNLIKELY(expression)\n\n   Indicate that the given Boolean *expression* is likely to be ``true``\n   or ``false``, respectively.  The compiler can sometimes use this\n   information to generate more efficient code.\n\n\n.. macro:: CORK_ATTR_CONST\n\n   Declare a “constant” function.  The return value of a constant\n   function can only depend on its parameters.  This is slightly more\n   strict than a “pure” function (declared by\n   :c:macro:`CORK_ATTR_PURE`); a constant function is not allowed to\n   read from global variables, whereas a pure function is.\n\n   .. note:: Note that the compiler won't verify that your function\n      meets the requirements of a constant function.  Instead, this\n      attribute notifies the compiler of your intentions, which allows\n      the compiler to assume more about your function when optimizing\n      code that calls it.\n\n   ::\n\n     int square(int x) CORK_ATTR_CONST;\n\n\n.. macro:: CORK_ATTR_MALLOC\n\n   Declare a function that returns a newly allocated pointer.  The\n   compiler can use this information to generate more accurate aliasing\n   information, since it can infer that the result of the function\n   cannot alias any other existing pointer.\n\n   ::\n\n     void *custom_malloc(size_t size) CORK_ATTR_MALLOC;\n\n\n.. macro:: CORK_ATTR_NOINLINE\n\n   Declare that a function shouldn't be eligible for inlining.\n\n\n.. macro:: CORK_ATTR_PRINTF(format_index, args_index)\n\n   Declare a function that takes in ``printf``\\ -like parameters.\n   *format_index* is the index (starting from 1) of the parameter that\n   contains the ``printf`` format string.  *args_index* is the index of\n   the first parameter that contains the data to format.\n\n\n.. macro:: CORK_ATTR_PURE\n\n   Declare a “pure” function.  The return value of a pure function can\n   only depend on its parameters, and on global variables.\n\n   ::\n\n     static int  _next_id;\n     int get_next_id(void) CORK_ATTR_PURE;\n\n\n.. macro:: CORK_ATTR_SENTINEL\n\n   Declare a var-arg function whose last parameter must be a ``NULL``\n   sentinel value.  When the compiler supports this attribute, it will\n   check the actual parameters whenever this function is called, and\n   ensure that the last parameter is a ``NULL``.\n\n\n.. macro:: CORK_ATTR_UNUSED\n\n   Declare a entity that might not be used.  This lets you keep\n   ``-Wall`` activated in several cases where you're obligated to define\n   something that you don't intend to use.\n\n   ::\n\n     CORK_ATTR_UNUSED static void\n     unused_function(void)\n     {\n         CORK_ATTR_UNUSED int  unused_value;\n     }\n\n\n.. macro:: CORK_INITIALIZER(func_name)\n           CORK_FINALIZER(func_name)\n\n   Declare a ``static`` function that will be automatically called at program\n   startup (for ``CORK_INITIALIZER``) or shutdown (for ``CORK_FINALIZER``).  If\n   there are multiple initializer functions linked into a program, there is no\n   guarantee about the order in which the functions will be called.\n\n   ::\n\n     #include <libcork/core.h>\n     #include <libcork/ds.h>\n\n     static cork_array(int)  array;\n\n     CORK_INITIALIZER(init_array)\n     {\n        cork_array_init(&array);\n     }\n\n     CORK_FINALIZER(done_array)\n     {\n        cork_array_done(&array);\n     }\n"
  },
  {
    "path": "docs/old/basic-types.rst",
    "content": ".. _basic-types:\n\n***********\nBasic types\n***********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThe types in this section ensure that the C99 integer types are\navailable, regardless of platform.  We also define some preprocessor\nmacros that give the size of the non-fixed-size standard types.  In\naddition, libcork defines some useful low-level types:\n\n.. toctree::\n   :maxdepth: 1\n\n   int128\n   net-addresses\n   timestamps\n   hash-values\n   unique-ids\n\nIntegral types\n==============\n\n.. type:: bool\n\n   A boolean.  Where possible, we simply include ``<stdbool.h>`` to get\n   this type.  It might be ``typedef``\\ ed to ``int``\\ .  We also make\n   sure that the following constants are defined:\n\n   .. var:: bool false\n            bool true\n\n.. type:: int8_t\n          uint8_t\n          int16_t\n          uint16_t\n          int32_t\n          uint32_t\n          int64_t\n          uint64_t\n\n   Signed and unsigned, fixed-size integral types.\n\n.. type:: intptr_t\n          uintptr_t\n\n   Signed and unsigned integers that are guaranteed to be big enough to\n   hold a type-cast ``void *``\\ .\n\n.. type:: size_t\n\n   An unsigned integer big enough to hold the size of a memory object,\n   or a maximal array index.\n\n.. type:: ptrdiff_t\n\n   A signed integer big enough to hold the difference between two\n   pointers.\n\nSize macros\n===========\n\n.. macro:: CORK_SIZEOF_SHORT\n           CORK_SIZEOF_INT\n           CORK_SIZEOF_LONG\n           CORK_SIZEOF_POINTER\n\n   The size (in bytes) of the ``short``, ``int``, ``long``, and ``void\n   *`` types, respectively.\n\n\n.. _embedded-struct:\n\nEmbedded ``struct``\\ s\n======================\n\nQuite often a callback function or API will take in a pointer to a\nparticular ``struct``, with the expectation that you can embed that\n``struct`` into some other type for extension purposes.  Kind of a\nbastardized subclassing mechanism for C code.  The doubly-linked list\nmodule is a perfect example; you're meant to embed\n:c:type:`cork_dllist_item` within the linked list element type.  You can\nuse the following macro to obtain the pointer to the containing\n(“subclass”) ``struct``, when given a pointer to the contained\n(“superclass”) ``struct``:\n\n.. function:: struct_type \\*cork_container_of(field_type \\*field, TYPE struct_type, FIELD field_name)\n\n   The *struct_type* parameter must be the name of a ``struct`` type,\n   *field_name* must be the name of some field within that\n   ``struct``, and *field* must be a pointer to an instance of that\n   field.  The macro returns a pointer to the containing ``struct``.\n   So, given the following definitions::\n\n     struct superclass {\n         int  a;\n     };\n\n     struct subclass {\n         int  b;\n         struct superclass  parent;\n     };\n\n     struct subclass  instance;\n\n   then the following identity holds::\n\n     cork_container_of(&instance.parent, struct subclass, parent) == &instance\n\n   .. note:: When the superclass ``struct`` appears as the first element\n      of the subclass ``struct``, you can obtain the same effect using a\n      simple type-cast.  However, the ``cork_container_of`` macro is\n      more robust, since it also works when the superclass ``struct``\n      appears later on in the subclass ``struct``.\n"
  },
  {
    "path": "docs/old/bitset.rst",
    "content": ".. _bits:\n\n********\nBit sets\n********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis sections defines a type for storing an array of bits.  This data structure\nis most often used to implement a set of integers.  It is particularly good when\nyou expect your sets to be *dense*.  You should not use a bitset if the number\nof possibly elements is outrageously large, however, since that would cause your\nbitset to exhaust the available memory.\n\n.. type:: struct cork_bitset\n\n   An array of bits.  You should not allocate any instances of this type\n   yourself; use :c:func:`cork_bitset_new` instead.\n\n   .. member:: size_t bit_count\n\n      The number of bits that are included in this array.  (Each bit can be on\n      or off; this does not give you the number of bits that are *on*, it gives\n      you the number of bits in total, on or off.)\n\n\n.. function:: void cork_bitset_init(struct cork_bitset \\*set)\n\n   Initialize a new bitset instance that you've allocated yourself\n   (usually on the stack).  All bits will be initialized to ``0``.\n\n.. function:: struct cork_bitset \\*cork_bitset_new(size_t bit_count)\n\n   Create a new bitset with enough space to store the given number of bits.\n   All bits will be initialized to ``0``.\n\n.. function:: void cork_bitset_done(struct cork_bitset \\*set)\n\n   Finalize a bitset, freeing any set content that it contains.  This\n   function should only be used for bitsets that you allocated yourself,\n   and initialized using :c:func:`cork_bitset_init()`.  You must **not** use\n   this function to free a bitset allocated using :c:func:`cork_bitset_new()`.\n\n.. function:: void cork_bitset_free(struct cork_bitset \\*set)\n\n   Finalize and deallocate a bitset, freeing any set content that it\n   contains.  This function should only be used for bitsets allocated\n   using :c:func:`cork_bitset_new()`.  You must **not** use this\n   function to free a bitset initialized using :c:func:`cork_bitset_init()`.\n\n.. function:: bool cork_bitset_get(struct cork_bitset \\*set, size_t index)\n\n   Return whether the given bit is on or off in *set*.  It is your\n   responsibility to ensure that *index* is within the valid range for *set*.\n\n.. function:: void cork_bitset_set(struct cork_bitset \\*set, size_t index, bool value)\n\n   Turn the given bit on or off in *set*.  It is your responsibility to ensure\n   that *index* is within the valid range for *set*.\n\n.. function:: void cork_bitset_clear(struct cork_bitset \\*set)\n\n   Turn off of the bits in *set*.\n"
  },
  {
    "path": "docs/old/buffer.rst",
    "content": ".. _buffer:\n\n************************\nResizable binary buffers\n************************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines a resizable binary buffer type.  This class can\nalso be used to construct C strings, when you don't know the size of\nthe string in advance.\n\nThis class is not reference counted; we assume that there's a single\nowner of the buffer.  The contents of a :c:type:`cork_buffer` are fully\nmutable.  If you want to turn the buffer into something that's safe to\npass between threads, you can use the :c:func:`cork_buffer_to_slice()`\nor :c:func:`cork_buffer_to_managed_buffer()` functions to create an\nimmutable managed wrapper around the buffer.\n\nYou can read the contents of the buffer by accessing the :c:member:`buf\n<cork_buffer.buf>` and :c:member:`size <cork_buffer.size>` fields\ndirectly.  However, to modify the contents of a buffer, you should use\nthe mutator functions described below, since they take care of\nautomatically resizing the underlying buffer when necessary.\n\n.. note::\n\n   This class always creates its own copy of any data added to the\n   buffer; there aren't any methods for wrapping existing buffers\n   without copying.  If you want to do that, you should use\n   :ref:`managed-buffer` or :ref:`slice`.\n\n\n.. type:: struct cork_buffer\n\n   A resizable binary buffer.\n\n   .. member:: void \\*buf\n\n      The current contents of the buffer.\n\n   .. member:: size_t  size\n\n      The current size of the buffer.\n\n\n.. function:: void cork_buffer_init(struct cork_buffer \\*buffer)\n              struct cork_buffer CORK_BUFFER_INIT()\n\n   Initialize a new buffer instance that you've allocated yourself\n   (usually on the stack).  The ``CORK_BUFFER_INIT`` version can only be\n   used as a static initializer.\n\n   The preallocated ``cork_buffer`` instance that you provide doesn't\n   include space for the content of the buffer; this will be allocated\n   automatically as content is added.\n\n.. function:: struct cork_buffer \\*cork_buffer_new(void)\n\n   Allocate and initialize a new buffer instance.\n\n.. function:: void cork_buffer_done(struct cork_buffer \\*buffer)\n\n   Finalize a buffer, freeing any content that it contains.  This\n   function should only be used for buffers that you allocated yourself,\n   and initialized using :c:func:`cork_buffer_init()` or\n   :c:func:`CORK_BUFFER_INIT()`.  You must **not** use this function to\n   free a buffer allocated using :c:func:`cork_buffer_new()`.\n\n.. function:: void cork_buffer_free(struct cork_buffer \\*buffer)\n\n   Finalize and deallocate a buffer, freeing any content that it\n   contains.  This function should only be used for buffers allocated\n   using :c:func:`cork_buffer_new()`.  You must **not** use this\n   function to free a buffer initialized using\n   :c:func:`cork_buffer_init()` or :c:func:`CORK_BUFFER_INIT()`.\n\n.. function:: bool cork_buffer_equal(const struct cork_buffer \\*buffer1, const struct cork_buffer \\*buffer2)\n\n   Compare two buffers for equality.\n\n.. function:: void cork_buffer_ensure_size(struct cork_buffer \\*buffer, size_t desired_size)\n\n   Ensure that a buffer has allocated enough space to store at least\n   *desired_size* bytes.  We won't shrink the size of the buffer's\n   internal storage; if the buffer has already allocated at least\n   *desired_size* bytes, the function acts as a no-op.\n\n.. function:: uint8_t cork_buffer_byte(struct cork_buffer \\*buffer, size_t index)\n              char cork_buffer_char(struct cork_buffer \\*buffer, size_t index)\n\n   Return the byte or character at the given index in *buffer*.\n\n\nMutator functions\n-----------------\n\nMost of the mutator functions defined in this section come in two\nvariants: a ``_set`` function, which clears the buffer before adding new\ncontent, and an ``_append`` function, which retains the old content,\nadding the new content to the end of the buffer.\n\nEach mutator function will automatically append an extra ``NUL`` byte to\nthe end of whatever content is placed into the buffer.  However, this\n``NUL`` byte will **not** be included in the :c:member:`size\n<cork_buffer.size>` of the buffer.  This ensures that the contents of\nany ``cork_buffer`` can be used as a ``NUL``\\ -terminated C string\n(assuming that there aren't any internal ``NUL``\\ s), even if the buffer\nis constructed from a data source that doesn't include ``NUL``\nterminators.\n\n.. function:: void cork_buffer_clear(struct cork_buffer \\*buffer)\n\n   Clear a buffer.  This does not free any storage that the buffer has\n   allocated; this storage will be reused if you add contents back to the\n   buffer.\n\n.. function:: void cork_buffer_truncate(struct cork_buffer \\*buffer, size_t length)\n\n   Truncate a buffer so that contains no more than *length* bytes.  If the\n   buffer is already shorter than this, it is not modified.\n\n.. function:: void cork_buffer_copy(struct cork_buffer \\*dest, const struct cork_buffer \\*src)\n              void cork_buffer_append_copy(struct cork_buffer \\*dest, const struct cork_buffer \\*src)\n\n   Copy the contents of the *src* buffer into *dest*.  The ``_set`` variant\n   clears the buffer first, while the ``_append`` variant adds *src* to whatever\n   content is already there.\n\n.. function:: void cork_buffer_set(struct cork_buffer \\*buffer, const void \\*src, size_t length)\n              void cork_buffer_append(struct cork_buffer \\*buffer, const void \\*src, size_t length)\n\n   Copy the contents of *src* into a buffer.  The ``_set`` variant\n   clears the buffer first, while the ``_append`` variant adds *src* to\n   whatever content is already there.\n\n.. function:: void cork_buffer_set_string(struct cork_buffer \\*buffer, const char \\*str)\n              void cork_buffer_append_string(struct cork_buffer \\*buffer, const char \\*str)\n              void cork_buffer_set_literal(struct cork_buffer \\*buffer, const char \\*str)\n              void cork_buffer_append_literal(struct cork_buffer \\*buffer, const char \\*str)\n\n   Copy the contents of *str* (which must be a ``NUL``\\ -terminated C\n   string) into a buffer.  The ``_set`` variants clears the buffer first,\n   while the ``_append`` variants adds *str* to whatever content is\n   already there.  The ``_literal`` variants only work when *str* is a C string\n   literal; we use the ``sizeof`` operator to determine the length of the string\n   at compile time.  The ``_string`` variants work with any C string; we use the\n   builtin ``strlen`` function to determine the length of the string.\n\n.. function:: void cork_buffer_printf(struct cork_buffer \\*buffer, const char \\*format, ...)\n              void cork_buffer_vprintf(struct cork_buffer \\*buffer, const char \\*format, va_list args)\n              void cork_buffer_append_printf(struct cork_buffer \\*buffer, const char \\*format, ...)\n              void cork_buffer_append_vprintf(struct cork_buffer \\*buffer, const char \\*format, va_list args)\n\n   Format data according to a ``printf`` format string, placing the\n   result into a buffer.  The ``_append`` variants add the formatted\n   string to whatever content is already in the buffer; the non-\\\n   ``_append`` variants clear the buffer first.  The ``_printf``\n   variants are vararg functions, and take in the format string's data\n   as direct parameters.  The ``_vprintf`` variants can be used within\n   another vararg function, and let you pass in the format string's data\n   as a C99-standard ``va_list`` instance.\n\n\nPretty-printing\n---------------\n\nWe also provide several helper functions for adding pretty-printed content to a\n``cork_buffer``.\n\n.. function:: void cork_buffer_append_indent(struct cork_buffer \\*buffer, size_t indent)\n\n   Append *indent* spaces to *buffer*.\n\n.. function:: void cork_buffer_append_c_string(struct cork_buffer \\*buffer, const char \\*str, size_t length)\n\n   Append the C string literal representation of *str* to *buffer*.  This will\n   include opening and closing double quotes, and any non-printable characters\n   will be escaped.  (We will use the standard letter-based escapes where\n   possible, and fall back on ``\"\\xXX\"`` hexadecimal escapes for other\n   non-printable characters.)  The result is guaranteed to stay on a single\n   line, since any embedded newlines will be converted to a ``\\n`` escape\n   sequence.\n\n.. function:: void cork_buffer_append_hex_dump(struct cork_buffer \\*buffer, size_t indent, const char \\*str, size_t length)\n              void cork_buffer_append_multiline(struct cork_buffer \\*buffer, size_t indent, const char \\*str, size_t length)\n              void cork_buffer_append_binary(struct cork_buffer \\*buffer, size_t indent, const char \\*str, size_t length)\n\n   Append a pretty-printed representation of *str* to *buffer*.  All of these\n   functions can produce multiple lines of output.  All lines except for the\n   first will be prefaced with *indent* space characters.  The final line will\n   **not** have a trailing newline.\n\n   The ``hex_dump`` variant will output a hex-dump representation of *str*.\n   This will include the hexadecimal representation of each byte, and the actual\n   character of any printable byte.\n\n   The ``multiline`` variant appends the raw content of *str* to the buffer,\n   without making any attempt to sanitize non-printable characters.  (That means\n   you should only call this variant if you know that *str* contains only\n   printable characters.)  If *str* itself spans multiple lines, then we'll\n   insert indentation to make sure that we satisfy the indentation rules\n   described above.\n\n   The ``binary`` variant autodetects how to best render *str*.  If it contains\n   any non-printable characters, then we'll use the ``hex_dump`` representation.\n   If it spans multiple lines, we'll use the ``multiline`` representation.\n   Otherwise, we'll append the content directly without any modification.\n\n\nOther binary data structures\n----------------------------\n\nThe ``cork_buffer`` class is the only binary data class that is mutable;\nthis comes at the cost of only being usable by a single owner thread or\nfunction at a time.  Once you have constructed a binary string or\npayload using a ``cork_buffer``, you can use the functions in this\nsection to produce a corresponding instance of one of libcork's\nsharable, immutable binary data types.\n\n.. function:: struct cork_managed_buffer \\*cork_buffer_to_managed_buffer(struct cork_buffer \\*buffer)\n\n   Create a new :ref:`managed buffer <managed-buffer>` to manage the\n   contents of a ``cork_buffer`` instance.  *buffer* must have been\n   allocated on the heap (i.e., using :c:func:`cork_buffer_new()`, and\n   not :c:func:`cork_buffer_init()`).  We take ownership of *buffer*,\n   regardless of whether we're able to successfully create a new\n   :c:type:`cork_managed_buffer` instance.  You must **not** try to free\n   *buffer* yourself.\n\n.. function:: int cork_buffer_to_slice(struct cork_buffer \\*buffer, struct cork_slice \\*slice)\n\n   Initialize a new :ref:`slice <slice>` to manage the contents of\n   *buffer*.  *buffer* must have been allocated on the heap (i.e., using\n   :c:func:`cork_buffer_new()`, and not :c:func:`cork_buffer_init()`).\n   We take ownership of *buffer*, regardless of whether we're able to\n   successfully create a new :c:type:`cork_managed_buffer` instance.\n   You must **not** try to free *buffer* yourself.\n\n   The slice will point into the contents of a new :ref:`managed buffer\n   <managed-buffer>` instance.  The managed buffer isn't returned\n   directly, though you can create additional slices into it using the\n   usual :c:type:`cork_slice` methods.\n\n   Regardless of whether we can initialize the slice successfully, you\n   **must** call :c:func:`cork_slice_finish()` on *slice* when you're\n   done with the slice.\n\n.. function:: struct cork_stream_consumer \\*cork_buffer_to_stream_consumer(struct cork_buffer \\*buffer)\n\n   Create a new stream consumer that appends any received data into\n   *buffer*.\n\n   We do **not** take control of *buffer*.  You retain responsibility\n   for freeing the buffer, and you must ensure that it remains allocated\n   and valid for the entire lifetime of the stream consumer that we\n   return.\n"
  },
  {
    "path": "docs/old/byte-order.rst",
    "content": ".. _byte-order:\n\n**********\nByte order\n**********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThis section contains definitions for determining the endianness of the\nhost system, and for byte-swapping integer values of various sizes.\n\n\nEndianness detection\n====================\n\n.. macro:: CORK_LITTLE_ENDIAN\n           CORK_BIG_ENDIAN\n           CORK_HOST_ENDIANNESS\n           CORK_OTHER_ENDIANNESS\n\n   The ``CORK_HOST_ENDIANNESS`` macro can be used to determine the\n   endianness of the host system.  It will be equal to either\n   ``CORK_LITTLE_ENDIAN`` or ``CORK_BIG_ENDIAN``.  (The actual values\n   don't matter; you should always compare against the predefined\n   constants.)  The ``CORK_OTHER_endianness`` macro is defined to be the\n   opposite endianness as ``CORK_HOST_ENDIANNESS``.  A common use case\n   would be something like::\n\n     #if CORK_HOST_endianness == CORK_LITTLE_ENDIAN\n     /* do something to little-endian values */\n     #else\n     /* do something to big-endian values */\n     #endif\n\n.. macro:: CORK_HOST_ENDIANNESS_NAME\n           CORK_OTHER_ENDIANNESS_NAME\n\n   These macros give you a human-readable name of the host's endianness.\n   You can use this in debugging messages.\n\n   .. note:: You should *not* use these macros to detect the\n      endianness of the system, since we might change their definitions\n      at some point to support localization.  For that,\n      use :macro:`CORK_LITTLE_ENDIAN` and :macro:`CORK_BIG_ENDIAN`.\n\n\nByte swapping\n=============\n\nSwapping arbitrary expressions\n------------------------------\n\nAll of the macros in this section take in an rvalue (i.e., any arbitrary\nexpression) as a parameter.  The result of the swap is returned as the\nvalue of the macro.\n\n.. function:: uint16_t CORK_SWAP_UINT16(uint16_t value)\n              uint32_t CORK_SWAP_UINT32(uint32_t value)\n              uint64_t CORK_SWAP_UINT64(uint64_t value)\n              cork_u128 CORK_SWAP_UINT128(cork_128 value)\n\n   These functions always perform a byte-swap, regardless of the\n   endianness of the host system.\n\n.. function:: uint16_t CORK_UINT16_BIG_TO_HOST(uint16_t value)\n              uint32_t CORK_UINT32_BIG_TO_HOST(uint32_t value)\n              uint64_t CORK_UINT64_BIG_TO_HOST(uint64_t value)\n              cork_u128 CORK_UINT128_BIG_TO_HOST(cork_u128 value)\n\n   These functions convert a big-endian (or network-endian) value into\n   host endianness.  (I.e., they only perform a swap if the current host\n   is little-endian.)\n\n.. function:: uint16_t CORK_UINT16_HOST_TO_BIG(uint16_t value)\n              uint32_t CORK_UINT32_HOST_TO_BIG(uint32_t value)\n              uint64_t CORK_UINT64_HOST_TO_BIG(uint64_t value)\n              cork_u128 CORK_UINT128_HOST_TO_BIG(cork_u128 value)\n\n   These functions convert a host-endian value into big (or network)\n   endianness.  (I.e., they only perform a swap if the current host is\n   little-endian.)\n\n.. function:: uint16_t CORK_UINT16_LITTLE_TO_HOST(uint16_t value)\n              uint32_t CORK_UINT32_LITTLE_TO_HOST(uint32_t value)\n              uint64_t CORK_UINT64_LITTLE_TO_HOST(uint64_t value)\n              cork_u128 CORK_UINT128_LITTLE_TO_HOST(cork_u128 value)\n\n   These functions convert a little-endian value into host endianness.\n   (I.e., they only perform a swap if the current host is big-endian.)\n\n.. function:: uint16_t CORK_UINT16_HOST_TO_LITTLE(uint16_t value)\n              uint32_t CORK_UINT32_HOST_TO_LITTLE(uint32_t value)\n              uint64_t CORK_UINT64_HOST_TO_LITTLE(uint64_t value)\n              cork_u128 CORK_UINT128_HOST_TO_LITTLE(cork_u128 value)\n\n   These functions convert a host-endian value into little endianness.\n   (I.e., they only perform a swap if the current host is big-endian.)\n\nSwapping values in place\n------------------------\n\nThe macros in this section swap an integer *in place*, which means that\nthe original value is overwritten with the result of the swap.  To\nsupport this, you must pass in an *lvalue* as the parameter to the\nmacro.  (Note that you don't pass in a *pointer* to the original value;\nthese operations are implemented as macros, and you just need to provide\na reference to the variable to be swapped.)\n\n.. function:: void CORK_SWAP_UINT16_IN_PLACE(uint16_t &value)\n              void CORK_SWAP_UINT32_IN_PLACE(uint32_t &value)\n              void CORK_SWAP_UINT64_IN_PLACE(uint64_t &value)\n              void CORK_SWAP_UINT128_IN_PLACE(cork_u128 &value)\n\n   These functions always perform a byte-swap, regardless of the\n   endianness of the host system.\n\n.. function:: void CORK_UINT16_BIG_TO_HOST_IN_PLACE(uint16_t &value)\n              void CORK_UINT32_BIG_TO_HOST_IN_PLACE(uint32_t &value)\n              void CORK_UINT64_BIG_TO_HOST_IN_PLACE(uint64_t &value)\n              void CORK_UINT128_BIG_TO_HOST_IN_PLACE(cork_u128 &value)\n\n   These functions convert a big-endian (or network-endian) value into\n   host endianness, and vice versa.  (I.e., they only perform a swap if\n   the current host is little-endian.)\n\n.. function:: void CORK_UINT16_HOST_TO_BIG_IN_PLACE(uint16_t &value)\n              void CORK_UINT32_HOST_TO_BIG_IN_PLACE(uint32_t &value)\n              void CORK_UINT64_HOST_TO_BIG_IN_PLACE(uint64_t &value)\n              void CORK_UINT128_HOST_TO_BIG_IN_PLACE(cork_u128 &value)\n\n   These functions convert a host-endian value into big (or network)\n   endianness.  (I.e., they only perform a swap if the current host is\n   little-endian.)\n\n.. function:: void CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(uint16_t &value)\n              void CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(uint32_t &value)\n              void CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(uint64_t &value)\n              void CORK_UINT128_LITTLE_TO_HOST_IN_PLACE(cork_u128 &value)\n\n   These functions convert a little-endian value into host endianness, and\n   vice versa.  (I.e., they only perform a swap if the current host is\n   big-endian.)\n\n.. function:: void CORK_UINT16_HOST_TO_LITTLE_IN_PLACE(uint16_t &value)\n              void CORK_UINT32_HOST_TO_LITTLE_IN_PLACE(uint32_t &value)\n              void CORK_UINT64_HOST_TO_LITTLE_IN_PLACE(uint64_t &value)\n              void CORK_UINT128_HOST_TO_LITTLE_IN_PLACE(cork_u128 &value)\n\n   These functions convert a host-endian value into little endianness.\n   (I.e., they only perform a swap if the current host is big-endian.)\n"
  },
  {
    "path": "docs/old/cli.rst",
    "content": ".. _cli:\n\n*********************\nCommand-line programs\n*********************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/cli.h>\n\nThe functions in this section let you easily create complex command-line\napplications that include subcommands, in the style of the ``git`` or ``svn``\nprograms.\n\n\nOverview\n========\n\nIf you're designing an application where you want to provide command-line access\nto many different operations or use cases, the simplest solution is to create a\nseparate executable for each one.  This can clutter up the user's\n``$PREFIX/bin`` directory, however, and can add complexity to your code base.\nMany projects instead create a single “super-command” executable, which includes\nwithin it all of the operations that you want to support.  You choose specific\noperations by selecting a *subcommand* on the command line.\n\n.. type:: struct cork_command\n\n   An opaque type describing one of the subcommands in an executable.\n\nSo, for instance, if you were writing a library for manipulating sets of\nobjects, you could define several subcommands of a single ``set`` executable:\n\n.. code-block:: none\n\n    $ set add <filename> <element>\n    $ set query <filename> <element>\n    $ set remove <filename> <element>\n    $ set union -o <output file> <file1> <file2>\n    $ set print avro <filename>\n    $ set print json <filename>\n\nEach of these operations acts in exactly the same as if they were defined as\nseparate executables:\n\n.. code-block:: none\n\n    $ set-add <filename> <element>\n    $ set-query <filename> <element>\n    $ set-remove <filename> <element>\n    $ set-union -o <output file> <file1> <file2>\n    $ set-print-avro <filename>\n    $ set-print-json <filename>\n\nNote that you're not limited to one level of subcommands.  The ``set print``\nsubcommand, for instance, itself contains two subcommands: ``avro`` and\n``json``.\n\n\nLeaf commands\n=============\n\nA *leaf command* is a subcommand that represents one operation in your\nexecutable.  In the example above, there are six leaf commands: ``set add``,\n``set query``, ``set remove``, ``set union``, ``set print avro``, and ``set\nprint json``.\n\nTo define a leaf command, you use the following macro:\n\n.. macro:: cork_leaf_command(const char \\*name, const char \\*short_description, const char \\*usage, const char \\*full_help, cork_option_parser parse_options, run)\n\n   Returns :c:type:`cork_command` instance that defines a leaf command.  *name*\n   is the name of the leaf command; this is the word that the user must type on\n   the command-line to select this command.  (For ``set add``, this would be\n   ``add``; for ``set print avro``, this would be ``avro``.)\n\n   *short_description*, *usage*, and *full_help* should be static strings, and\n   will be used to produce various forms of :ref:`help text <cli-help>` for the\n   subcommand.  *short_description* should fit into one line; this will be used\n   as the short description of this leaf command when we print out a list of all\n   of the subcommands that are in the command set that this leaf belongs to.\n   *usage* will be printed whenever we need to print out a usage synopsis.  This\n   should describe the options and arguments to the leaf command; it will be\n   printed after the full name of the subcommand.  (For instance, using the\n   example above, the ``set add`` command's usage text would be ``<filename>\n   <element>``.)  *full_help* should be a longer, multi-line string that\n   describes the subcommand *in full detail*.  We will automatically preface the\n   help text with the usage summary for the command.\n\n   *parse_options* is a function that will be used to parse any command-line\n   options that appear *after* the subcommand's name on the command line.  (See\n   :ref:`below <cli-options>` for more details.)  This can be ``NULL`` if the\n   subcommand does not have any options.\n\n   *run* is the function that will be called to actually execute the command.\n   Any options will have already been processed by the *parse_options* function;\n   you should stash the option values into global or file-scope variables, and\n   then use the contents of those variables in this function.  Your *run*\n   function must be an instance of the :c:type:`cork_leaf_command_run` function\n   type:\n\n   .. type:: void (\\*cork_leaf_command_run)(int argc, char \\*\\*argv)\n\n      The *argc* and *argv* parameters will describe any values that appear on\n      the command line after the name of the leaf command.  This will *not*\n      include any options that were processed by the command's *parse_options*\n      function.\n\nAs an example, we could define the ``set add`` command as follows::\n\n    static void\n    set_add_run(int argc, char **argv);\n\n    #define SET_ADD_SHORT  \"Adds an element to a set\"\n    #define SET_ADD_USAGE  \"<filename> <element>\"\n    #define SET_ADD_FULL \\\n        \"Loads in a set from <filename>, and adds <element> to the set.  The\\n\" \\\n        \"new set will be written back out to <filename>.\\n\"\n\n    static struct cork_command  set_add =\n        cork_leaf_command(\"add\", SET_ADD_SHORT, SET_ADD_USAGE, SET_ADD_FULL,\n                          NULL, set_add_run);\n\n    static void\n    set_add_run(int argc, char **argv)\n    {\n        /* Verify that the user gave both required options... */\n        if (argc < 1) {\n            cork_command_show_help(&set_add, \"Missing set filename.\");\n            exit(EXIT_FAILURE);\n        }\n        if (argc < 2) {\n            cork_command_show_help(&set_add, \"Missing element to add.\");\n            exit(EXIT_FAILURE);\n        }\n\n        /* ...and no others. */\n        if (argc > 2) {\n            cork_command_show_help(&set_add, \"Too many values on command line.\");\n            exit(EXIT_FAILURE);\n        }\n\n        /* At this point, <filename> will be in argv[0], <element> will be in\n         * argv[1]. */\n\n        /* Do what needs to be done */\n        exit(EXIT_SUCCESS);\n    }\n\nThere are a few interesting points to make.  First, note that we use\npreprocessor macros to define all of the help text for the command.  Also, note\nthat *each* line (including the last) of the full help text needs to have a\ntrailing newline included in the string literal.\n\nLastly, note that we still have to perform some final validation of the command\nline arguments given by the user.  If the user hasn't satisfied the subcommand's\nrequirements, we use the :c:func:`cork_command_show_help` function to print out\na nice error message (including a usage summary of the subcommand), and then we\nhalt the executable using the standard ``exit`` function.\n\n\nCommand sets\n============\n\nA *command set* is a collection of subcommands.  Every executable will have at\nleast one command set, for the root executable itself.  It's also possible to\nhave nested command sets.  In our example above, ``set`` and ``set print`` are\nboth command sets.\n\nTo define a command set, you use the following macro:\n\n.. macro:: cork_command_set(const char \\*name, const char \\*short_description, cork_option_parser parse_options, struct cork_command \\*\\*subcommands)\n\n   Returns :c:type:`cork_command` instance that defines a command set.  *name*\n   is the name of the command set; this is the word that the user must type on\n   the command-line to select this set of commands.  If the user only specifies\n   the name of the command set, then we'll print out a list of this set's\n   subcommands, along with their short descriptions.  (For instance, running\n   ``set`` on its own would describe the ``set add``, ``set query``, ``set\n   remove``, ``set union``, and ``set print`` subcommands.  Running ``set\n   print`` on its own would describe the ``set print avro`` and ``set print\n   json`` commands.)\n\n   *short_description*, should be a static strings, and will be used to produce\n   various forms of :ref:`help text <cli-help>` for the command set.\n   *short_description* should fit into one line; this will be used as the short\n   description of this command when we print out a list of all of the\n   subcommands that are in the command set that this command belongs to.\n\n   *parse_options* is a function that will be used to parse any command-line\n   options that appear *after* the command set's name on the command line, but\n   *before* the name of one of the set's subcommands.  (See :ref:`below\n   <cli-options>` for more details.)  This can be ``NULL`` if the command set\n   does not have any options.\n\n   *subcommands* should be an array of :c:type:`cork_command` pointers.  The\n   array **must** have a ``NULL`` pointer as its last element.  The order of the\n   subcommands in the array will effect the order that the commands are listed\n   in the command set's help text.\n\nAs an example, we could define the ``set print`` command set as follows::\n\n    /* Assuming set_print_avro and set_print_json were already defined\n     * previously, using cork_leaf_command: */\n    struct cork_command  set_print_avro = cork_leaf_command(...);\n    struct cork_command  set_print_json = cork_leaf_command(...);\n\n    /* \"set print\" command set */\n    static struct cork_command  *set_print_subcommands[] = {\n        &set_print_avro,\n        &set_print_json,\n        NULL\n    };\n\n    #define SET_PRINT_SHORT \\\n        \"Print out the contents of a set in a variety of formats\"\n\n    static struct cork_command  set_print =\n        cork_command_set(\"print\", SET_PRINT_SHORT, NULL, &set_print_subcommands);\n\nYou must define your executable's top level of subcommands as a command set as\nwell.  For instance, we could define the ``set`` command set as follows::\n\n    static struct cork_command  *root_subcommands[] = {\n        &set_add,\n        &set_query,\n        &set_remove,\n        &set_union,\n        &set_print,\n        NULL\n    };\n\n    static struct cork_command  root =\n        cork_command_set(\"set\", NULL, NULL, &root_subcommands);\n\nNote that we don't need to provide a short description for the root command,\nsince it doesn't belong to any command sets.\n\n\nRunning the commands\n====================\n\nOnce you've defined all of your subcommands, your executable's ``main`` function\nis trivial::\n\n    int\n    main(int argc, char **argv)\n    {\n        return cork_command_main(&root, argc, argv);\n    }\n\n.. function:: int cork_command_main(struct cork_command \\*root, int argc, char \\*\\*argv)\n\n   Runs a subcommand, as defined by the command-line arguments given by *argc*\n   and *argv*.  *root* should define the root command set for the executable.\n\n\n.. _cli-help:\n\nHelp text\n=========\n\nThe command-line programs created with this framework automatically support\ngenerating several flavors of help text for its subcommands.  You don't need to\ndo anything special, except for ensuring that the actual help text that you\nprovide to the :c:macro:`cork_leaf_command` and :c:macro:`cork_command_set`\nmacros defined is intelligble and useful.\n\nYour executable will automatically include a ``help`` command in every command\nset, as well as ``--help`` and ``-h`` options in every command set and leaf\ncommand.  So all of the following would print out the help text for the ``set\nadd`` command:\n\n.. code-block:: none\n\n    $ set help add\n    $ set add --help\n    $ set add -h\n\nAnd all of the following would print out the list of ``set print`` subcommands:\n\n.. code-block:: none\n\n    $ set help print\n    $ set print --help\n    $ set print -h\n\nYou can also print out the help text for a command explicitly by calling the\nfollowing function:\n\n.. function:: void cork_command_show_help(struct cork_command \\*command, const char \\*message)\n\n    Prints out help text for *command*.  (If it's a leaf command, this is the\n    full help text.  If it's a command set, it's a list of the set's\n    subcommands.)  We will preface the help text with *message* if it's\n    non-``NULL``.  (The message should not include a trailing newline.)\n\n\n.. _cli-options:\n\nOption parsing\n==============\n\nLeaf commands and command sets both let you provide a function that parse\ncommand-line options for the given command.  We don't prescribe any particular\noption parsing library, you just need to conform to the interface described in\nthis section.  (Note that the standard ``getopt`` and ``getopt_long`` functions\ncan easily be used in an option parsing function.)\n\n.. type:: int (\\*cork_option_parser)(int argc, char \\*\\*argv)\n\n   Should parse any command-line options that can appear at this point in the\n   executable's command line.  (The options must appear immediately after the\n   name of the command that this function belongs to.  See below for several\n   examples.)\n\n   Your function must look for and process any options that appear at the\n   beginning of *argv*.  If there are any errors processing the options, you\n   should print out an error message (most likely via\n   :c:func:`cork_command_show_help`) and exit the program, using the standard\n   ``exit`` function, with an exit code of ``EXIT_FAILURE``.\n\n   If there aren't any errors processing the options, you should return the\n   number of *argv* elements that were consumed while processing the options.\n   We will use this return value to update *argc* and *argv* beforing continuing\n   with subcommand selection and argument processing.  (Note that ``getopt``'s\n   ``optind`` variable is exactly what you need for the return value.)\n\nAs mentioned above, different option parsing functions are used to parse options\nfrom a particular point in the command line.  Given the following command:\n\n.. code-block:: none\n\n    $ set --opt1 print --opt2 avro --opt3 --opt4=foo <filename>\n\nThe ``--opt1`` option would be parsed by the ``set`` command's parser.  The\n``--opt2`` option would be parsed by the ``set print`` command's parser.  The\n``--opt3`` and ``-opt4=foo`` options would be parsed by the ``set print avro``\ncommand's parser.  And the ``<filename>`` argument would be parsed by the ``set\nprint avro`` command's *run* function.\n"
  },
  {
    "path": "docs/old/conf.py",
    "content": "# -*- coding: utf-8 -*-\n\nimport sys, os\n\nextensions = ['sphinx.ext.mathjax']\nsource_suffix = '.rst'\nmaster_doc = 'index'\nproject_name = u'libcork'\nproject_slug = u'libcork'\ncompany = u'libcork authors'\ncopyright_years = u'2011-2017'\n\ndefault_role = 'c:func'\nprimary_domain = 'c'\n\nrst_epilog = \"\"\"\n.. |project_name| replace:: \"\"\" + project_name + \"\"\"\n\"\"\"\n\n# Intersphinx stuff\n\n# If your documentation uses intersphinx to link to other Sphinx\n# documentation sets, uncomment and fill in the following.\n#\n#intersphinx_mapping = {\n#    'libcork': ('http://libcork.readthedocs.org/en/latest/', None),\n#}\n\n# Our CMake build scripts will insert overrides below if the prereq\n# libraries have installed their Sphinx documentation locally.  DO NOT\n# uncomment out the last line of this block; we need it commented so\n# that this conf.py file still works if CMake doesn't do its\n# substitution thing.\n# @INTERSPHINX_OVERRIDES@\n\n#----------------------------------------------------------------------\n# Everything below here shouldn't need to be changed.\n\nrelease = None\nversion = None\n\n# Give CMake a chance to insert a version number\n# @VERSION_FOR_CONF_PY@\n\n# Otherwise grab version from git\nif version is None:\n    import re\n    import subprocess\n    release = str(subprocess.check_output([\"git\", \"describe\"]).rstrip())\n    version = re.sub(r\"-dev.*$\", \"-dev\", release)\n\n# Project details\n\nproject = project_name\ncopyright = copyright_years+u', '+company\ntemplates_path = ['_templates']\nexclude_patterns = ['_build']\npygments_style = 'sphinx'\n\nhtml_theme = 'default'\nhtml_style = 'docco-sphinx.css'\nhtml_static_path = ['_static']\nhtmlhelp_basename = project_slug+'-doc'\n\n\nlatex_documents = [\n  ('index', project_slug+'.tex', project_name+u' Documentation',\n   company, 'manual'),\n]\n\nman_pages = [\n    ('index', 'libcork', u'libcork documentation',\n     [u'libcork authors'], 1)\n]\n\ntexinfo_documents = [\n  ('index', 'libcork', u'libcork documentation',\n   u'libcork authors', 'libcork', 'One line description of project.',\n   'Miscellaneous'),\n]\n"
  },
  {
    "path": "docs/old/config.rst",
    "content": ".. _config:\n\n*******************\nConfiguring libcork\n*******************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/config.h>\n\nSeveral libcork features have different implementations on different\nplatforms.  Since we want libcork to be easily embeddable into projects\nwith a wide range of build systems, we try to autodetect which\nimplementations to use, using only the C preprocessor and the predefined\nmacros that are available on the current system.\n\nThis module provides a layer of indirection, with all of the\npreprocessor-based autodetection in one place.  This module's task is to\ndefine a collection of libcork-specific configuration macros, which all\nother libcork modules will use to select which implementation to use.\n\nThis design also lets you skip the autodetection, and provide values for\nthe configuration macros directly.  This is especially useful if you're\nembedding libcork into another project, and already have a ``configure``\nstep in your build system that performs platform detection.  See\n:c:macro:`CORK_CONFIG_SKIP_AUTODETECT` for details.\n\n.. note::\n\n   The autodetection logic is almost certainly incomplete.  If you need\n   to port libcork to another platform, this is where an important chunk\n   of edits will take place.  Patches are welcome!\n\n\n.. _configuration-macros:\n\nConfiguration macros\n====================\n\nThis section lists all of the macros that are defined by libcork's\nautodetection logic.  Other libcork modules will use the values of these\nmacros to choose among the possible implementations.\n\n\n.. macro:: CORK_CONFIG_VERSION_MAJOR\n           CORK_CONFIG_VERSION_MINOR\n           CORK_CONFIG_VERSION_PATCH\n\n   The libcork library version, with each part of the version number separated\n   out into separate macros.\n\n\n.. macro:: CORK_CONFIG_VERSION_STRING\n\n   The libcork library version, encoded as a single string.\n\n\n.. macro:: CORK_CONFIG_REVISION\n\n   The git SHA-1 commit identifier of the libcork version that you're using.\n\n\n.. macro:: CORK_CONFIG_ARCH_X86\n           CORK_CONFIG_ARCH_X64\n           CORK_CONFIG_ARCH_PPC\n\n   Exactly one of these macros should be defined to ``1`` to indicate\n   the architecture of the current platform.  All of the other macros\n   should be defined to ``0`` or left undefined.  The macros correspond\n   to the following architectures:\n\n   ============ ================================================\n   Macro suffix Architecture\n   ============ ================================================\n   ``X86``      32-bit Intel (386 or greater)\n   ``X64``      64-bit Intel/AMD (AMD64/EM64T, *not* IA-64)\n   ``PPC``      32-bit PowerPC\n   ============ ================================================\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_ASM\n\n   Whether the GCC `inline assembler`_ syntax is available.  (This\n   doesn't imply that the compiler is specifically GCC.)  Should be\n   defined to ``0`` or ``1``.\n\n   .. _inline assembler: http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n\n   Whether the GCC-style syntax for `compiler attributes`_ is available.\n   (This doesn't imply that the compiler is specifically GCC.)  Should\n   be defined to ``0`` or ``1``.\n\n   .. _compiler attributes: http://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_ATOMICS\n\n   Whether GCC-style `atomic intrinsics`_ are available.  (This doesn't\n   imply that the compiler is specifically GCC.)  Should be defined to\n   ``0`` or ``1``.\n\n   .. _atomic intrinsics: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html\n\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_INT128\n\n   Whether the GCC-style `128-bit integer`_ types (``__int128`` and ``unsigned\n   __int128``) are available.  (This doesn't imply that the compiler is\n   specifically GCC.)  Should be defined to ``0`` or ``1``.\n\n   .. _128-bit integer: http://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE\n\n   Whether GCC-style `machine modes`_ are available.  (This doesn't imply that\n   the compiler is specifically GCC.)  Should be defined to ``0`` or ``1``.\n\n   .. _machine modes: http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gccint/Machine-Modes.html#Machine-Modes\n\n\n.. macro:: CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS\n\n   Whether GCC-style `statement expressions`_ are available.\n   (This doesn't imply that the compiler is specifically GCC.)  Should\n   be defined to ``0`` or ``1``.\n\n   .. _statement expressions: http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html\n\n\n.. macro:: CORK_CONFIG_HAVE_REALLOCF\n\n   Whether this platform defines a ``reallocf`` function in\n   ``stdlib.h``.  ``reallocf`` is a BSD extension to the standard\n   ``realloc`` function that frees the existing pointer if a\n   reallocation fails.  If this function exists, we can use it to\n   implement :func:`cork_realloc`.\n\n\n.. macro:: CORK_CONFIG_IS_BIG_ENDIAN\n           CORK_CONFIG_IS_LITTLE_ENDIAN\n\n   Whether the current system is big-endian or little-endian.  Exactly\n   one of these macros should be defined to ``1``; the other should be\n   defined to ``0``.\n\n\n.. _skipping-autodetection:\n\nSkipping autodetection\n======================\n\n\n.. macro:: CORK_CONFIG_SKIP_AUTODETECT\n\n   If you want to skip libcork's autodetection logic, then you are\n   responsible for providing the appropriate values for all of the\n   macros defined in :ref:`configuration-macros`.  To do this, have your\n   build system define this macro, with a value of ``1``.  This will\n   override the default value of ``0`` provided in the\n   ``libcork/config/config.h`` header file.\n\n   Then, create (or have your build system create) a\n   ``libcork/config/custom.h`` header file.  You can place this file\n   anywhere in your header search path.  We will load that file instead\n   of libcork's autodetection logic.  Place the appropriate definitions\n   for each of the configuration macros into this file.  If needed, you\n   can generate this file as part of the ``configure`` step of your\n   build system; the only requirement is that it's available once you\n   start compiling the libcork source files.\n"
  },
  {
    "path": "docs/old/dllist.rst",
    "content": ".. _dllist:\n\n*******************\nDoubly-linked lists\n*******************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines a doubly-linked list data structure.  The structure\nis “invasive”, since you must place an instance of the\n:c:type:`cork_dllist_item` type into the type whose instances will be\nstored in the list.  The list itself is represented by the\n:c:type:`cork_dllist` type.\n\nAs an example, we could define the following types for storing groups,\nas well as the users within each group::\n\n  struct group {\n      const char  *group_name;\n      struct cork_dllist  members;\n  };\n\n  struct user {\n      const char  *username;\n      const char  *real_name;\n      struct cork_dllist_item  list;\n  };\n\nNote that both ``cork_dllist`` and ``cork_dllist_item`` are embedded\ndirectly into our domain-specific types.  This means that every list\noperation defined in this section is guaranteed to succeed, since no\nmemory operations will be involved.  (The list and any items will have\nalready been allocated before you try to call the list function.)\n\nLike with any embedded ``struct``, you can use the\n:c:func:`cork_container_of` macro to obtain a pointer to a ``struct\nuser`` if you're given a pointer to a :c:type:`cork_dllist_item`.\n\n\n.. type:: struct cork_dllist\n\n   A doubly-linked list.  The list itself is represented by a sentinel\n   element, representing the empty list.\n\n\n.. type:: struct cork_dllist_item\n\n   An element of a doubly-linked list.  This type will usually be\n   embedded within the type whose instances will be stored in the list.\n\n   .. member:: struct cork_dllist_item \\*next\n               struct cork_dllist_item \\*prev\n\n      A pointer to the next (or previous) element in the list.  If this\n      element marks the end (or beginning) of the list, then *next* (or\n      *prev*) will point to the list's sentinel value.\n\n\n.. function:: void cork_dllist_init(struct cork_dllist \\*list)\n              struct cork_dllist CORK_DLLIST_INIT(SYMBOL name)\n\n   Initializes a doubly-linked list.  The list will initially be empty.\n\n   The second variant is a static initializer, that lets you initialize a list\n   at compile time, rather than runtime.  You must pass in the name of the list\n   for this to work, since we need to be able to extract pointers into the list\n   object.\n\n\nQuerying a list\n---------------\n\n.. function:: size_t cork_dllist_size(const struct cork_dllist \\*list)\n\n   Returns the number of elements in *list*.\n   \n   This operation runs in :math:`O(n)` time.\n\n\n.. function:: bool cork_dllist_is_empty(struct cork_dllist \\*list)\n\n   Returns whether *list* is empty.\n\n   This operation runs in :math:`O(1)` time.\n\n\nEditing a list\n--------------\n\n.. function:: void cork_dllist_add_to_head(struct cork_dllist \\*list, struct cork_dllist_item \\*element)\n              void cork_dllist_add_to_tail(struct cork_dllist \\*list, struct cork_dllist_item \\*element)\n\n   Adds *element* to *list*.  The ``_head`` variant adds the new element to the\n   beginning of the list; the ``_tail`` variant adds it to the end.\n   \n   You are responsible for allocating the list element yourself, most likely by\n   allocating the ``struct`` that you've embedded :c:type:`cork_dllist_item`\n   into.\n\n   .. note::\n\n      This function assumes that *element* isn't already a member of a different\n      list.  You're responsible for calling :c:func:`cork_dllist_remove()` if\n      this isn't the case.  (If you don't, the other list will become\n      malformed.)\n\n   This operation runs in :math:`O(1)` time.\n\n\n.. function:: void cork_dllist_add_after(struct cork_dllist_item \\*pred, struct cork_dllist_item \\*element)\n              void cork_dllist_add_before(struct cork_dllist_item \\*succ, struct cork_dllist_item \\*element)\n\n   Adds *element* to the same list that *pred* or *succ* belong to.  The\n   ``_after`` variant ensures that *element* appears in the list immediately\n   after *pred*.  The ``_before`` variant ensures that *element* appears in the\n   list immediately before *succ*.\n\n   .. note::\n\n      This function assumes that *element* isn't already a member of a different\n      list.  You're responsible for calling :c:func:`cork_dllist_remove()` if\n      this isn't the case.  (If you don't, the other list will become\n      malformed.)\n\n   This operation runs in :math:`O(1)` time.\n\n\n.. function:: void cork_dllist_add_list_to_head(struct cork_dllist \\*dest, struct cork_dllist \\*src)\n              void cork_dllist_add_list_to_tail(struct cork_dllist \\*dest, struct cork_dllist \\*src)\n\n   Moves all of the elements in *src* to *dest*.  The ``_head`` variant moves\n   the elements to the beginning of *dest*; the ``_tail`` variant moves them to\n   the end.  After these functions return, *src* will be empty.\n\n   This operation runs in :math:`O(1)` time.\n\n\n.. function:: void cork_dllist_remove(struct cork_dllist_item \\*element)\n\n   Removes *element* from the list that it currently belongs to.  (Note\n   that you don't have to pass in a pointer to that list.)\n\n   .. note::\n\n      You must not call this function on a list's sentinel element.\n\n   This operation runs in :math:`O(1)` time.\n\n\nIterating through a list\n------------------------\n\nThere are two strategies you can use to access all of the elements in a\ndoubly-linked list: *visiting* and *iterating*.  With visiting, you write\na visitor function, which will be applied to each element in the list.\n(In this case, libcork controls the loop that steps through each\nelement.)\n\n.. function:: int cork_dllist_visit(struct cork_dllist \\*list, void \\*user_data, cork_dllist_visit_f \\*func)\n\n   Apply a function to each element in *list*.  The function is allowed\n   to remove the current element from the list; this will not affect our\n   ability to iterate through the remainder of the list.  The function\n   will be given a pointer to the :c:type:`cork_dllist_item` for each\n   element; you can use :c:func:`cork_container_of()` to get a pointer to the\n   actual element type.\n\n   If your visitor function ever returns a non-zero value, we will abort the\n   iteration and return that value from ``cork_dllist_visit``.  If your function\n   always returns ``0``, then you will visit all of the elements in *list*, and\n   we'll return ``0`` from ``cork_dllist_visit``.\n\n   .. type:: int cork_dllist_visit_f(void \\*user_data, struct cork_dllist_item \\*element)\n\n      A function that can be applied to each element in a doubly-linked list.\n\nFor instance, you can manually calculate the number of elements in a\nlist as follows (assuming you didn't want to use the built-in\n:c:func:`cork_dllist_size()` function, of course)::\n\n  static int\n  count_elements(void *user_data, struct cork_dllist_item *element)\n  {\n      size_t  *count = ud;\n      (*count)++;\n      return 0;\n  }\n\n  struct cork_dllist  *list = /* from somewhere */;\n  size_t  count = 0;\n  cork_dllist_visit(list, &count, count_elements);  /* returns 0 */\n  /* the number of elements is now in count */\n\n\nThe second strategy is to iterate through the elements yourself.\n\n.. macro:: cork_dllist_foreach(struct cork_dllist \\*list, struct cork_dllist_item &\\*curr, struct cork_dllist_item &\\*next, TYPE element_type, TYPE &\\*element, FIELD item_field)\n           cork_dllist_foreach_void(struct cork_dllist \\*list, struct cork_dllist_item &\\*curr, struct cork_dllist_item &\\*next)\n\n   Iterate through each element in *list*, executing a statement for each one.\n   You must declare two variables of type ``struct cork_dllist_item *``, and\n   pass in their names as *curr* and *next*.  (You'll usually call the variables\n   ``curr`` and ``next``, too.)\n\n   For the ``_void`` variant, your statement can only use these\n   :c:type:`cork_dllist_item` variables to access the current list element.  You\n   can use :c:func:`cork_container_of` to get a pointer to the actual element\n   type.\n\n   For the non-``_void`` variant, we'll automatically call\n   :c:func:`cork_container_of` for you.  *element_type* should be the actual\n   element type, which must contain an embedded :c:func:`cork_dllist_item`\n   field.  *item_field* should be the name of this embedded field.  You must\n   allocate a pointer to the element type, and pass in its name as *element*.\n\nFor instance, you can use these macros calculate the number of elements as\nfollows::\n\n  struct cork_dllist  *list = /* from somewhere */;\n  struct cork_dllist  *curr;\n  struct cork_dllist  *next;\n  size_t  count = 0;\n  cork_dllist_foreach_void(list, curr, next) {\n      count++;\n  }\n  /* the number of elements is now in count */\n\nWe're able to use :c:macro:`cork_dllist_foreach_void` since we don't need to\naccess the contents of each element to calculate how many of theo there are.  If\nwe wanted to calculuate a sum, however, we'd have to use\n:c:macro:`cork_dllist_foreach`::\n\n  struct element {\n      unsigned int  value;\n      struct cork_dllist_item  item;\n  };\n\n  struct cork_dllist  *list = /* from somewhere */;\n  struct cork_dllist  *curr;\n  struct cork_dllist  *next;\n  struct element  *element;\n  unsigned int  sum = 0;\n  cork_dllist_foreach(list, curr, next, struct element, element, item) {\n      sum += element->value;\n  }\n  /* the sum of the elements is now in sum */\n\n\nIf the ``foreach`` macros don't provide what you need, you can also iterate\nthrough the list manually.\n\n.. function:: struct cork_dllist_item \\*cork_dllist_head(struct cork_dllist \\*list)\n              struct cork_dllist_item \\*cork_dllist_start(struct cork_dllist \\*list)\n\n   Returns the element at the beginning of *list*.  If *list* is empty,\n   then the ``_head`` variant will return ``NULL``, while the ``_start``\n   variant will return the list's sentinel element.\n\n\n.. function:: struct cork_dllist_item \\*cork_dllist_tail(struct cork_dllist \\*list)\n              struct cork_dllist_item \\*cork_dllist_end(struct cork_dllist \\*list)\n\n   Returns the element at the end of *list*.  If *list* is empty, then\n   the ``_tail`` variant will return ``NULL``, while the ``_end``\n   variant will return the list's sentinel element.\n\n.. function:: bool cork_dllist_is_start(struct cork_dllist \\*list, struct cork_dllist_item \\*element)\n              bool cork_dllist_is_end(struct cork_dllist \\*list, struct cork_dllist_item \\*element)\n\n   Returns whether *element* marks the start (or end) of *list*.\n\nWith these functions, manually counting the list elements looks like::\n\n  struct cork_dllist  *list = /* from somewhere */;\n  struct cork_dllist_item  *curr;\n  size_t  count = 0;\n  for (curr = cork_dllist_start(list); !cork_dllist_is_end(list, curr);\n       curr = curr->next) {\n      count++;\n  }\n  /* the number of elements is now in count */\n\nYou can also count the elements in reverse order::\n\n  struct cork_dllist  *list = /* from somewhere */;\n  struct cork_dllist_item  *curr;\n  size_t  count = 0;\n  for (curr = cork_dllist_end(list); !cork_dllist_is_start(list, curr);\n       curr = curr->prev) {\n      count++;\n  }\n  /* the number of elements is now in count */\n"
  },
  {
    "path": "docs/old/ds.rst",
    "content": ".. _ds:\n\n***************\nData structures\n***************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nlibcork includes implementations of a number of useful data structures.\n\n.. toctree::\n   :maxdepth: 1\n\n   array\n   bitset\n   slice\n   managed-buffer\n   buffer\n   stream\n   dllist\n   hash-table\n   ring-buffer\n"
  },
  {
    "path": "docs/old/errors.rst",
    "content": ".. _errors:\n\n***************\nError reporting\n***************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThis section defines an API for reporting error conditions.  It's loosely\nmodeled on the POSIX ``errno`` mechanism.\n\nThe standard POSIX approach for reporting errors is to return an integer status\ncode, and to store error codes into the ``errno`` global variable.  This\napproach has a couple of drawbacks.  The first is that you --- or really, your C\nlibrary --- has to ensure that ``errno`` is placed in thread-local storage, so\nthat separate threads have their own error condition variables.  The second, and\nin our mind more important, is that the set of error codes is fixed and\nplatform-dependent.  It's difficult to add new error codes to represent\napplication-level error conditions.\n\nThe libcork error API is a way around this.  Like standard POSIX-conforming\nfunctions, you return an integer status code from any function that might need\nto report an error to its caller.  The status return code is simple: ``0``\nindicates success, ``-1`` indicates failure.\n\nWhen an error occurs, you can use the functions in this section to get more\ninformation about the error: an *error code*, and human-readable string\ndescription of the error.  The POSIX ``errno`` values, while hard to extend, are\nperfectly well-defined for most platforms; therefore, any ``errno`` value\nsupported by your system's C library is a valid libcork error code.  To support\nnew application-specific error codes, an error code can also be the hash of some\nstring describing the error.  This “hash of a string” approach makes it easy to\ndefine new error codes without needing any centralized mechanism for assigning\nIDs to the various codes.  Moreover, it's very unlikely that a hashed error code\nwill conflict with some existing POSIX ``errno`` value, or with any other hashed\nerror codes.\n\n.. note::\n\n   We correctly maintain a separate error condition for each thread in\n   the current process.  This is all hidden by the functions in this\n   section; it's safe to call them from multiple threads simultaneously.\n\n\nCalling a function that can return an error\n-------------------------------------------\n\nThere are two basic forms for a function that can produce an error.  The\nfirst is if the function returns a single pointer as its result::\n\n  TYPE *\n  my_function(/* parameters */);\n\nThe second is for any other function::\n\n  int\n  my_function(/* parameters */);\n\nIf an error occurs, the function will return either ``NULL`` or ``-1``,\ndepending on its return type.  Success will be indicated by a non-\\\n``NULL`` pointer or a ``0``.  (More complex return value schemes are\npossible, if the function needs to signal more than a simple “success”\nor “failure”; in that case, you'll need to check the function's\ndocumentation for details.)\n\nIf you want to know specifics about the error, there are several\nfunctions that you can use to interrogate the current error condition.\n\n.. function:: bool cork_error_occurred(void)\n\n   Returns whether an error has occurred.\n\n.. function:: cork_error cork_error_code(void)\n\n   Returns the error code of the current error condition.  If no error has\n   occurred, the result will be :c:macro:`CORK_ERROR_NONE`.\n\n.. function:: const char \\*cork_error_message(void)\n\n   Returns the human-readable string description the current error\n   condition.  If no error occurred, the result of this function is\n   undefined.\n\nYou can use the ``cork_error_prefix`` family of functions to add additional\ncontext to the beginning of an error message.\n\n.. function:: void cork_error_prefix_printf(const char \\*format, ...)\n              void cork_error_prefix_string(const char \\*string)\n              void cork_error_prefix_vprintf(const char \\*format, va_list args)\n\n   Prepends some additional text to the current error condition.\n\nWhen you're done checking the current error condition, you clear it so\nthat later calls to :c:func:`cork_error_occurred` and friends don't\nre-report this error.\n\n.. function:: void cork_error_clear(void)\n\n   Clears the current error condition.\n\n\nWriting a function that can return an error\n-------------------------------------------\n\nWhen writing a function that might produce an error condition, your\nfunction signature should follow one of the two standard patterns\ndescribed above::\n\n  int\n  my_function(/* parameters */);\n\n  TYPE *\n  my_function(/* parameters */);\n\nYou should return ``-1`` or ``NULL`` if an error occurs, and ``0`` or a\nnon-\\ ``NULL`` pointer if it succeeds.  If ``NULL`` is a valid\n“successful” result of the function, you should use the first form, and\ndefine a ``TYPE **`` output parameter to return the actual pointer\nvalue.  (If you're using the first form, you can use additional return\ncodes if there are other possible results besides a simple “success” and\n“failure”.)\n\nIf your function results in an error, you need to fill in the current\nerror condition using the ``cork_error_set`` family of functions:\n\n.. function:: void cork_error_set_printf(cork_error ecode, const char \\*format, ...)\n              void cork_error_set_string(cork_error ecode, const char \\*string)\n              void cork_error_set_vprintf(cork_error ecode, const char \\*format, va_list args)\n\n   Fills in the current error condition.  The error condition is defined\n   by the error code *ecode*.  The human-readable description is constructed\n   from *string*, or from *format* and any additional parameters, depending on\n   which variant you use.\n\nAs an example, the :ref:`IP address <net-addresses>` parsing functions fill in\n:c:macro:`CORK_PARSE_ERROR` error conditions when you try to parse a malformed\naddress::\n\n  const char  *str = /* the string that's being parsed */;\n  cork_error_set_printf\n      (CORK_PARSE_ERROR, \"Invalid IP address: %s\", str);\n\nIf a particular kind of error can be raised in several places\nthroughout your code, it can be useful to define a helper function for\nfilling in the current error condition::\n\n  static void\n  cork_ip_address_parse_error(const char *version, const char *str)\n  {\n      cork_error_set_printf\n          (CORK_PARSE_ERROR, \"Invalid %s address: %s\", version, str);\n  }\n\n\nError-checking macros\n---------------------\n\nThere can be a lot of repetitive code when calling functions that return\nerror conditions.  We provide a collection of helper macros that make it\neasier to write this code.\n\n.. note::\n\n   Unlike most libcork modules, these macros are **not** automatically\n   defined when you include the ``libcork/core.h`` header file, since\n   they don't include a ``cork_`` prefix.  Because of this, we don't\n   want to pollute your namespace unless you ask for the macros.  To do\n   so, you must explicitly include their header file::\n\n     #include <libcork/helpers/errors.h>\n\nAdditional debugging output\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. macro:: CORK_PRINT_ERRORS\n\n   If you define this macro to ``1`` before including\n   :file:`libcork/helpers/errors.h`, then we'll output the current\n   function name, file, and line number, along with the description of\n   the error, to stderr whenever an error is detected by one of the\n   macros described in this section.\n\nReturning a default error code\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you follow one of the standard function signature patterns described\nabove, then your function will either return an ``int`` or some pointer\ntype, and errors will be signalled by a return value of ``-1`` or\n``NULL``.  If so, you can use the macros in this section to\nautomatically return the appropriate error return value if a nested\nfunction call returns an error.\n\nWith these macros, you won't have a chance to inspect the error\ncondition when an error occurs, so you should pass in your own *err*\nparameter when calling the nested function.\n\n(The mnemonic for remembering these macro names is that they all start\nwith ``rXY_``.  The ``r`` indicates that they automatically “return”.\nThe second character indicates whether *your* function returns an\n``int`` or a pointer.  The third character indicates whether the\nfunction you're *calling* returns an ``int`` or a pointer.)\n\n.. function:: void rie_check(call)\n\n   Call a function whose return value isn't enough to check for an error, when\n   your function returns an ``int``.  We'll use :c:func:`cork_error_occurred` to\n   check for an error.  If the nested function call returns an error, we\n   propagate that error on.\n\n.. function:: void rii_check(call)\n\n   Call a function that returns an ``int`` error indicator, when your\n   function also returns an ``int``.  If the nested function call\n   returns an error, we propagate that error on.\n\n.. function:: void rip_check(call)\n\n   Call a function that returns a pointer, when your function returns an\n   ``int``.  If the nested function call returns an error, we propagate\n   that error on.\n\n.. function:: void rpe_check(call)\n\n   Call a function whose return value isn't enough to check for an error, when\n   your function returns a pointer.  We'll use :c:func:`cork_error_occurred` to\n   check for an error.  If the nested function call returns an error, we\n   propagate that error on.\n\n.. function:: void rpi_check(call)\n\n   Call a function that returns an ``int`` error indicator, when your\n   function returns a pointer.  If the nested function call returns an\n   error, we propagate that error on.\n\n.. function:: void rpp_check(call)\n\n   Call a function that returns a pointer, when your function also\n   returns a pointer.  If the nested function call returns an error, we\n   propagate that error on.\n\nReturning a non-standard return value\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf your function doesn't have a standard signature, or it uses\nadditional return values besides ``0``, ``1``, ``NULL``, and valid\npointers, then you can use the macros in this section to return a custom\nreturn value in case of an error.\n\nWith these macros, you won't have a chance to inspect the error\ncondition when an error occurs, so you should pass in your own *err*\nparameter when calling the nested function.\n\n(The mnemonic for remembering these macro names is that they all start\nwith ``xY_``.  The ``x`` doesn't standard for anything in particular.\nThe second character indicates whether the function you're *calling*\nreturns an ``int`` or a pointer.  We don't need separate macros for\n*your* function's return type, since you provide a return value\nexplicitly.)\n\n.. function:: void xe_check(retval, call)\n\n   Call a function whose return value isn't enough to check for an error.  If\n   the nested function call raises an error, we propagate that error on, and\n   return *retval* from the current function.\n\n.. function:: void xi_check(retval, call)\n\n   Call a function that returns an ``int`` error indicator.  If the\n   nested function call raises an error, we propagate that error on, and\n   return *retval* from the current function.\n\n.. function:: void xp_check(retval, call)\n\n   Call a function that returns a pointer.  If the nested function call\n   raises an error, we propagate that error on, and return *retval* from\n   the current function.\n\nPost-processing when an error occurs\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you need to perform some post-processing when a nested function\nreturns an error, you can use the functions in this section.  They will\nautomatically jump to the current scope's ``error`` label whenever an\nerror occurs.\n\n(The mnemonic for remembering these macro names is that they all start\nwith ``eY_``.  The ``e`` indicates that they'll jump to the ``error``\nlabel.  The second character indicates whether the function you're\n*calling* returns an ``int`` or a pointer.  We don't need separate\nmacros for *your* function's return type, since the macros won't\nautomatically return anything.)\n\n.. function:: void ei_check(call)\n\n   Call a function whose return value isn't enough to check for an error.  If\n   the nested function call raises an error, we automatically jump to the\n   current scope's ``error`` label.\n\n.. function:: void ei_check(call)\n\n   Call a function that returns an ``int`` error indicator.  If the\n   nested function call raises an error, we automatically jump to the\n   current scope's ``error`` label.\n\n.. function:: void ep_check(call)\n\n   Call a function that returns a pointer.  If the nested function call\n   raises an error, we automatically jump to the current scope's\n   ``error`` label.\n\n\nCalling POSIX functions\n~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :c:func:`cork_system_error_set` function automatically translates a POSIX\nerror (specified in the standard ``errno`` variable) into a libcork error\ncondition (which will be reported by :c:func:`cork_error_occurred` and friends).\nWe also define several helper macros for calling a POSIX function and\nautomatically checking its result.\n\n::\n\n   #include <libcork/helpers/posix.h>\n\n.. note::\n\n   For all of these macros, the ``EINTR`` POSIX error is handled specially.\n   This error indicates that a system call was interrupted by a signal, and that\n   the call should be retried.  The macros do not translate ``EINTR`` errors\n   into libcork errors; instead, they will retry the ``call`` until the\n   statement succeeds or returns a non-``EINTR`` error.\n\n.. function:: void rii_check_posix(call)\n\n   Call a function that returns an ``int`` error indicator, when your function\n   also returns an ``int``.  If the nested function call returns a POSIX error,\n   we translate it into a libcork error and return a libcork error code.\n\n.. function:: void rip_check_posix(call)\n\n   Call a function that returns a pointer, when your function returns an\n   ``int``.  If the nested function call returns a POSIX error, we translate it\n   into a libcork error and return a libcork error code.\n\n.. function:: void rpi_check_posix(call)\n\n   Call a function that returns an ``int`` error indicator, when your function\n   returns a pointer.  If the nested function call returns a POSIX error, we\n   translate it into a libcork error and return a libcork error code.\n\n.. function:: void rpp_check_posix(call)\n\n   Call a function that returns a pointer, when your function also returns a\n   pointer.  If the nested function call returns a POSIX error, we translate it\n   into a libcork error and return a libcork error code.\n\n.. function:: void ei_check_posix(call)\n\n   Call a function that returns an ``int`` error indicator.  If the nested\n   function call raises a POSIX error, we translate it into a libcork error and\n   automatically jump to the current scope's ``error`` label.\n\n.. function:: void ep_check_posix(call)\n\n   Call a function that returns a pointer.  If the nested function call raises a\n   POSIX error, we translate it into a libcork error and automatically jump to\n   the current scope's ``error`` label.\n\n\nDefining new error codes\n------------------------\n\nIf none of the built-in error codes suffice for an error condition that you need\nto report, you'll have to define our own.  As mentioned above, each libcork\nerror code is either a predefined POSIX ``errno`` value, or a hash some of\nstring identifying a custom error condition.\n\nTypically, you will create a macro in one of your public header files, whose\nvalue will be your new custom error code.  If this is the case, you can use the\nmacro name itself to create the hash value for the error code.  This is what we\ndo for the non-POSIX builtin errors; for instance, the value of the\n:c:macro:`CORK_PARSE_ERROR` error code macro is the hash of the string\n``CORK_PARSE_ERROR``.\n\nGiven this string, you can produce the error code's hash value using the\n:ref:`cork-hash <cork-hash>` command that's installed with libcork::\n\n  $ cork-hash CORK_PARSE_ERROR\n  0x95dfd3c8\n\nIt's incredibly unlikely that the hash value for your new error code will\nconflict with any other custom hash-based error codes, or with any predefined\nPOSIX ``errno`` values.\n\nWith your macro name and hash value ready, defining the new error code is\nsimple::\n\n  #define CORK_PARSE_ERROR  0x95dfd3c8\n\nYou should also provide a helper macro that makes it easier to report new\ninstances of this error condition::\n\n  #define cork_parse_error(...) \\\n      cork_error_set_printf(CORK_PARSE_ERROR, __VA_ARGS__)\n\n.. type:: uint32_t  cork_error\n\n   An identifier for a particular error condition.  This will either be a\n   predefined POSIX ``errno`` value, or the hash of a unique string describing\n   the error condition.\n\nWith your error class and code defined, you can fill in error instances\nusing :c:func:`cork_error_set_printf` and friends.\n\n\nBuiltin errors\n--------------\n\nIn addition to all of the predefined POSIX ``errno`` values, we also provide\nerror codes for a handful of common error conditions.  You should feel free to\nuse these in your libraries and applications, instead of creating custom error\ncodes, if they apply.\n\n.. macro:: CORK_ERROR_NONE\n\n   A special error code that signals that no error occurred.\n\n.. macro:: CORK_PARSE_ERROR\n\n   The provided input violates the rules of the language grammar or file format\n   (or anything else, really) that you're trying to parse.\n\n   .. function:: void cork_parse_error(const char *format*, ...)\n\n.. macro:: CORK_REDEFINED\n           CORK_UNDEFINED\n\n   Useful when you have a container type that must ensure that there is only one\n   entry for any given key.\n\n   .. function:: void cork_redefined(const char *format*, ...)\n                 void cork_undefined(const char *format*, ...)\n\n.. macro:: CORK_UNKNOWN_ERROR\n\n   Some error occurred, but we don't have any other information about the error.\n\n   .. function:: void cork_unknown_error(void)\n\n      The error description will include the name of the current function.\n\n\nWe also provide some helper functions for setting these built-in errors:\n\n.. function:: void cork_system_error_set(void)\n              void cork_system_error_set_explicit(int err)\n\n   Fills in the current libcork error condition with information from a POSIX\n   ``errno`` value.  The human-readable description of the error will be\n   obtained from the standard ``strerror`` function.  With the ``_explicit``\n   variant, you provide the ``errno`` value directly; for the other variant, we\n   get the error code from the C library's ``errno`` variable.\n\n\n.. function:: void cork_abort(const char \\*fmt, ...)\n\n   Aborts the current program with an error message given by *fmt* and any\n   additional parameters.\n\n.. function:: void cork_unreachable(void)\n\n   Aborts the current program with a message indicating that the code path\n   should be unreachable.  This can be useful in the ``default`` clause of a\n   ``switch`` statement if you can ensure that one of the non-``default``\n   branches will always be selected.\n"
  },
  {
    "path": "docs/old/files.rst",
    "content": ".. _files:\n\n*********************\nFiles and directories\n*********************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/os.h>\n\nThe functions in this section let you interact with files and directories in the\nlocal filesystem.\n\n\nPaths\n=====\n\nWe provide several functions for constructing and handling paths into the local\nfilesystem.\n\n.. type:: struct cork_path\n\n   Represents a path in the local filesystem.  The path can be relative or\n   absolute.  The paths don't have to refer to existing files or directories.\n\n.. function:: struct cork_path \\*cork_path_new(const char \\*path)\n              struct cork_path \\*cork_path_clone(const struct cork_path \\*other)\n\n   Construct a new path object from the given path string, or as a copy of\n   another path object.\n\n.. function:: void cork_path_free(struct cork_path \\*path)\n\n   Free a path object.\n\n.. function:: const char \\*cork_path_get(const struct cork_path \\*path)\n\n   Return the string content of a path.  This is not normalized in any way.  The\n   result is guaranteed to be non-``NULL``, but may refer to an empty string.\n   The return value belongs to the path object; you must not modify the contents\n   of the string, nor should you try to free the underlying memory.\n\n.. function:: struct cork_path \\*cork_path_absolute(const struct cork_path \\*other)\n              int cork_path_make_absolute(struct cork_path \\path)\n\n   Convert a relative path into an absolute path.  The first variant constructs\n   a new path object to hold the result; the second variant overwritesthe\n   contents of *path*.\n\n   If there is a problem obtaining the current working directory, these\n   functions will return an error condition.\n\n.. function:: struct cork_path \\*cork_path_join(const struct cork_path \\*path, const char \\*more)\n              struct cork_path \\*cork_path_join_path(const struct cork_path \\*path, const struct cork_path \\*more)\n              void \\*cork_path_append(struct cork_path \\path, const char \\*more)\n              void \\*cork_path_append_path(struct cork_path \\*path, const struct cork_path \\*more)\n\n   Concatenate two paths together.  The ``join`` variants create a new path\n   object containing the concatenated results.  The ``append`` variants\n   overwrite the contents of *path* with the concatenated results.\n\n\n.. function:: struct cork_path \\*cork_path_basename(const struct cork_path \\*path)\n              void \\*cork_path_set_basename(struct cork_path \\*path)\n\n   Extract the base name of *path*.  This is the portion after the final\n   trailing slash.  The first variant constructs a new path object to hold the\n   result; the second variant overwritesthe contents of *path*.\n\n   .. note::\n\n      These functions return a different result than the standard\n      ``basename(3)`` function.  We consider a trailing slash to be significant,\n      whereas ``basename(3)`` does not::\n\n          basename(\"a/b/c/\") == \"c\"\n          cork_path_basename(\"a/b/c/\") == \"\"\n\n.. function:: struct cork_path \\*cork_path_dirname(const struct cork_path \\*path)\n              void \\*cork_path_set_dirname(struct cork_path \\*path)\n\n   Extract the directory name of *path*.  This is the portion before the final\n   trailing slash.  The first variant constructs a new path object to hold the\n   result; the second variant overwritesthe contents of *path*.\n\n   .. note::\n\n      These functions return a different result than the standard ``dirname(3)``\n      function.  We consider a trailing slash to be significant, whereas\n      ``dirname(3)`` does not::\n\n          dirname(\"a/b/c/\") == \"a/b\"\n          cork_path_dirname(\"a/b/c/\") == \"a/b/c\"\n\n\nLists of paths\n==============\n\n.. type:: struct cork_path_list\n\n   A list of paths in the local filesystem.\n\n.. function:: struct cork_path_list \\*cork_path_list_new_empty(void)\n              struct cork_path_list \\*cork_path_list_new(const char \\*list)\n\n   Create a new list of paths.  The first variant creates a list that is\n   initially empty.  The second variant takes in a colon-separated list of paths\n   as a single string, and adds each of those paths to the new list.\n\n.. function:: void cork_path_list_free(struct cork_path_list \\*list)\n\n   Free a path list.\n\n.. function:: void cork_path_list_add(struct cork_path_list \\*list, struct cork_path \\*path)\n\n   Add *path* to *list*.  The list takes control of the path instance; you must\n   not try to free *path* yourself.\n\n.. function:: size_t cork_path_list_size(const struct cork_path_list \\*list)\n\n   Return the number of paths in *list*.\n\n.. function:: const struct cork_path \\*cork_path_list_get(const struct cork_path_list \\*list, size_t index)\n\n   Return the path in *list* at the given *index*.  The list still owns the path\n   instance that's returned; you must not try to free it or modify its contents.\n\n.. function:: const char \\*cork_path_list_to_string(const struct cork_path_list \\*list)\n\n   Return a string containing all of the paths in *list* separated by colons.\n\n\n.. function:: struct cork_file \\*cork_path_list_find_file(const struct cork_path_list \\*list, const char \\*rel_path)\n              struct cork_file_list \\*cork_path_list_find_files(const struct cork_path_list \\*list, const char \\*rel_file)\n\n   Search for a file in a list of paths.  *rel_path* gives the path of the\n   sought-after file, relative to each of the directories in *list*.\n\n   The first variant returns a :c:type:`cork_file` instance for the first match.\n   In no file can be found, it returns ``NULL`` and sets an error condition.\n\n   The second variant returns a :c:type:`cork_file_list` instance containing all\n   of the matches.  In no file can be found, we return an empty list.  (Unlike\n   the first variant, this is not considered an error.)\n\n\nStandard paths\n==============\n\n.. function:: struct cork_path \\*cork_path_home(void)\n\n   Return a :c:type:`cork_path` that refers to the current user's home\n   directory.  If we can't determine the current user's home directory, we set\n   an error condition and return ``NULL``.\n\n   On POSIX systems, this directory is determined by the ``HOME`` environment\n   variable.\n\n.. function:: struct cork_path_list \\*cork_path_config_paths(void)\n\n   Return a :c:type:`cork_path_list` that includes all of the standard\n   directories that can be used to store configuration files.  This includes a\n   user-specific directory that allows the user to override any global\n   configuration files.\n\n   On POSIX systems, these directories are defined XDG Base Directory\n   Specification.\n\n.. function:: struct cork_path_list \\*cork_path_data_paths(void)\n\n   Return a :c:type:`cork_path_list` that includes all of the standard\n   directories that can be used to store application data files.  This includes\n   a user-specific directory that allows the user to override any global data\n   files.\n\n   On POSIX systems, these directories are defined XDG Base Directory\n   Specification.\n\n.. function:: struct cork_path \\*cork_path_user_cache_path(void)\n\n   Return a :c:type:`cork_path` that refers to a directory that can be used to\n   store cache files created on behalf of the current user.  This directory\n   should only be used to store data that you can reproduce if needed.\n\n   On POSIX systems, these directories are defined XDG Base Directory\n   Specification.\n\n.. function:: struct cork_path \\*cork_path_user_runtime_path(void)\n\n   Return a :c:type:`cork_path` that refers to a directory that can be used to\n   store small runtime management files on behalf of the current user.\n\n   On POSIX systems, these directories are defined XDG Base Directory\n   Specification.\n\n\nFiles\n=====\n\n.. type:: struct cork_file\n\n   Represents a file on the local filesystem.  The file in question does not\n   necessarily have to exist; you can use :c:type:`cork_file` instances to refer\n   to files that you have not yet created, for instance.\n\n.. type:: typedef unsigned int  cork_file_mode\n\n   Represents a Unix-style file permission set.\n\n\n.. function:: struct cork_file \\*cork_file_new(const char \\*path)\n              struct cork_file \\*cork_file_new_from_path(struct cork_path \\*path)\n\n   Create a new :c:type:`cork_file` instance to represent the file with the\n   given *path*.  The ``_from_path`` variant uses an existing\n   :c:type:`cork_path` instance to specify the path.  The new file instance will\n   take control of the :c:type`cork_path` instance, so you should not try to\n   free it yourself.\n\n.. function:: void cork_file_free(struct cork_file \\*file)\n\n   Free a file instance.\n\n.. function:: const struct cork_path \\*cork_file_path(struct cork_file \\*file)\n\n   Return the path of a file.  The :c:type:`cork_path` instance belongs to the\n   file; you must not try to modify or free the path instance.\n\n.. function:: int cork_file_exists(struct cork_file \\*file, bool \\*exists)\n\n   Check whether a file exists in the filesystem, storing the result in\n   *exists*.  The function returns an error condition if we are unable to\n   determine whether the file exists --- for instance, because you do not have\n   permission to look into one of the containing directories.\n\n.. function:: int cork_file_type(struct cork_file \\*file, enum cork_file_type \\*type)\n\n   Return what kind of file the given :c:type:`cork_file` instance refers to.\n   The function returns an error condition if there is an error accessing the\n   file --- for instance, because you do not have permission to look into one of\n   the containing directories.\n\n   If the function succeeds, it will fill in *type* with one of the following\n   values:\n\n   .. type:: enum cork_file_type\n\n      .. member:: CORK_FILE_MISSING\n\n         *file* does not exist.\n\n      .. member:: CORK_FILE_REGULAR\n\n         *file* is a regular file.\n\n      .. member:: CORK_FILE_DIRECTORY\n\n         *file* is a directory.\n\n      .. member:: CORK_FILE_SYMLINK\n\n         *file* is a symbolic link.\n\n      .. member:: CORK_FILE_UNKNOWN\n\n         We can access *file*, but we do not know what type of file it is.\n\n\n.. function:: int cork_file_remove(struct cork_file \\*file, unsigned int flags)\n\n   Remove *file* from the filesystem.  *flags* must be the bitwise OR (``|``) of\n   the following flags.  (Use ``0`` if you do not want any of the flags.)\n\n   .. macro:: CORK_FILE_PERMISSIVE\n\n      If this flag is given, then it is not considered an error if *file* does\n      not exist.  If the flag is not given, then the function function returns\n      an error if *file* doesn't exist.  (This mimics the standard ``rm -f``\n      command.)\n\n   .. macro:: CORK_FILE_RECURSIVE\n\n      If this flag is given, and *file* refers to a directory, then the function\n      will automatically remove the directory and all of its contents.  If the\n      flag is not given, and *file* refers to a directory, then the directory\n      must be empty for this function to succeed.  If *file* does not refer to a\n      directory, this flag has no effect.  (This mimics the standard ``rmdir\n      -r`` command.)\n\n\nDirectories\n===========\n\nCertain functions can only be applied to a :c:type:`cork_file` instance that\nrefers to a directory.\n\n\n.. function:: int cork_file_mkdir(struct cork_file \\*directory, cork_file_mode mode, unsigned int flags)\n\n   Create a new directory in the filesystem, with permissions given by *mode*.\n   *flags* must be the bitwise OR (``|``) of the following flags.  (Use ``0`` if\n   you do not want any of the flags.)\n\n   .. macro:: CORK_FILE_PERMISSIVE\n\n      If this flag is given, then it is not considered an error if *directory*\n      already exists.  If the flag is not given, then the function function\n      returns an error if *directory* exists.  (This mimics part of the standard\n      ``mkdir -p`` command.)\n\n   .. macro:: CORK_FILE_RECURSIVE\n\n      If this flag is given, then the function will ensure that all of the\n      parent directories of *directory* exist, creating them if necessary.  Each\n      directory created will have permissions given by *mode*.  (This mimics\n      part of the standard ``mkdir -p`` command.)\n\n\n.. function:: int cork_file_iterate_directory(struct cork_file \\*directory, cork_file_directory_iterator iterator, void \\*user_data)\n\n   Call *iterator* for each file or subdirectory contained in *directory* (not\n   including the directory's ``.`` and ``..`` entries).  This function does not\n   recurse into any subdirectories; it only iterates through the immediate\n   children of *directory*.\n\n   If your iteration function returns a non-zero result, we will abort the\n   iteration and return that value.  Otherwise, if each call to the iteration\n   function returns ``0``, then we will return ``0`` as well.\n\n   *iterator* must be an instance of the following function type:\n\n   .. type:: typedef int (\\*cork_file_directory_iterator)(struct cork_file \\*child, const char \\*rel_name, void \\*user_data)\n\n      Called for each child entry in *directory*.  *child* will be a file\n      instance referring to the child entry.  *rel_name* gives the relative name\n      of the child entry within its parent *directory*.\n\n\nLists of files\n==============\n\n.. type:: struct cork_file_list\n\n   A list of files in the local filesystem.\n\n.. function:: struct cork_file_list \\*cork_file_list_new_empty(void)\n              struct cork_file_list \\*cork_file_list_new(struct cork_path_list \\*path_list)\n\n   Create a new list of files.  The first variant creates a list that is\n   initially empty.  The second variant adds a new file instance for each of the\n   paths in *path_list*.\n\n.. function:: void cork_file_list_free(struct cork_file_list \\*list)\n\n   Free a file list.\n\n.. function:: void cork_file_list_add(struct cork_file_list \\*list, struct cork_file \\*file)\n\n   Add *file* to *list*.  The list takes control of the file instance; you must\n   not try to free *file* yourself.\n\n.. function:: size_t cork_file_list_size(const struct cork_file_list \\*list)\n\n   Return the number of files in *list*.\n\n.. function:: struct cork_file \\*cork_file_list_get(const struct cork_file_list \\*list, size_t index)\n\n   Return the file in *list* at the given *index*.  The list still owns the file\n   instance that's returned; you must not try to free it.\n\n\n\nDirectory walking\n=================\n\n.. function:: int cork_walk_directory(const char \\*path, struct cork_dir_walker \\*walker)\n\n   Walk through the contents of a directory.  *path* can be an absolute or\n   relative path.  If it's relative, it will be interpreted relative to the\n   current directory.  If *path* doesn't exist, or there are any problems\n   reading the contents of the directory, we'll set an error condition and\n   return ``-1``.\n\n   To process the contents of the directory, you must provide a *walker* object,\n   which contains several callback methods that we will call when files and\n   subdirectories of *path* are encountered.  Each method should return ``0`` on\n   success.  Unless otherwise noted, if we receive any other return result, we\n   will abort the directory walk, and return that same result from the\n   :c:func:`cork_walk_directory` call itself.\n\n   In all of the following methods, *base_name* will be the base name of the\n   entry within its immediate subdirectory.  *rel_path* will be the relative\n   path of the entry within the *path* that you originally asked to walk\n   through.  *full_path* will the full path to the entry, including *path*\n   itself.\n\n   .. type:: struct cork_dir_walker\n\n      .. member:: int (\\*file)(struct cork_dir_walker \\*walker, const char \\*full_path, const char \\*rel_path, const char \\*base_name)\n\n         Called when a regular file is encountered.\n\n      .. member:: int (\\*enter_directory)(struct cork_dir_walker \\*walker, const char \\*full_path, const char \\*rel_path, const char \\*base_name)\n\n         Called when a subdirectory of *path* of encountered.  If you don't want\n         to recurse into this directory, return :c:data:`CORK_SKIP_DIRECTORY`.\n\n         .. macro:: CORK_SKIP_DIRECTORY\n\n      .. member:: int (\\*leave_directory)(struct cork_dir_walker \\*walker, const char \\*full_path, const char \\*rel_path, const char \\*base_name)\n\n         Called when a subdirectory has been fully processed.\n"
  },
  {
    "path": "docs/old/gc.rst",
    "content": ".. _gc:\n\n************************************\nReference-counted garbage collection\n************************************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThe functions in this section implement a reference counting garbage\ncollector.  The garbage collector handles reference cycles correctly.\nIt is **not** a conservative garbage collector — i.e., we don't assume\nthat every word inside an object might be a pointer.  Instead, each\ngarbage-collected object must provide a *recursion function* that knows\nhow to delve down into any child objects that it references.\n\nThe garbage collector is **not** thread-safe.  If your application is\nmulti-threaded, each thread will (automatically) have its own garbage\ncollection context.  There are two strategies that you can use when\nusing the garbage collector in a multi-threaded application:\n\n* Have a single “master” thread be responsible for the lifecycle of\n  every object.  This thread is the only one allowed to interact with\n  the garbage collector.  **No** other threads are allowed to call any\n  of the functions in this section, including the\n  :c:func:`cork_gc_incref()` and :c:func:`cork_gc_decref()` functions.\n  Other threads are allowed to access the objects that are managed by\n  the garbage collector, but the master thread must ensure that all\n  objects are live whenever another thread attempts to use them.  This\n  will require some kind of thread-safe communication or synchronization\n  between the master thread and the worker threads.\n\n* Have a separate garbage collector per thread.  Each object is “owned”\n  by a single thread, and the object is managed by that thread's garbage\n  collector.  As with the first strategy, other threads can use any\n  object, as long as the object's owner thread is able to guarantee that\n  the object will be live for as long as it's needed.  (Eventually we'll\n  also support migrating an object from one garbage collector to\n  another, but that feature isn't currently implemented.)\n\nThe garbage collection implementation is based on the algorithm\ndescribed in §3 of [1]_.\n\n.. [1] Bacon, DF and Rajan VT.  *Concurrent cycle collection in\n   reference counted systems*.  Proc. ECOOP 2001.  LNCS 2072.\n\n\nCreating a garbage collector\n============================\n\n.. function:: void cork_gc_init(void)\n\n   Initalizes a garbage collection context for the current thread.\n   Usually, you can allocate this on the stack of your ``main``\n   function::\n\n     int\n     main(int argc, char ** argv)\n     {\n         cork_gc_init();\n\n         // use the GC context\n\n         // and free it when you're done\n         cork_gc_done();\n     }\n\n   It's not required that you call this function at all; if you don't,\n   we'll automatically initialize a garbage collection context for the\n   current thread the first time you try to allocate a garbage-collected\n   object.  You can call this function, though, if you want to have more\n   control over when the initialization occurs.\n\n.. function:: void cork_gc_done(void)\n\n   Finalize the garbage collection context for the current thread.  All\n   objects created in this thread will be freed when this function\n   returns.\n\n   You must call this function in each thread that allocates\n   garbage-collected objects, just before that thread finishes.  (If\n   your application is single-threaded, then you must call this function\n   before the ``main`` function finishes.)  If you don't, you'll almost\n   certainly get memory leaks.\n\n\nManaging garbage-collected objects\n==================================\n\nA garbage collection context can't be used to manage arbitrary objects,\nsince each garbage-collected class must define some callback functions\nfor interacting with the garbage collector.  (The :ref:`next section\n<new-gc-class>` contains more details.)\n\nEach garbage-collected class will provide its own constructor function\nfor instantiating a new instance of that class.  There aren't any\nexplicit destructors for garbage-collected objects; instead you manage\n“references” to the objects.  Each pointer to a garbage-collected object\nis a reference, and each object maintains a count of the references to\nitself.  A newly constructed object starts with a reference count of\n``1``.  Whenever you save a pointer to a garbage-collected object, you\nshould increase the object's reference count.  When you're done with the\npointer, you decrease its reference count.  When the reference count\ndrops to ``0``, the garbage collector frees the object.\n\n.. function:: void \\*cork_gc_incref(void \\*obj)\n\n   Increments the reference count of an object *obj* that is managed by\n   the current thread's garbage collector.  We always return *obj* as a\n   result, which allows you to use the following idiom::\n\n     struct my_obj * my_copy_of_obj = cork_gc_incref(obj);\n\n.. function:: void cork_gc_decref(void \\*obj)\n\n   Decrements the reference count of an object *obj* that is managed by\n   the current thread's garbage collector  If the reference count drops\n   to ``0``, then the garbage collector will free the object.\n\n   .. note::\n\n      It's safe to call this function with a ``NULL`` *obj* pointer; in\n      this case, the function acts as a no-op.\n\n.. _borrow-ref:\n\nBorrowing a reference\n---------------------\n\nWhile the strategy mentioned above implies that you should call\n:c:func:`cork_gc_incref()` and :c:func:`cork_gc_decref()` for *every*\npointer to a garbage-collected object, you can sometimes get away\nwithout bumping the reference count.  In particular, you can often\n*borrow* an existing reference to an object, if you can guarantee that\nthe borrowed reference will exist for as long as you need access to the\nobject.  The most common example of this when you pass in a\ngarbage-collected object as the parameter to a function::\n\n  int\n  use_new_reference(struct my_obj *obj)\n  {\n      /* Here we're being pedantically correct, and incrementing obj's\n       * reference count since we've got our own pointer to the object. */\n      cork_gc_incref(obj);\n\n      /* Do something useful with obj */\n\n      /* And now that we're done with it, decrement the reference count. */\n      cork_gc_decref(obj);\n  }\n\n  int\n  borrowed_reference(struct my_obj *obj)\n  {\n      /* We can assume that the caller has a valid reference to obj, so\n       * we're just going to borrow that reference. */\n\n      /* Do something useful with obj */\n  }\n\nIn this example, ``borrowed_reference`` doesn't need to update *obj*\\ 's\nreference count.  We assume that the caller has a valid reference to\n*obj* when it makes the call to ``borrowed_reference``.  Moreover, we\nknow that the caller can't possibly release this reference (via\n:c:func:`cork_gc_decref()`) until ``borrowed_reference`` returns.  Since\nwe can guarantee that the caller's reference to *obj* will exist for the\nentire duration of ``borrowed_reference``, we don't need to protect it\nwith an ``incref``/``decref`` pair.\n\n.. _steal-ref:\n\nStealing a reference\n--------------------\n\nAnother common pattern is for a “parent” object to maintain a reference\nto a “child” object.  (For example, a container class might maintain\nreferences to all of the elements in the container, assuming that the\ncontainer and elements are all garbage-collected objects.)  When you\nhave a network of objects like this, the parent object's constructor\nwill usually take in a pointer to the child object as a parameter.  If\nwe strictly follow the basic referencing counting rules described above,\nyou'll end up with something like::\n\n  struct child  *child = child_new();\n  struct parent  *parent = parent_new(child);\n  cork_gc_decref(child);\n\nThe ``child_new`` constructor gives us a reference to *child*.  The\n``parent_new`` constructor then creates a new reference to *child*,\nwhich will be stored somewhere in *parent*.  We no longer need our own\nreference to *child*, so we immediately decrement its reference count.\n\nThis is a common enough occurrence that many constructor functions will\ninstead *steal* the reference passed in as a parameter.  This means that\nthe constructor takes control of the caller's reference.  This allows us\nto rewrite the example as::\n\n  struct parent  *parent = parent_new_stealing(child_new());\n\nFor functions that steal a reference, the caller **cannot** assume that\nthe object pointed to by the stolen reference exists when the function\nreturns.  (If there's an error in ``parent_new_stealing``, for instance,\nit must release the stolen reference to *child* to prevent a memory\nleak.)  If a function is going to steal a reference, but you also need\nto use the object after the function call returns, then you need to\nexplicitly increment the reference count *before* calling the function::\n\n  struct child  *child = child_new();\n  struct parent  *parent = parent_new_stealing(cork_gc_incref(child));\n  /* Do something with child. */\n  /* And then release our reference when we're done. */\n  cork_gc_decref(child);\n\n.. note::\n\n   It's important to point out that not every constructor will steal the\n   references passed in as parameters.  Moreover, there are some\n   constructors that steal references for some parameters but not for\n   others.  It entirely depends on what the “normal” use case is for the\n   constructor.  If you're almost always going to pass in a child object\n   that was just created, and that will always be accessed via the\n   parent, then the constructor will usually steal the reference.  If\n   the child can be referenced by many parents, then the constructor\n   will usually *not* steal the reference.  The documentation for each\n   constructor function will explicitly state which references are\n   stolen and which objects it creates new references for.\n\n\n.. _new-gc-class:\n\nWriting a new garbage-collected class\n=====================================\n\nWhen you are creating a new class that you want to be managed by a\ngarbage collector, there are two basic steps you need to follow:\n\n* Implement a set of callback functions that allow the garbage collector\n  to interact with objects of the new class.\n\n* Use the garbage collector's allocation functions to allocate storage\n  for instance of your class.\n\nYou won't need to write a public destructor function, since objects of\nthe new class will be destroyed automatically when the garbage collector\ndetermines that they're no longer needed.\n\nGarbage collector callback interface\n------------------------------------\n\nEach garbage-collected class must provide an implementation of the\n“callback interface”:\n\n.. type:: struct cork_gc_obj_iface\n\n   .. member:: void (\\*free)(void \\*obj)\n\n      This callback is called when a garbage-collected object is about\n      to be freed.  You can perform any special cleanup steps in this\n      callback.  You do **not** need to deallocate the object's storage,\n      and you do **not** need to release any references that you old to\n      other objects.  Both of these steps will be taken care of for you\n      by the garbage collector.\n\n      If your class doesn't need any additional finalization steps, this\n      entry in the callback interface can be ``NULL``.\n\n   .. member:: void (\\*recurse)(struct cork_gc \\*gc, void \\*obj, cork_gc_recurser recurse, void \\*ud)\n\n      This callback is how you inform the garbage collector of your\n      references to other garbage-collected objects.\n\n      The garbage collector will call this function whenever it needs to\n      traverse through a graph of object references.  Your\n      implementation of this callback should just call *recurse* with\n      each garbage-collected object that you hold a reference to.  You\n      must pass in *gc* as the first parameter to each call to\n      *recurse*, and *ud* as the third parameter.\n\n      Note that it's fine to call *recurse* with a ``NULL`` object\n      pointer, which makes it slightly easier to write implementations\n      of this callback.\n\n      If instances of your class can never contain references to other\n      garbage-collected objects, this entry in the callback interface\n      can be ``NULL``.\n\n.. type:: void (\\*cork_gc_recurser)(struct cork_gc \\*gc, void \\*obj, void \\*ud)\n\n   An opaque callback provided by the garbage collector when it calls an\n   object's :c:member:`~cork_gc_obj_iface.recurse` method.\n\n.. type:: struct cork_gc\n\n   An opaque type representing the current thread's garbage-collection\n   context.  You'll only need to use this type when implementing a\n   :c:member:`~cork_gc_obj_iface.recurse` function.\n\n\n.. _gc-macros:\n\nHelper macros\n~~~~~~~~~~~~~\n\nThere are several macros declared in :file:`libcork/helpers/gc.h` that\nmake it easier to define the garbage-collection interface for a new\nclass.\n\n.. note::\n\n   Unlike most libcork modules, these macros are **not** automatically\n   defined when you include the ``libcork/core.h`` header file, since\n   they don't include a ``cork_`` prefix.  Because of this, we don't\n   want to pollute your namespace unless you ask for the macros.  To do\n   so, you must explicitly include their header file::\n\n     #include <libcork/helpers/gc.h>\n\n.. macro:: _free_(SYMBOL name)\n           _recurse_(SYMBOL name)\n\n   These macros declare the *free* and *recurse* methods for a new\n   class.  The functions will be declared with exactly the signatures\n   and parameter names shown in the entries for the\n   :c:member:`~cork_gc_obj_iface.free` and\n   :c:member:`~cork_gc_obj_iface.recurse` methods.\n\n   You will almost certainly not need to refer to the method\n   implementations directly, since you can use the :c:macro:`_gc_*_\n   <_gc_>` macros below to declare the interface struct.  But if you do,\n   they'll be called :samp:`{[name]}__free` and\n   :samp:`{[name]}__recurse`.  (Note the double underscore.)\n\n.. macro:: _gc_(SYMBOL name)\n           _gc_no_free_(SYMBOL name)\n           _gc_no_recurse_(SYMBOL name)\n           _gc_leaf_(SYMBOL name)\n\n   Define the garbage-collection interface struct for a new class.  If\n   you defined both ``free`` and ``recurse`` methods, you should use the\n   ``_gc_`` variant.  If you only defined one of the methods, you should\n   use ``_gc_no_free_`` or ``_gc_no_recurse_``.  If you didn't define\n   either method, you should use ``_gc_free_``.\n\n   Like the method definitions, you probably won't need to refer to the\n   interface struct directly, since you can use the\n   :c:func:`cork_gc_new` macro to allocate new instances of the new\n   class.  But if you do, it will be called :samp:`{[name]}__gc`.  (Note\n   the double underscore.)\n\n\nAs an example, we can use these macros to define a new tree class::\n\n    #include <libcork/helpers/gc.h>\n\n    struct tree {\n        const char  *name;\n        struct tree  *left;\n        struct tree  *right;\n    };\n\n    _free_(tree) {\n        struct tree  *self = obj;\n        cork_strfree(self->name);\n    }\n\n    _recurse_(tree) {\n        struct tree  *self = obj;\n        recurse(self->left, ud);\n        recurse(self->right, ud);\n    }\n\n    _gc_(tree);\n\n\nAllocating new garbage-collected objects\n----------------------------------------\n\nIn your garbage-collected class's constructor, you must use one of the\nfollowing functions to allocate the object's storage.  (The garbage\ncollector hides some additional state in the object's memory region, so\nyou can't allocate the storage using ``malloc`` or :c:func:`cork_new()`\ndirectly.)\n\n.. function:: void \\*cork_gc_alloc(size_t instance_size, struct cork_gc_obj_iface \\*iface)\n\n   Allocates a new garbage-collected object that is *instance_size*\n   bytes large.  *iface* should be a pointer to a callback interface for\n   the object.  If there are any problems allocating the new instance,\n   the program will abort.\n\n.. function:: type \\*cork_gc_new_iface(TYPE type, struct cork_gc_obj_iface \\*iface)\n\n   Allocates a new garbage-collected instance of *type*.  The size of\n   the memory region to allocate is calculated using the ``sizeof``\n   operator, and the result will be automatically cast to ``type *``.\n   *iface* should be a pointer to a callback interface for the object.\n   If there are any problems allocating the new instance, the program\n   will abort.\n\n.. function:: struct name \\*cork_gc_new(SYMBOL name)\n\n   Allocates a new garbage-collected instance of :samp:`struct\n   {[name]}`.  (Note that you don't pass in the ``struct`` part of the\n   type name.) We assume that the garbage collection interface was\n   created using one of the :c:macro:`_gc_*_ <_gc_>` macros, using the\n   same *name* parameter.\n\nUsing these functions, could instantiate our example tree class as\nfollows::\n\n    struct tree *\n    tree_new(const char *name)\n    {\n        struct tree  *self = cork_gc_new(tree);\n        self->name = cork_strdup(name);\n        self->left = NULL;\n        self->right = NULL;\n        return self;\n    }\n"
  },
  {
    "path": "docs/old/hash-table.rst",
    "content": ".. _hash-table:\n\n***********\nHash tables\n***********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines a hash table class.  Our hash table implementation\nis based on the public domain hash table package written in the late\n1980's by Peter Moore at UC Berkeley.\n\nThe keys and values of a libcork hash table are both represented by ``void *``\npointers.  You can also store integer keys or values, as long as you use the\n:c:type:`intptr_t` or :c:type:`uintptr_t` integral types.  (These are the only\ninteger types guaranteed by the C99 standard to fit within the space used by a\n``void *``.)  The keys of the hash table can be any arbitrary type; you must\nprovide two functions that control how key pointers are used to identify entries\nin the table: the *hasher* (:c:type:`cork_hash_f`) and the *comparator*\n(:c:type:`cork_equals_f`).  It's your responsibility to ensure that these two\nfunctions are consistent with each other — i.e., if two keys are equal according\nto your comparator, they must also map to the same hash value.  (The inverse\ndoesn't need to be true; it's fine for two keys to have the same hash value but\nnot be equal.)\n\n.. type:: struct cork_hash_table\n\n   A hash table.\n\n.. function:: struct cork_hash_table \\*cork_hash_table_new(size_t initial_size, unsigned int flags)\n\n   Creates a new hash table instance.\n\n   If you know roughly how many entries you're going to add to the hash\n   table, you can pass this in as the *initial_size* parameter.  If you\n   don't know how many entries there will be, you can use ``0`` for this\n   parameter instead.\n\n   You will most likely need to provide a hashing function and a comparison\n   function for the new hash table (using :c:func:`cork_hash_table_set_hash` and\n   :c:func:`cork_hash_table_set_equals`), which will be used to compare key\n   values of the entries in the table.  If you do not provide your own\n   functions, the default functions will compare key pointers as-is without\n   interpreting what they point to.\n\n   The *flags* field is currently unused, and should be ``0``.  In the future,\n   this parameter will be used to let you customize the behavior of the hash\n   table.\n\n\n.. function:: void cork_hash_table_free(struct cork_hash_table \\*table)\n\n   Frees a hash table.  If you have provided a :c:func:`free_key\n   <cork_hash_table_set_free_key>` or :c:func:`free_value\n   <cork_hash_table_set_free_value>` callback for *table*, then we'll\n   automatically free any remaining keys and/or values.\n\n\n.. type:: struct cork_hash_table_entry\n\n   The contents of an entry in a hash table.\n\n   .. member:: void  \\*key\n\n      The key for this entry.  There won't be any other entries in the\n      hash table with the same key, as determined by the comparator\n      function that you provide.\n\n   .. member:: void  \\*value\n\n      The value for this entry.  The entry's value is completely opaque\n      to the hash table; we'll never need to compare or interrogate the\n      values in the table.\n\n   .. member:: cork_hash  hash\n\n      The hash value for this entry's key.  This field is strictly\n      read-only.\n\n\nCallback functions\n------------------\n\nYou can use the callback functions in this section to customize the behavior of\na hash table.\n\n.. function:: void cork_hash_table_set_user_data(struct cork_hash_table \\*table, void \\*user_data, cork_free_f free_user_data)\n\n   Lets you provide an opaque *user_data* pointer to each of the hash table's\n   callbacks.  This lets you provide additional state, other than the hash table\n   itself to those callbacks.  If *free_user_data* is not ``NULL``, then the\n   hash table will take control of *user_data*, and will use the\n   *free_user_data* function to free it when the hash table is destroyed.\n\n\nKey management\n~~~~~~~~~~~~~~\n\n.. function:: void cork_hash_table_set_hash(struct cork_hash_table \\*table, void \\*user_data, cork_hash_f hash)\n\n   The hash table will use the ``hash`` callback to calculate a hash value for\n   each key.\n\n   .. type:: cork_hash (\\*cork_hash_f)(void \\*user_data, const void \\*key)\n\n      .. note::\n\n         It's important to use a hash function that has a uniform distribution\n         of hash values for the set of values you expect to use as hash table\n         keys.  In particular, you *should not* rely on there being a prime\n         number of hash table bins to get the desired uniform distribution.  The\n         :ref:`hash value functions <hash-values>` that we provide have uniform\n         distribution (and are fast), and should be safe to use for most key\n         types.\n\n.. function:: void cork_hash_table_set_equals(struct cork_hash_table \\*table, void \\*user_data, cork_equals_f equals)\n\n   The hash table will use the ``equals`` callback to compare keys.\n\n   .. type:: bool (\\*cork_equals_f)(void \\*user_data, const void \\*key1, const void \\*key2)\n\n\nBuilt-in key types\n~~~~~~~~~~~~~~~~~~\n\nWe also provide a couple of specialized constructors for common key types, which\nprevents you from having to duplicate common hashing and comparison functions.\n\n.. function:: struct cork_hash_table \\*cork_string_hash_table_new(size_t initial_size, unsigned int flags)\n\n   Create a hash table whose keys will be C strings.\n\n.. function:: struct cork_hash_table \\*cork_pointer_hash_table_new(size_t initial_size, unsigned int flags)\n\n   Create a hash table where keys should be compared using standard pointer\n   equality.  (In other words, keys should only be considered equal if they\n   point to the same physical object.)\n\n\nAutomatically freeing entries\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. function:: void cork_hash_table_set_free_key(struct cork_hash_table \\*table, void \\*user_data, cork_free_f free_key)\n              void cork_hash_table_set_free_value(struct cork_hash_table \\*table, void \\*user_data, cork_free_f free_value)\n\n   If you provide ``free_key`` and/or ``free_value`` callbacks, then the hash\n   table will take ownership of any keys and values that you add.  The hash\n   table will use these callbacks to free each key and value when entries are\n   explicitly deleted (via :c:func:`cork_hash_table_delete` or\n   :c:func:`cork_hash_table_clear`), and when the hash table itself is\n   destroyed.\n\n\nAdding and retrieving entries\n-----------------------------\n\nThere are several functions that can be used to add or retrieve entries\nfrom a hash table.  Each one has slightly different semantics; you\nshould read through them all before deciding which one to use for a\nparticular use case.\n\n.. note::\n\n   Each of these functions comes in two variants.  The “normal” variant will use\n   the hash table's :c:func:`hash <cork_hash_table_set_hash>` callback to\n   calculate the hash value for the *key* parameter.  This is the normal way to\n   interact with a hash table.\n\n   When using the ``_hash`` variant, you must calculate the hash value for each\n   key yourself, and pass in this hash value as an extra parameter.  The hash\n   table's :c:func:`hash <cork_hash_table_set_hash>` callback is not invoked.\n   This can be more efficient, if you've already calculated or cached the hash\n   value.  It is your responsibility to make sure that the hash values you\n   provide are consistent, just like when you write a :c:func:`hash\n   <cork_hash_table_set_hash>` callback.\n\n.. function:: void \\*cork_hash_table_get(const struct cork_hash_table \\*table, const void \\*key)\n              void \\*cork_hash_table_get_hash(const struct cork_hash_table \\*table, cork_hash hash, const void \\*key)\n\n   Retrieves the value in *table* with the given *key*.  We return\n   ``NULL`` if there's no corresponding entry in the table.  This means\n   that, using this function, you can't tell the difference between a\n   missing entry, and an entry that's explicitly mapped to ``NULL``.  If\n   you need to distinguish those cases, you should use\n   :c:func:`cork_hash_table_get_entry()` instead.\n\n.. function:: struct cork_hash_table_entry \\*cork_hash_table_get_entry(const struct cork_hash_table \\*table, const void \\*key)\n              struct cork_hash_table_entry \\*cork_hash_table_get_entry_hash(const struct cork_hash_table \\*table, cork_hash hash, const void \\*key)\n\n   Retrieves the entry in *table* with the given *key*.  We return\n   ``NULL`` if there's no corresponding entry in the table.\n\n   You are free to update the :c:member:`key\n   <cork_hash_table_entry.key>` and :c:member:`value\n   <cork_hash_table_entry.value>` fields of the entry.  However, you\n   must ensure that any new key is considered “equal” to the old key,\n   according to the hasher and comparator functions that you provided\n   for this hash table.\n\n.. function:: struct cork_hash_table_entry \\*cork_hash_table_get_or_create(struct cork_hash_table \\*table, void \\*key, bool \\*is_new)\n              struct cork_hash_table_entry \\*cork_hash_table_get_or_create_hash(struct cork_hash_table \\*table, cork_hash hash, void \\*key, bool \\*is_new)\n\n   Retrieves the entry in *table* with the given *key*.  If there is no\n   entry with the given key, it will be created.  (If we can't create\n   the new entry, we'll return ``NULL``.)  We'll fill in the *is_new*\n   output parameter to indicate whether the entry is new or not.\n\n   If a new entry is created, its value will initially be ``NULL``, but\n   you can update this as necessary.  You can also update the entry's\n   key, though you must ensure that any new key is considered “equal” to\n   the old key, according to the hasher and comparator functions that\n   you provided for this hash table.  This is necessary, for instance,\n   if the *key* parameter that we search for was allocated on the stack.\n   We can't save this stack key into the hash table, since it will\n   disapppear as soon as the calling function finishes.  Instead, you\n   must create a new key on the heap, which can be saved into the entry.\n   For efficiency, you'll only want to allocate this new heap-stored key\n   if the entry is actually new, especially if there will be a lot\n   successful lookups of existing keys.\n\n.. function:: int cork_hash_table_put(struct cork_hash_table \\*table, void \\*key, void \\*value, bool \\*is_new, void \\*\\*old_key, void \\*\\*old_value)\n              int cork_hash_table_put_hash(struct cork_hash_table \\*table, cork_hash hash, void \\*key, void \\*value, bool \\*is_new, void \\*\\*old_key, void \\*\\*old_value)\n\n   Add an entry to a hash table.  If there is already an entry with the\n   given key, we will overwrite its key and value with the *key* and\n   *value* parameters.  If the *is_new* parameter is non-\\ ``NULL``,\n   we'll fill it in to indicate whether the entry is new or already\n   existed in the table.  If the *old_key* and/or *old_value* parameters\n   are non-\\ ``NULL``, we'll fill them in with the existing key and\n   value.  This can be used, for instance, to finalize an overwritten\n   key or value object.\n\n.. function:: void cork_hash_table_delete_entry(struct cork_hash_table \\*table, struct cork_hash_table_entry \\*entry)\n\n   Removes *entry* from *table*.  You must ensure that *entry* refers to a\n   valid, existing entry in the hash table.  This function can be more efficient\n   than :c:func:`cork_hash_table_delete` if you've recently retrieved a hash\n   table entry using :c:func:`cork_hash_table_get_or_create` or\n   :c:func:`cork_hash_table_get_entry`, since we won't have to search for the\n   entry again.\n\n.. function:: bool cork_hash_table_delete(struct cork_hash_table \\*table, const void \\*key, void \\*\\*deleted_key, void \\*\\*deleted_value)\n              bool cork_hash_table_delete_hash(struct cork_hash_table \\*table, cork_hash hash, const void \\*key, void \\*\\*deleted_key, void \\*\\*deleted_value)\n\n   Removes the entry with the given *key* from *table*.  If there isn't\n   any entry with the given key, we'll return ``false``.  If the\n   *deleted_key* and/or *deleted_value* parameters are non-\\ ``NULL``,\n   we'll fill them in with the deleted key and value.  This can be used,\n   for instance, to finalize the key or value object that was stored in\n   the hash table entry.\n\n   If you have provided a :c:func:`free_key <cork_hash_table_set_free_key>` or\n   :c:func:`free_value <cork_hash_table_set_free_value>` callback for *table*,\n   then we'll automatically free the key and/or value of the deleted entry.\n   (This happens before ``cork_hash_table_delete`` returns, so you must not\n   provide a *deleted_key* and/or *deleted_value* in this case.)\n\n\nOther operations\n----------------\n\n.. function:: size_t cork_hash_table_size(const struct cork_hash_table \\*table)\n\n   Returns the number of entries in a hash table.\n\n.. function:: void cork_hash_table_clear(struct cork_hash_table \\*table)\n\n   Removes all of the entries in a hash table, without finalizing the\n   hash table itself.\n\n   If you have provided a :c:func:`free_key <cork_hash_table_set_free_key>` or\n   :c:func:`free_value <cork_hash_table_set_free_value>` callback for *table*,\n   then we'll automatically free any remaining keys and/or values.\n\n.. function:: int cork_hash_table_ensure_size(struct cork_hash_table \\*table, size_t desired_count)\n\n   Ensures that *table* has enough space to efficiently store a certain\n   number of entries.  This can be used to reduce (or eliminate) the\n   number of resizing operations needed to add a large number of entries\n   to the table, when you know in advance roughly how many entries there\n   will be.\n\n\nIterating through a hash table\n------------------------------\n\nThere are two strategies you can use to access all of the entries in a\nhash table: *mapping* and *iterating*.\n\n\nIteration order\n~~~~~~~~~~~~~~~\n\nRegardless of whether you use the mapping or iteration functions, we guarantee\nthat the collection of items will be processed in the same order that they were\nadded to the hash table.\n\n\nMapping\n~~~~~~~\n\nWith mapping, you write a mapping function that will be applied to each entry in\nthe table.  (In this case, libcork controls the loop that steps through each\nentry.)\n\n.. function:: void cork_hash_table_map(struct cork_hash_table \\*table, void \\*user_data, cork_hash_table_map_f map)\n\n   Applies the *map* function to each entry in a hash table.  The *map*\n   function's :c:type:`cork_hash_table_map_result` return value can be used to\n   influence the iteration.\n\n   .. type:: enum cork_hash_table_map_result (\\*cork_hash_table_map_f)(void \\*user_data, struct cork_hash_table_entry \\*entry)\n\n      The function that will be applied to each entry in a hash table.  The\n      function's return value can be used to influence the iteration:\n\n      .. type:: enum cork_hash_table_map_result\n\n         .. var:: CORK_HASH_TABLE_CONTINUE\n\n            Continue the current :c:func:`cork_hash_table_map()` operation.  If\n            there are any remaining elements, the next one will be passed into\n            another call of the *map* function.\n\n         .. var:: CORK_HASH_TABLE_ABORT\n\n            Stop the current :c:func:`cork_hash_table_map()` operation.  No more\n            entries will be processed after this one, even if there are\n            remaining elements in the hash table.\n\n         .. var:: CORK_HASH_TABLE_DELETE\n\n            Continue the current :c:func:`cork_hash_table_map()` operation, but\n            first delete the entry that was just processed.  If there are any\n            remaining elements, the next one will be passed into another call of\n            the *map* function.\n\nFor instance, you can manually calculate the number of entries in a hash\ntable as follows (assuming you didn't want to use the built-in\n:c:func:`cork_hash_table_size()` function, of course)::\n\n  static enum cork_hash_table_map_result\n  count_entries(void *user_data, struct cork_hash_table_entry *entry)\n  {\n      size_t  *count = user_data;\n      (*count)++;\n      return CORK_HASH_TABLE_MAP_CONTINUE;\n  }\n\n  struct cork_hash_table  *table = /* from somewhere */;\n  size_t  count = 0;\n  cork_hash_table_map(table, &count, count_entries);\n  /* the number of entries is now in count */\n\n\nIterating\n~~~~~~~~~\n\nThe second strategy is to iterate through the entries yourself.  Since\nthe internal struture of the :c:type:`cork_hash_table` type is opaque\n(and slightly more complex than a simple array), you have to use a\nspecial “iterator” type to manage the manual iteration.  Note that\nunlike when using a mapping function, it is **not** safe to delete\nentries in a hash table as you manually iterate through them.\n\n.. type:: struct cork_hash_table_iterator\n\n   A helper type for manually iterating through the entries in a hash\n   table.  All of the fields in this type are private.  You'll usually\n   allocate this type on the stack.\n\n.. function:: void cork_hash_table_iterator_init(struct cork_hash_table \\*table, struct cork_hash_table_iterator \\*iterator)\n\n   Initializes a new iterator for the given hash table.\n\n.. function:: struct cork_hash_table_entry \\*cork_hash_table_iterator_next(struct cork_hash_table_iterator \\*iterator)\n\n   Returns the next entry in *iterator*\\ 's hash table.  If you've\n   already iterated through all of the entries in the table, we'll\n   return ``NULL``.\n\nWith these functions, manually counting the hash table entries looks\nlike::\n\n  struct cork_hash_table  *table = /* from somewhere */;\n  struct cork_hash_table_iterator  iter;\n  struct cork_hash_table_entry  *entry;\n  size_t  count = 0;\n\n  cork_hash_table_iterator_init(table, &iter);\n  while ((entry = cork_hash_table_iterator_next(&iter)) != NULL) {\n      count++;\n  }\n  /* the number of elements is now in count */\n"
  },
  {
    "path": "docs/old/hash-values.rst",
    "content": ".. _hash-values:\n\n***********\nHash values\n***********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\n\nThe functions in this section can be used to produce fast, good hash\nvalues.\n\n.. note::\n\n   For the curious, libcork currently uses the public-domain\n   `MurmurHash3 <http://code.google.com/p/smhasher/>`_ as its hash\n   implementation.\n\n\nHashing in C code\n-----------------\n\nA common pattern would be something along the lines of::\n\n  struct my_type {\n      int  a;\n      long  b;\n      double  c;\n      size_t  name_length;\n      const char  *name;\n  };\n\n  cork_hash\n  my_type_hash(const struct my_type *self)\n  {\n      /* hash of \"struct my_type\" */\n      cork_hash  hash = 0xd4a130d8;\n      hash = cork_hash_variable(hash, self->a);\n      hash = cork_hash_variable(hash, self->b);\n      hash = cork_hash_variable(hash, self->c);\n      hash = cork_hash_buffer(hash, self->name, self->name_length);\n      return hash;\n   }\n\nIn this example, the seed value (``0xd4a130d8``) is the hash of the\nconstant string ``\"struct my_type\"``.  You can produce seed values like\nthis using the :ref:`cork-hash <cork-hash>` script described below::\n\n  $ cork-hash \"struct my_type\"\n  0xd4a130d8\n\n\n.. type:: uint32_t  cork_hash\n\n.. function:: cork_hash cork_hash_buffer(cork_hash seed, const void \\*src, size_t len)\n              cork_hash cork_hash_variable(cork_hash seed, TYPE val)\n\n   Incorporate the contents of the given binary buffer or variable into a hash\n   value.  For the ``_variable`` variant, *val* must be an lvalue visible in the\n   current scope.\n\n   The hash values produces by these functions can change over time, and might\n   not be consistent across different platforms.  The only guarantee is that\n   hash values will be consistest for the duration of the current process.\n\n.. function:: cork_hash cork_stable_hash_buffer(cork_hash seed, const void \\*src, size_t len)\n              cork_hash cork_stable_hash_variable(cork_hash seed, TYPE val)\n\n   Stable versions of :c:func:`cork_hash_buffer` and\n   :c:func:`cork_hash_variable`.  We guarantee that the hash values produced by\n   this function will be consistent across different platforms, and across\n   different versions of the libcork library.\n\n\n.. type:: cork_big_hash\n\n.. function:: cork_big_hash cork_big_hash_buffer(cork_big_hash seed, const void \\*src, size_t len)\n\n   Incorporate the contents of the given binary buffer into a \"big\" hash value.\n   A big hash value has a much larger space of possible hash values (128 bits vs\n   32).\n\n\n.. function:: bool cork_big_hash_equal(cork_big_hash hash1, cork_big_hash hash2)\n\n   Compare two big hash values for equality.\n\n\n.. _cork-hash:\n\nHashing from the command line\n-----------------------------\n\nSeveral parts of libcork use hash values as identifiers; you use a\nunique string to identify part of your code, and use the hash of that\nstring as the actual identifier value.  We provide a command-line\nutility that you can use to produce these hash values:\n\n.. code-block:: none\n\n   cork-hash <string>\n\n.. describe:: <string>\n\n   The string to hash.  This should be provided as a single argument on\n   the command line, so if your string contains spaces or other shell\n   meta-characters, you must enclose the string in quotes.\n"
  },
  {
    "path": "docs/old/index.rst",
    "content": ".. _index:\n\n|project_name| documentation\n============================\n\nThis is the documentation for |project_name| |release|, last updated\n|today|.\n\n\nIntroduction\n------------\n\nSo what is libcork, exactly?  It's a “simple, easily embeddable, cross-platform\nC library”.  It falls roughly into the same category as glib_ or APR_ in the C\nworld; the STL, POCO_, or QtCore_ in the C++ world; or the standard libraries\nof any decent dynamic language.\n\nSo if libcork has all of these comparables, why a new library?  Well, none of\nthe C++ options are really applicable here.  And none of the C options work,\nbecause one of the main goals is to have the library be highly modular, and\nuseful in resource-constrained systems.  Once we describe some of the design\ndecisions that we've made in libcork, you'll hopefully see how this fits into\nan interesting niche of its own.\n\n.. _glib: http://library.gnome.org/devel/glib/\n.. _APR: http://apr.apache.org/\n.. _POCO: http://pocoproject.org/\n.. _QtCore: http://qt.nokia.com/\n\n\nContents\n--------\n\n.. toctree::\n   :maxdepth: 2\n\n   config\n   versions\n   visibility\n   basic-types\n   byte-order\n   attributes\n   allocation\n   errors\n   gc\n   mempool\n   ds\n   cli\n   files\n   process\n   subprocess\n   threads\n\n\nIndices and tables\n------------------\n\n* :ref:`genindex`\n* :ref:`search`\n"
  },
  {
    "path": "docs/old/int128.rst",
    "content": ".. _int128:\n\n****************\n128-bit integers\n****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nWe provide an API for working with unsigned, 128-bit integers.  Unlike libraries\nlike GMP_, our goal is not to support arbitrarily large integers, but to provide\noptimized support for this one specific integer type.  We might add support for\nadditional large integer types in the future, as need arises, but the focus will\nalways be on a small number of specific types, and not on arbitrary sizes.  For\nthat, use GMP.\n\n.. _GMP: http://gmplib.org/\n\n\n.. type:: cork_u128\n\n   An unsigned, 128-bit integer.  You can assume that instances of this type\n   will be exactly 16 bytes in size, and that the integer value will be stored\n   in host-endian order.  This type is currently implemented as a ``struct``,\n   but none of its members are part of the public API.\n\n\nInitialization\n==============\n\n.. function:: cork_u128 cork_u128_from_32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3)\n              cork_u128 cork_u128_from_64(uint64_t i0, uint64_t i1)\n\n   Return a 128-bit integer initialized with the given portions.  The various\n   *iX* pieces are given in big-endian order, regardless of the host's\n   endianness.  For instance, both of the following initialize an integer to\n   :math:`2^{64}`::\n\n       cork_u128  value1 = cork_u128_from_32(0, 1, 0, 0);\n       cork_u128  value2 = cork_u128_from_64(1, 0);\n\n\nAccessing subsets\n=================\n\n.. function:: &uint8_t cork_u128_be8(cork_u128 value, unsigned int index)\n              &uint16_t cork_u128_be16(cork_u128 value, unsigned int index)\n              &uint32_t cork_u128_be32(cork_u128 value, unsigned int index)\n              &uint64_t cork_u128_be64(cork_u128 value, unsigned int index)\n\n   Returns a reference to a portion of a 128-bit integer.  Regardless of the\n   host's endianness, the indices are counted in big-endian order — i.e., an\n   *index* of ``0`` will always return the most-significant portion of *value*.\n\n   The result is a valid lvalue, so you can assign to it to update the contents\n   of *value*::\n\n       cork_u128  value;\n       cork_u128_be64(value, 0) = 4;\n       cork_u128_be64(value, 1) = 16;\n\n\nArithmetic\n==========\n\nAll of the functions in this section are implemented as macros or inline\nfunctions, so you won't incur any function-call overhead when using them.\n\n.. function:: cork_u128 cork_u128_add(cork_128 a, cork_u128 b)\n              cork_u128 cork_u128_sub(cork_128 a, cork_u128 b)\n\n   Add or subtract two 128-bit integers, returning the result.\n\n   ::\n\n       cork_u128  a = cork_u128_from_32(0, 10);\n       cork_u128  b = cork_u128_from_32(0, 3);\n       cork_u128  c = cork_u128_add(a, b);\n       cork_u128  d = cork_u128_sub(a, b);\n       // c == 13 && d == 7\n\n\nComparison\n==========\n\nAll of the functions in this section are implemented as macros or inline\nfunctions, so you won't incur any function-call overhead when using them.\n\n.. function:: bool cork_u128_eq(cork_128 a, cork_u128 b)\n              bool cork_u128_ne(cork_128 a, cork_u128 b)\n              bool cork_u128_lt(cork_128 a, cork_u128 b)\n              bool cork_u128_le(cork_128 a, cork_u128 b)\n              bool cork_u128_gt(cork_128 a, cork_u128 b)\n              bool cork_u128_ge(cork_128 a, cork_u128 b)\n\n   Compare two 128-bit integers.  These functions correspond, respectively, to\n   the ``==``, ``!=``, ``<``, ``<=``, ``>``, and ``>=`` operators.\n\n   ::\n\n       cork_u128  a = cork_u128_from_32(0, 10);\n       cork_u128  b = cork_u128_from_32(0, 3);\n       // cork_u128_eq(a, b) → false\n       // cork_u128_ne(a, b) → true\n       // cork_u128_eq(a, a) → true\n       // cork_u128_gt(a, b) → true\n       // cork_u128_ge(a, a) → true\n       // and so on\n\n\nPrinting\n========\n\n.. function:: const char \\*cork_u128_to_decimal(char \\*buf, cork_u128 value)\n              const char \\*cork_u128_to_hex(char \\*buf, cork_u128 value)\n              const char \\*cork_u128_to_padded_hex(char \\*buf, cork_u128 value)\n\n   Write the string representation of *value* into *buf*.  The ``decimal`` and\n   ``hex`` variants do not include any padding in the result.  The\n   ``padded_hex`` variant pads the result with ``0`` characters so that the\n   string representation of every :c:type:`cork_u128` has the same width.\n\n   You must provide the buffer that the string representation will be rendered\n   into.  (This ensures that these functions are thread-safe.)  The return value\n   will be some portion of this buffer, but might not be *buf* itself.\n\n   You are responsible for ensuring that *buf* is large enough to hold the\n   string representation of any valid 128-bit integer.  The\n   :c:macro:`CORK_U128_DECIMAL_LENGTH` and :c:macro:`CORK_U128_HEX_LENGTH`\n   macros can be helpful for this::\n\n     char  buf[CORK_U128_DECIMAL_LENGTH];\n     cork_u128  value = cork_u128_from_32(0, 125);\n     printf(\"%s\\n\", cork_u128_to_decimal(buf, value));\n     // prints \"125\\n\"\n\n\n.. macro:: CORK_U128_DECIMAL_LENGTH\n           CORK_U128_HEX_LENGTH\n\n   The maximum length of the decimal or hexadecimal string representation of a\n   128-bit integer, including a ``NUL`` terminator.\n"
  },
  {
    "path": "docs/old/managed-buffer.rst",
    "content": ".. _managed-buffer:\n\n**********************\nManaged binary buffers\n**********************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines an interface for handling reference-counted binary\nbuffers.  The :c:type:`cork_managed_buffer` type wraps a buffer with a\nsimple reference count, and takes care of freeing the necessary\nresources when the reference count drops to zero.  There should only be\na single :c:type:`cork_managed_buffer` instance for any given buffer,\nregardless of how many threads or functions access that buffer.  Each\nthread or function that uses the buffer does so via a\n:c:type:`cork_slice` instance.  This type is meant to be allocated\ndirectly on the stack (or in some other managed storage), and keeps a\npointer to the managed buffer instance that it slices.  As its name\nimplies, a slice can refer to a subset of the buffer.\n\n\n.. type:: struct cork_managed_buffer\n\n   A “managed buffer”, which wraps a buffer with a simple reference\n   count.\n\n   Managed buffer consumers should consider all of the fields of this\n   class private.  Managed buffer implementors should fill in this\n   fields when constructing a new ``cork_managed_buffer`` instance.\n\n   .. member:: const void  \\*buf\n\n      The buffer that this instance manages.\n\n   .. member:: size_t  size\n\n      The size of :c:member:`buf`.\n\n   .. member:: volatile int  ref_count\n\n      A reference count for the buffer.  If this drops to ``0``, the\n      buffer will be finalized.\n\n   .. member:: struct cork_managed_buffer_iface  \\*iface\n\n      The managed buffer implementation for this instance.\n\n\n.. function:: struct cork_managed_buffer \\*cork_managed_buffer_ref(struct cork_managed_buffer \\*buf)\n\n   Atomically increase the reference count of a managed buffer.  This\n   function is thread-safe.\n\n\n.. function:: void cork_managed_buffer_unref(struct cork_managed_buffer \\*buf)\n\n   Atomically decrease the reference count of a managed buffer.  If the\n   reference count falls to ``0``, the instance is freed.  This function\n   is thread-safe.\n\n.. function:: int cork_managed_buffer_slice(struct cork_slice \\*dest, struct cork_managed_buffer \\*buffer, size_t offset, size_t length)\n              int cork_managed_buffer_slice_offset(struct cork_slice \\*dest, struct cork_managed_buffer \\*buffer, size_t offset)\n\n   Initialize a new slice that refers to a subset of a managed buffer.\n   The *offset* and *length* parameters identify the subset.  (For the\n   ``_slice_offset`` variant, the *length* is calculated automatically\n   to include all of the managed buffer content starting from *offset*.)\n   If these parameters don't refer to a valid portion of the buffer, we\n   return ``false``, and you must not try to deference the slice's\n   :c:member:`buf <cork_slice.buf>` pointer.  If the slice is valid, we\n   return ``true``.\n\n   Regardless of whether the new slice is valid, you **must** ensure\n   that you call :c:func:`cork_slice_finish()` when you are done with\n   the slice.\n\n\nPredefined managed buffer implementations\n-----------------------------------------\n\n.. function:: struct cork_managed_buffer \\*cork_managed_buffer_new_copy(const void \\*buf, size_t size)\n\n   Make a copy of *buf*, and allocate a new managed buffer to manage\n   this copy.  The copy will automatically be freed when the managed\n   buffer's reference count drops to ``0``.\n\n\n.. type:: void (\\*cork_managed_buffer_freer)(void \\*buf, size_t size)\n\n   A finalization function for a managed buffer created by\n   :c:func:`cork_managed_buffer_new()`.\n\n.. function:: struct cork_managed_buffer \\*cork_managed_buffer_new(const void \\*buf, size_t size, cork_managed_buffer_freer free)\n\n   Allocate a new managed buffer to manage an existing buffer (*buf*).\n   The existing buffer is *not* copied; the new managed buffer instance\n   takes control of it.  When the managed buffer's reference count drops\n   to ``0``, it will call *free* to finalize *buf*.\n\n   This is a helper function, and keeps you from having to write a\n   complete custom managed buffer implementation when you don't need to\n   store any additional state in the managed buffer object.\n\n   .. note::\n\n      The *free* function is *not* responsible for freeing the\n      ``cork_managed_buffer`` instance itself.\n\n\nCustom managed buffer implementations\n-------------------------------------\n\n.. type:: struct cork_managed_buffer_iface\n\n   The interface of methods that managed buffer implementations must\n   provide.\n\n   .. member:: void (\\*free)(struct cork_managed_buffer \\*self)\n\n      Free the contents of a managed buffer, and the\n      ``cork_managed_buffer`` instance itself.\n"
  },
  {
    "path": "docs/old/mempool.rst",
    "content": ".. _mempool:\n\n************\nMemory pools\n************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThe functions in this section let you define *memory pools*, which allow\nyou to reduce the overhead of allocating and freeing large numbers of\nsmall objects.  Instead of generating a ``malloc`` call for each\nindividual object, the memory pool allocates a large *block* of memory,\nand then subdivides this block of memory into objects of the desired\nsize.  The free objects in the memory pool are linked together in a\nsingly-linked list, which means that allocation and deallocation is\nusually a (very small) constant-time operation.\n\n.. note::\n\n   Memory pools are *not* thread safe; if you have multiple threads\n   allocating objects of the same type, they'll need separate memory\n   threads.\n\n\nBasic interface\n---------------\n\n.. type:: struct cork_mempool\n\n   A memory pool.  All of the objects created by the memory pool will be\n   the same size; this size is provided when you initialize the memory\n   pool.\n\n.. function:: struct cork_mempool \\*cork_mempool_new_size(size_t element_size)\n              struct cork_mempool \\*cork_mempool_new(TYPE type)\n\n   Allocate a new memory pool.  The size of the objects allocated by\n   the memory pool is given either as an explicit *element_size*, or by\n   giving the *type* of the objects.  The blocks allocated by the memory\n   pool will be of a default size (currently 4Kb).\n\n.. function:: struct cork_mempool \\*cork_mempool_new_size_ex(size_t element_size, size_t block_size)\n              struct cork_mempool \\*cork_mempool_new_ex(TYPE type, size_t block_size)\n\n   Allocate a new memory pool.  The size of the objects allocated by\n   the memory pool is given either as an explicit *element_size*, or by\n   giving the *type* of the objects.  The blocks allocated by the memory\n   pool will be *block_size* bytes large.\n\n.. function:: void cork_mempool_free(struct cork_mempool \\*mp)\n\n   Free a memory pool.  You **must** have already freed all of the\n   objects allocated by the pool; if you haven't, then this function\n   will cause the current process to abort.\n\n.. function:: void \\*cork_mempool_new_object(struct cork_mempool \\*mp)\n\n   Allocate a new object from the memory pool.\n\n.. function:: void cork_mempool_free_object(struct cork_mempool \\*mp, void \\*ptr)\n\n   Free an object that was allocated from the memory pool.\n\n\n\n.. _mempool-lifecycle:\n\nInitializing and finalizing objects\n-----------------------------------\n\nWhen you free an object that was allocated via a memory pool, the memory\nfor that object isn't actually freed immediately.  (That's kind of the\nreason that you're using a memory pool in the first place.)  This means\nthat if your object contains any fields that are expensive to initialize\nand finalize, it can make sense to postpone the finalization of those\nfields until the memory for the object itself is actually freed.\n\nAs an example, let's say you have the following type that you're going\nto allocate via a memory pool::\n\n    struct my_data {\n        struct cork_buffer  scratch_space;\n        int  age;\n    };\n\nOur first attempt at a constructor and destructor would then be::\n\n    static cork_mempool  *pool;\n    pool = cork_mempool_new(struct my_data);\n\n    struct my_data *\n    my_data_new(void)\n    {\n        struct my_data  *self = cork_mempool_new_object(pool);\n        if (self == NULL) {\n            return NULL;\n        }\n\n        cork_buffer_init(&self->scratch_space);\n        return self;\n    }\n\n    void\n    my_data_free(struct my_data *self)\n    {\n        cork_buffer_done(&self->scratch_space);\n        cork_mempool_free_object(pool, self);\n    }\n\nWhat's interesting about this example is that the ``scratch_space``\nfield, being a :c:type:`cork_buffer`, allocates some space internally to\nhold whatever data we're building up in the buffer.  When we call\n:c:func:`cork_buffer_done` in our destructor, that memory is returned to\nthe system.  Later on, when we allocate a new ``my_data``, the\n:c:func:`cork_mempool_new_object` call in our constructor might get this same\nphysical instance back.  We'll then proceed to re-initialize the\n``scratch_space`` buffer, which will then reallocate its internal buffer\nspace as we use the type.\n\nSince we're using a memory pool to reuse the memory for the ``my_data``\ninstance, we might as well try to reuse the memory for the\n``scratch_space`` field, as well.  To do this, you provide initialization and\nfinalization callbacks:\n\n.. function:: void cork_mempool_set_user_data(struct cork_mempool \\*mp, void \\*user_data, cork_free_f free_user_data)\n              void cork_mempool_set_init_object(struct cork_mempool \\*mp, cork_init_f init_object)\n              void cork_mempool_set_done_object(struct cork_mempool \\*mp, cork_done_f done_object)\n\n   Provide callback functions that will be used to initialize and finalize each\n   object created by the memory pool.\n\nSo, instead of putting the initialization logic into our constructor, we\nput it into the ``init_object`` function.  Similarly, the finalization\nlogic goes into ``done_object``, and not our destructor::\n\n    static void\n    my_data_init(void *user_data, void *vself)\n    {\n        struct my_data  *self = vself;\n        cork_buffer_init(&self->scratch_space);\n        return 0;\n    }\n\n    static void\n    my_data_done(void *user_data, void *vself)\n    {\n        struct my_data  *self = vself;\n        cork_buffer_done(&self->scratch_space);\n    }\n\n    static cork_mempool  *pool;\n    pool = cork_mempool_new(pool, struct my_data);\n    cork_mempool_set_init_object(pool, my_data_init);\n    cork_mempool_set_done_object(pool, my_data_done);\n\n    struct my_data *\n    my_data_new(void)\n    {\n        return cork_mempool_new_object(pool);\n    }\n\n    void\n    my_data_free(struct my_data *self)\n    {\n        cork_mempool_free_object(pool, self);\n    }\n\nIn this implementation, the ``scratch_space`` buffer is initialized when\nthe memory for an instance is first allocated, and it's not finalized\nuntil the memory for the instance is returned to the system.  (Which\nbasically means \"when the memory pool itself is freed\".)\n\nA caveat with this approach is that we've no longer guaranteed that the\n``scratch_space`` buffer is empty when ``my_data_new`` returns — if\nwe're reusing an existing object, then the contents of the \"previous\"\nobject's buffer will still be there.  We can either make sure that\nconsumers of ``my_data`` don't assume anything about the contents of\n``scratch_space``, or better yet, we can *reset* the fields in our\nconstructor object::\n\n    struct my_data *\n    my_data_new(void)\n    {\n        struct my_data  *self = cork_mempool_new_object(pool);\n        cork_buffer_clear(&self->scratch_space);\n        return self;\n    }\n\nIn this example, we can reset the buffer just by clearing it.  If\nresetting is more involved, it can sometimes be better to leave the\ninstance in a \"messy\" state, and have your clients not make assumptions.\nBut if you do this, make sure to be clear about it in your\ndocumentation.\n"
  },
  {
    "path": "docs/old/net-addresses.rst",
    "content": ".. _net-addresses:\n\n*****************\nNetwork addresses\n*****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\n\nIP addresses\n------------\n\nlibcork provides C types for storing IPv4 and IPv6 addresses, as well as\na union type for storing a generic IP address, regardless of whether\nit's IPv4 or IPv6.  (This lets you distinguish between an IPv4 address\nand the equivalent ``::ffff:0:0/96`` IPv4-mapped IPv6 address.)\n\n.. type:: struct cork_ipv4\n          struct cork_ipv6\n\n   An IPv4 or IPv6 address.  The address is stored in memory exactly as\n   it would be if sent over a network connection — i.e., in\n   network-endian order, regardless of the endianness of the current\n   host.  The types are also guaranteed to be exactly the size of an\n   actual IPv4 or IPv6 address (without additional padding), so they can\n   be embedded directly into ``struct`` types that represent binary\n   disk/wire formats.\n\n   The contents of these types should be considered opaque.  You should\n   use the accessor functions defined below to interact with the IP\n   address.\n\n.. type:: struct cork_ip\n\n   A single union type that can contain either an IPv4 or IPv6 address.\n   This type contains a discriminator field, so you can't use it\n   directly in a binary disk/wire format type.\n\n   .. member:: unsigned int  version\n\n      Either ``4`` or ``6``, indicating whether the current IP address\n      is an IPv4 address or an IPv6 address.\n\n   .. member:: struct cork_ipv4  ip.v4\n               struct cork_ipv6  ip.v6\n\n      Gives you access to the underlying :c:type:`cork_ipv4` or\n      :c:type:`cork_ipv6` instance for the current address.  It's your\n      responsibility to check the :c:member:`cork_ip.version` field and\n      only access the union branch that corresponds to the current IP\n      version.\n\n\n.. function:: void cork_ipv4_copy(struct cork_ipv4 \\*addr, const void \\*src)\n              void cork_ipv6_copy(struct cork_ipv6 \\*addr, const void \\*src)\n              void cork_ip_from_ipv4(struct cork_ip \\*addr, const void \\*src)\n              void cork_ip_from_ipv6(struct cork_ip \\*addr, const void \\*src)\n\n   Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or\n   :c:type:`cork_ip` instance from an existing IP address somewhere in\n   memory.  The existing address doesn't have to be an instance of the\n   :c:type:`cork_ipv4` or :c:type:`cork_ipv6` types, but it does have to\n   be a well-formed address.  (For IPv4, it must be 4 bytes long; for\n   IPv6, 16 bytes long.  And in both cases, the address must already be\n   in network-endian order, regardless of the host's endianness.)\n\n\n.. function:: int cork_ipv4_init(struct cork_ipv4 \\*addr, const char \\*str)\n              int cork_ipv6_init(struct cork_ipv6 \\*addr, const char \\*str)\n              int cork_ip_init(struct cork_ip \\*addr, const char \\*str)\n\n   Initializes a :c:type:`cork_ipv4`, :c:type:`cork_ipv6`, or\n   :c:type:`cork_ip` instance from the string representation of an IP\n   address.  *str* must point to a string containing a well-formed IP\n   address.  (Dotted-quad for an IPv4, and colon-hex for IPv6.)\n   Moreover, the version of the IP address in *str* must be compatible\n   with the function that you call: it can't be an IPv6 address if you\n   call ``cork_ipv4_init``, and it can't be an IPv4 address if you call\n   ``cork_ipv6_init``.\n\n   If *str* doesn't represent a valid address (of a compatible IP\n   version), then we leave *addr* unchanged, fill in the current error\n   condition with a :c:data:`CORK_NET_ADDRESS_PARSE_ERROR` error, and\n   return ``-1``.\n\n\n.. function:: bool cork_ipv4_equal(const struct cork_ipv4 \\*addr1, const struct cork_ipv4 \\*addr2)\n              bool cork_ipv6_equal(const struct cork_ipv6 \\*addr1, const struct cork_ipv6 \\*addr2)\n              bool cork_ip_equal(const struct cork_ip \\*addr1, const struct cork_ip \\*addr2)\n\n   Checks two IP addresses for equality.\n\n\n.. macro:: CORK_IPV4_STRING_LENGTH\n           CORK_IPV6_STRING_LENGTH\n           CORK_IP_STRING_LENGTH\n\n   The maximum length of the string representation of an IPv4, IPv6, or\n   generic IP address, including a ``NUL`` terminator.\n\n.. function:: void cork_ipv4_to_raw_string(const struct cork_ipv4 \\*addr, char \\*dest)\n              void cork_ipv6_to_raw_string(const struct cork_ipv6 \\*addr, char \\*dest)\n              void cork_ip_to_raw_string(const struct cork_ip \\*addr, char \\*dest)\n\n   Fills in *dest* with the string representation of an IPv4, IPv6, or\n   generic IP address.  You are responsible for ensuring that *dest* is\n   large enough to hold the string representation of any valid IP\n   address of the given version.  The\n   :c:macro:`CORK_IPV4_STRING_LENGTH`,\n   :c:macro:`CORK_IPV6_STRING_LENGTH`, and\n   :c:macro:`CORK_IP_STRING_LENGTH` macros can be helpful for this::\n\n     char  buf[CORK_IPV4_STRING_LENGTH];\n     struct cork_ipv4  addr;\n     cork_ipv4_to_raw_string(&addr, buf);\n\n\n.. function:: bool cork_ipv4_is_valid_network(const struct cork_ipv4 \\*addr, unsigned int cidr_prefix)\n              bool cork_ipv6_is_valid_network(const struct cork_ipv6 \\*addr, unsigned int cidr_prefix)\n              bool cork_ip_is_valid_network(const struct cork_ipv6 \\*addr, unsigned int cidr_prefix)\n\n    Checks an IP address for alignment with a CIDR block prefix. For example,\n    10.1.2.4/24 is invalid, but 10.1.2.4/30 is valid.\n\n\n.. macro:: CORK_NET_ADDRESS_ERROR\n           CORK_NET_ADDRESS_PARSE_ERROR\n\n   The error class and codes used for the :ref:`error conditions\n   <errors>` described in this section.\n"
  },
  {
    "path": "docs/old/process.rst",
    "content": ".. _processes:\n\n*********\nProcesses\n*********\n\n.. highlight:: c\n\n::\n\n  #include <libcork/os.h>\n\nThe functions in this section let you interact with the current running process.\n\n\nCleanup functions\n~~~~~~~~~~~~~~~~~\n\nOften you will need to perform some cleanup tasks whenever the current process\nterminates normally.  The functions in this section let you do that.\n\n.. function:: void cork_cleanup_at_exit(int priority, cork_cleanup_function function)\n              void cork_cleanup_at_exit_named(const char \\*name, int priority, cork_cleanup_function function)\n\n   Register a *function* that should be called when the current process\n   terminates.  When multiple functions are registered, the order in which they\n   are called is determined by their *priority* values --- functions with lower\n   priorities will be called first.  If any functions have the same priority\n   value, there is no guarantee about the order in which they will be called.\n\n   All cleanup functions must conform to the following signature:\n\n   .. type:: void (\\*cork_cleanup_function)(void)\n\n   The ``_named`` variant lets you provide an explicit name for the cleanup\n   function, which currently is only used when printing out debug messages.  The\n   plain variant automatically detects the name of *function*, so that you don't\n   have to provide it explicitly.\n\n\n.. _env:\n\nEnvironment variables\n~~~~~~~~~~~~~~~~~~~~~\n\n.. type:: struct cork_env\n\n   A collection of environment variables that can be passed to subprocesses.\n\n\n.. function:: struct cork_env \\*cork_env_new(void)\n\n   Create a new, empty collection of environment variables.\n\n.. function:: struct cork_env \\*cork_env_clone_current(void)\n\n   Create a new :c:type:`cork_env` containing all of the environment variables\n   in the current process's environment list.\n\n.. function:: void cork_env_free(struct cork_env \\*env)\n\n   Free a collection of environment variables.\n\n\n.. function:: const char \\*cork_env_get(struct cork_env \\*env, const char \\*name)\n\n   Return the value of the environment variable with the given *name*.  If there\n   is no variable with that name, return ``NULL``.\n\n   If *env* is ``NULL``, then the variable is retrieved from the current process\n   environment; otherwise, it is retrieved from *env*.\n\n.. function:: void cork_env_add(struct cork_env \\*env, const char \\*name, const char \\*value)\n              void cork_env_add_printf(struct cork_env \\*env, const char \\*name, const char \\*format, ...)\n              void cork_env_add_vprintf(struct cork_env \\*env, const char \\*name, const char \\*format, va_list args)\n\n   Add a new environment variable with the given *name* and *value*.  If there\n   is already a variable with that name, it is overwritten.  We make a copy of\n   both *name* and *variable*, so it is safe to pass in temporary or reusable\n   strings for either.  The ``printf`` and ``vprintf`` variants construct the\n   new variable's value from a ``printf``-like format string.\n\n   If *env* is ``NULL``, then the new variable is added to the current process\n   environment; otherwise, it is added to *env*.\n\n.. function:: void cork_env_remove(struct cork_env \\*env, const char \\*name)\n\n   Remove the environment variable with the given *name*, if it exists.  If\n   there isn't any variable with that name, do nothing.\n\n   If *env* is ``NULL``, then the variable is removed from the current process\n   environment; otherwise, it is removed from *env*.\n\n\n.. function:: void cork_env_replace_current(struct cork_env \\*env)\n\n   Replace the current process's environment list with the contents of *env*.\n\n\n.. _exec:\n\nExecuting another program\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. type:: struct cork_exec\n\n   A specification for executing another program.\n\n\n.. function:: struct cork_exec \\*cork_exec_new(const char \\*program)\n              struct cork_exec \\*cork_exec_new_with_params(const char \\*program, ...)\n              struct cork_exec \\*cork_exec_new_with_param_array(const char \\*program, char \\* const \\*params)\n\n   Create a new specification for executing *program*.  *program* must either be\n   an absolute path to an executable on the local filesystem, or the name of an\n   executable that should be found in the current ``PATH``.\n\n   The first variant creates a specification that initially doesn't contain any\n   parameters to pass into the new program.  The second variant allows you to\n   pass in each argument as a separate parameter; you must ensure that you\n   terminate the list of parameters with a ``NULL`` pointer.  The third variant\n   allows you to pass in a ``NULL``-terminated array of strings to use as an\n   initial parameter list.  For all three variants, you can add additional\n   parameters before executing the new program via the :c:func:`cork_add_param`\n   function.\n\n   .. note::\n\n      Most programs will expect the first parameter to be the name of the\n      program being executed.  The :c:func:`cork_exec_new_with_params` function\n      will automatically fill in this first parameter for you.  The other\n      constructor functions do not; when using them, it is your responsibility\n      to provide this parameter, just like any other parameters to pass into the\n      program.\n\n   This function does not actually execute the program; that is handled by the\n   :c:func:`cork_exec_run` function.\n\n.. function:: void cork_exec_free(struct cork_exec \\*exec)\n\n   Free an execution specification.  You normally won't need to call this\n   function; normally you'll replace the current process with the new program\n   (by calling :c:func:`cork_exec_run`), which means you won't have a chance to\n   free the specification object.\n\n.. function:: const char \\*cork_exec_description(struct cork_exec \\*exec)\n\n   Return a string description of the program described by an execution\n   specification.\n\n.. function:: void cork_exec_add_param(struct cork_exec \\*exec, const char \\*param)\n\n   Add a parameter to the parameter list that will be passed into the new\n   program.\n\n.. function:: void cork_exec_set_env(struct cork_exec \\*exec, struct cork_env \\*env)\n\n   Provide a set of environment variables that will be passed into the new\n   program.  The subprocess's environment will contain only those variables\n   defined in *env*.  You can use the :c:func:`cork_env_clone_current` function\n   to create a copy of the current process's environment, to use it as a base to\n   add new variables or remove unsafe variables.  We will take control of *env*,\n   so you must **not** call :c:func:`cork_env_free` to free the environment\n   yourself.\n\n   If you don't call this function for a specification object, the new\n   program will use the same environment as the calling process.\n\n.. function:: void cork_exec_set_cwd(struct cork_exec \\*exec, const char \\directory)\n\n   Change the working directory that the new program will be called from.  If\n   you don't call this function for a specification object, the new program will\n   be executed in the same working directory as the calling process.\n\n\n.. function:: const char \\*cork_exec_program(struct cork_exec \\*exec)\n              size_t \\*cork_exec_param_count(struct cork_exec \\*exec)\n              const char \\*cork_exec_param(struct cork_exec \\*exec, size_t index)\n              struct cork_env \\*cork_exec_env(struct cork_exec \\*exec)\n              const char \\*cork_exec_cwd(struct cork_exec \\*exec)\n\n   Accessor functions that allow you to retrieve the contents of an execution\n   specification.  The :c:func:`cork_exec_env` and :c:func:`cork_exec_cwd`\n   functions might return ``NULL``, if there isn't an environment or working\n   directory specified.\n\n\n.. function:: int cork_exec_run(struct cork_exec \\*exec)\n\n   Execute the program specified by *exec*, replacing the current process.\n   If we can successfully start the new program, this function will not return.\n   If there are any errors starting the program, this function will return an\n   error condition.\n"
  },
  {
    "path": "docs/old/ring-buffer.rst",
    "content": ".. _ring-buffer:\n\n************\nRing buffers\n************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\n\n.. type:: struct cork_ring_buffer\n\n   A ring buffer data structure that can be easily embedded into other\n   types.  All of the fields in ``cork_ring_buffer`` are private; you\n   should only access the contents of the ring buffer via the functions\n   defined below.\n\n   The elements of a ring buffer are ``void *`` pointers.  (You can also\n   store integers via the :c:type:`intptr_t` and :c:type:`uintptr_t`\n   types.)  Ring buffers have a fixed capacity, which must be specified\n   when the ring buffer instance is initialized.  You cannot add extra\n   space to an existing ring buffer.\n\n   Ring buffers implement a FIFO queue structure; elements will be\n   returned by :c:func:`cork_ring_buffer_pop()` in the same order that\n   they're added by :c:func:`cork_ring_buffer_add()`.\n\n\n.. function:: int cork_ring_buffer_init(struct cork_ring_buffer \\*buf, size_t size)\n              struct cork_ring_buffer \\*cork_ring_buffer_new(size_t size)\n\n   Initializes a ring buffer instance, having a capacity of *size* elements.\n   The ``_init`` version should be used to initialize an instance you\n   allocated yourself on the stack.  The ``_new`` version will allocate an\n   instance from the heap.  If memory allocation fails in either function,\n   the program will abort with an error.\n\n\n.. function:: void cork_ring_buffer_done(struct cork_ring_buffer \\*buf)\n              void cork_ring_buffer_free(struct cork_ring_buffer \\*buf)\n\n   Finalizes a ring buffer instance.  The ``_done`` variant should be used to\n   finalize an instance that you allocated yourself (i.e., on the stack).  The\n   ``_free`` version should be used on instance allocated on the heap by using\n   :c:func:`cork_hash_table_new()`.  Nothing special is done to any\n   remaining elements in the ring buffer; if they need to be finalized,\n   you should do that yourself before calling this function.\n\n\n.. function:: bool cork_ring_buffer_is_empty(struct cork_ring_buffer \\*buf)\n              bool cork_ring_buffer_is_full(struct cork_ring_buffer \\*buf)\n\n   Returns whether the ring buffer is empty or full.  (You cannot add\n   elements to a full ring buffer, and you cannot pop elemenst from an\n   empty one.)\n\n\n.. function:: int cork_ring_buffer_add(struct cork_ring_buffer \\*buf, void \\*element)\n\n   Adds *element* to a ring buffer.  If the ring buffer is full, we\n   return ``-1``, and the ring buffer will be unchanged.  Otherwise we\n   return ``0``.\n\n.. function:: void \\*cork_ring_buffer_pop(struct cork_ring_buffer \\*buf)\n              void \\*cork_ring_buffer_peek(struct cork_ring_buffer \\*buf)\n\n   Returns the next element in the ring buffer.  If the ring buffer is\n   empty, we return ``NULL``.  The ``_pop`` variant will remove the\n   returned element from the ring buffer before returning it; the\n   ``_peek`` variant will leave the element in the ring buffer.\n"
  },
  {
    "path": "docs/old/slice.rst",
    "content": ".. _slice:\n\n*************\nBinary slices\n*************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\nThis section defines an interface for safely referring to the contents\nof a binary buffer, without needing to know where the buffer came from.\nIn addition to accessing the contents of the underlying buffer, slices\nsupport three operations:\n\n* *Copying* initializes a new slice object to point at the same\n  underlying buffer as the current slice.  Depending on how the\n  underlying buffer is implemented, this doesn't necessarily involve\n  actual copying; for instance, the :c:type:`cork_managed_buffer` type\n  implements this operation by incrementing the reference count of the\n  managed buffer.\n\n* *Slicing* updates the current slice to point at a subset of its\n  current contents.  This doesn't affect the underlying buffer.\n\n* *Freeing* releases the resources used by the slice, possibly freeing\n  the underlying buffer.\n\nThese operations are represented by the *slice interface*\n(:c:type:`cork_slice_iface`).  To write a new slice implementation, you\njust need to provide an instance of this interface type.\n\n\n.. note::\n\n   There's no generic constructor or initialization function for slices;\n   instead, you'll create a slice from some other data structure, using\n   a function specific to that data structure.  (An example is the\n   :c:func:`cork_buffer_to_slice()` function, which initializes a slice\n   from a :ref:`resizable buffer <buffer>`.)\n\n\n.. type:: struct cork_slice\n\n   A specific window into a portion of an underlying binary buffer.\n\n   Instances of this class do not need to be (and almost never are)\n   allocated on the heap; you can define an instance directly on the\n   stack, or in some other kind of managed storage.\n\n   .. note::\n\n      It is **very important** that you ensure that\n      :c:func:`cork_slice_finish()` is called whenever you are done with\n      a slice — if you don't, there's a very good chance that the\n      underlying buffer will never be freed.  Yes, yes, it's unfortunate\n      that C doesn't have ``try``/``finally`` or RAII, but suck it up\n      and make sure that :c:func:`cork_slice_finish()` gets called.\n\n   .. member:: const void  \\*buf\n\n      The beginning of the sliced portion of the underlying buffer.\n\n   .. member:: size_t  size\n\n      The size of the sliced portion of the underlying buffer.\n\n   .. member:: struct cork_slice_iface  \\*iface\n\n      The slice implementation of the underlying buffer.  For slice\n      consumers, this field should be considered private.  For slice\n      implementors, you should fill in this field with your slice\n      interface.\n\n   .. member:: void  \\*user_data\n\n      An opaque pointer used by the slice implementation.  For slice\n      consumers, this field should be considered private.  For slice\n      implementors, you can use this field to point at the underlying\n      buffer (and/or any additional metadata that you need.)\n\n\n.. function:: void cork_slice_clear(struct cork_slice \\*slice)\n\n   Clear a slice object.  This fills in a slice instance so that it's\n   “empty”.  You should not try to call any of the slice methods on an\n   empty slice, nor should you try to dereference the slice's\n   :c:member:`buf <cork_slice.buf>` pointer.  An empty slice is\n   equivalent to a ``NULL`` pointer.\n\n.. function:: bool cork_slice_is_empty(struct cork_slice \\*slice)\n\n   Return whether a slice is empty.\n\n\n.. function:: int cork_slice_copy(struct cork_slice \\*dest, struct cork_slice \\*src, size_t offset, size_t length)\n              int cork_slice_copy_offset(struct cork_slice \\*dest, struct cork_slice \\*src, size_t offset)\n              int cork_slice_copy_fast(struct cork_slice \\*dest, struct cork_slice \\*src, size_t offset, size_t length)\n              int cork_slice_copy_offset_fast(struct cork_slice \\*dest, struct cork_slice \\*src, size_t offset)\n\n   Initialize a new slice that refers to a subset of an existing slice.\n   The *offset* and *length* parameters identify the subset.  (For the\n   ``_copy_offset`` variant, the *length* is calculated automatically to\n   include all of the original slice content starting from *offset*.)\n\n   For the ``_fast`` variants, we **don't** verify that the *offset* and\n   *length* parameters refer to a valid subset of the slice.  This is\n   your responsibility.  For the non-\\ ``_fast`` variants, we perform a\n   bounds check for you, and return an error if the requested slice is\n   invalid.\n\n   Regardless of whether the new slice is valid, you **must** ensure\n   that you call :c:func:`cork_slice_finish()` on *dest* when you are\n   done with it.\n\n.. function:: int cork_slice_light_copy(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset, size_t length)\n              int cork_slice_light_copy_offset(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset)\n              int cork_slice_light_copy_fast(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset, size_t length)\n              int cork_slice_light_copy_offset_fast(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset)\n\n   Initialize a new slice that refers to a subset of an existing slice.  By\n   calling a ``_light_copy`` function instead of a ``_copy`` function, you are\n   guaranteeing that *dest* will not outlive *src* — i.e., it is your\n   responsibility to ensure that you call :c:func:`cork_slice_finish` on *dest*\n   before you call it on *src*.  This guarantee lets slice implementations make\n   a more light-weight copy of the slice: for instance, by not having to make a\n   copy of the underlying buffer.\n\n   The *offset* and *length* parameters identify the subset.  (For the\n   ``_light_copy_offset`` variant, the *length* is calculated automatically to\n   include all of the original slice content starting from *offset*.)\n\n   For the ``_fast`` variants, we **don't** verify that the *offset* and\n   *length* parameters refer to a valid subset of the slice.  This is\n   your responsibility.  For the non-\\ ``_fast`` variants, we perform a\n   bounds check for you, and return an error if the requested slice is\n   invalid.\n\n   Regardless of whether the new slice is valid, you **must** ensure\n   that you call :c:func:`cork_slice_finish()` on *dest* when you are\n   done with it.\n\n.. function:: int cork_slice_slice(struct cork_slice \\*slice, size_t offset, size_t length)\n              int cork_slice_slice_offset(struct cork_slice \\*slice, size_t offset)\n              int cork_slice_slice_fast(struct cork_slice \\*slice, size_t offset, size_t length)\n              int cork_slice_slice_offset_fast(struct cork_slice \\*slice, size_t offset)\n\n   Update a slice to refer to a subset of its contents.  The *offset*\n   and *length* parameters identify the subset.  (For the\n   ``_slice_offset`` variant, the *length* is calculated automatically\n   to include all of the original slice content starting from *offset*.)\n\n   For the ``_fast`` variants, we **don't** verify that the *offset* and\n   *length* parameters refer to a valid subset of the slice.  This is\n   your responsibility.  For the non-\\ ``_fast`` variants, we perform a\n   bounds check for you, and return an error if the requested slice is\n   invalid.\n\n.. function:: void cork_slice_finish(struct cork_slice \\*slice)\n\n   Finalize a slice, freeing the underlying buffer if necessary.\n\n.. function:: int cork_slice_equal(const struct cork_slice \\*slice1, const struct cork_slice \\*slice2)\n\n   Compare the contents of two slices for equality.  (The *contents* of\n   the slices are compared, not their pointers; this is the slice\n   equivalent of ``memcmp``, not the ``==`` operator.)\n\n\nSlice interface\n---------------\n\n.. type:: struct cork_slice_iface\n\n   The interface of methods that slice implementations must provide.\n\n   .. member:: void (\\*free)(struct cork_slice \\*self)\n\n      Called when the slice should be freed.  If necessary, you should\n      free the contents of the underlying buffer.  (If the buffer\n      contents can be shared, it's up to you to keep track of when the\n      contents are safe to be freed.)\n\n      This function pointer can be ``NULL`` if you don't need to free\n      any underlying buffer.\n\n   .. member:: int (\\*copy)(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset, size_t length)\n               int (\\*light_copy)(struct cork_slice \\*dest, const struct cork_slice \\*src, size_t offset, size_t length)\n\n      Create a copy of a slice.  You can assume that *offset* and\n      *length* refer to a valid subset of *src*\\ 's content.\n\n      For the ``light_copy`` method, the caller guarantees that the new light\n      copy (*dest*) will not outlive the original slice (*src*).  For some slice\n      implementations, this lets you create a more light-weight copy — for\n      instance, by not having to make an actualy copy of the underlying buffer.\n\n   .. member:: int (\\*slice)(struct cork_slice \\*self, size_t offset, size_t length)\n\n      Update *self* to point at a different subset of the underlying\n      buffer.  You can assume that *offset* and *length* refer to a\n      valid subset of the buffer.  (They will be relative to *self*\\ 's\n      existing slice, and not to the original buffer.)\n\n      This function pointer can be ``NULL`` if you don't need to do\n      anything special to the underlying buffer; in this case,\n      :c:func:`cork_slice_slice()` and\n      :c:func:`cork_slice_slice_offset()` will update the slice's *buf*\n      and *size* fields for you.\n\n\nBuilt-in slice implementations\n------------------------------\n\nSeveral libcork classes can be used to initialize a slice:\n\n* :ref:`Managed buffers <managed-buffer>` via the\n  :c:func:`cork_managed_buffer_slice` function\n\n* :ref:`Resizable buffers <buffer>` via the\n  :c:func:`cork_buffer_to_slice` function\n\nYou can also initialize a slice to point at an existing buffer:\n\n\n.. function:: void cork_slice_init_static(struct cork_slice \\*dest, const void \\*buf, size_t size)\n\n   Initializes *dest* to point at the given static buffer.  Since the\n   buffer is static, and guaranteed to always exist, the slice's\n   :c:member:`~cork_slice.copy` method doesn't copy the underlying data,\n   it just creates a new pointer to the existing buffer.\n\n   .. note::\n\n      You can also use this function to refer to a non-static buffer,\n      but then you take responsibility for ensuring that the underlying\n      buffer exists for at least as long as the slice, and any copies\n      made of the slice.\n\n   As with all slices, you **must** ensure that you call\n   :c:func:`cork_slice_finish` when you're done with the slice.\n\n\n.. function:: void cork_slice_init_copy_once(struct cork_slice \\*dest, const void \\*buf, size_t size)\n\n   Initializes *dest* to point at the given buffer.  If any copies are made of\n   the slice, then we create a :ref:`managed copy <managed-buffer>` of the\n   underlying buffer.  This means that you only have to ensure that *buf* exists\n   for as long as the original *dest* slice is used.\n\n   As with all slices, you **must** ensure that you call\n   :c:func:`cork_slice_finish` when you're done with the slice.\n"
  },
  {
    "path": "docs/old/stream.rst",
    "content": ".. _stream:\n\n*****************\nStream processing\n*****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/ds.h>\n\n\nStream producers\n----------------\n\nA *producer* of binary data should take in a pointer to a\n:c:type:`cork_stream_consumer` instance.  Any data that is produced by the\nstream is then sent into the consumer instance for processing.  Once the stream\nhas been exhausted (for instance, by reaching the end of a file), you signal\nthis to the consumer.  During both of these steps, the consumer is able to\nsignal error conditions; for instance, a stream consumer that parses a\nparticular file format might return an error condition if the stream of data is\nmalformed.  If possible, the stream producer can try to recover from the error\ncondition, but more often, the stream producer will simply pass the error back\nup to its caller.\n\n.. function:: int cork_stream_consumer_data(struct cork_stream_consumer \\*consumer, const void \\*buf, size_t size, bool is_first_chunk)\n\n   Send the next chunk of data into a stream consumer.  You only have to ensure\n   that *buf* is valid for the duration of this function call; the stream\n   consumer is responsible for saving a copy of the data if it needs to be\n   processed later.  In particular, this means that it's perfectly safe for\n   *buf* to refer to a stack-allocated memory region.\n\n.. function:: int cork_stream_consumer_eof(struct cork_stream_consumer \\*consumer)\n\n   Notify the stream consumer that the end of the stream has been reached.  The\n   stream consumer might perform some final validation and error detection at\n   this point.\n\n.. function:: void cork_stream_consumer_free(struct cork_stream_consumer \\*consumer)\n\n   Finalize and deallocate a stream consumer.\n\n\nBuilt-in stream producers\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe provide several built-in stream producers:\n\n.. function:: int cork_consume_fd(struct cork_stream_consumer \\*consumer, int fd)\n              int cork_consume_file(struct cork_stream_consumer \\*consumer, FILE \\*fp)\n              int cork_consume_file_from_path(struct cork_stream_consumer \\*consumer, const char \\*path, int flags)\n\n   Read in a file, passing its contents into the given stream consumer.  The\n   ``_fd`` and ``_file`` variants consume a file that you've already opened; you\n   are responsible for closing the file after its been consumed.  The\n   ``_file_from_path`` variant will open the file for you, using the standard\n   ``open(2)`` function with the given *flags*.  This variant will close the\n   file before returning, regardless of whether the file was successfully\n   consumed or not.\n\n\nFile stream producer example\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAs an example, we could implement the :c:func:`cork_consume_file` stream\nproducer as follows::\n\n  #include <stdio.h>\n  #include <libcork/core.h>\n  #include <libcork/helpers/errors.h>\n  #include <libcork/ds.h>\n\n  #define BUFFER_SIZE  65536\n\n  int\n  cork_consume_file(struct cork_stream_consumer *consumer, FILE *fp)\n  {\n      char  buf[BUFFER_SIZE];\n      size_t  bytes_read;\n      bool  first = true;\n\n      while ((bytes_read = fread(buf, 1, BUFFER_SIZE, fp)) > 0) {\n          rii_check(cork_stream_consumer_data(consumer, buf, bytes_read, first));\n          first = false;\n      }\n\n      if (feof(fp)) {\n          return cork_stream_consumer_eof(consumer);\n      } else {\n          cork_system_error_set();\n          return -1;\n      }\n  }\n\nNote that this stream producer does not take care of opening or closing\nthe ``FILE`` object, nor does it take care of freeing the consumer.  (Our actual\nimplementation of :c:func:`cork_consume_file` also correctly handles ``EINTR``\nerrors, and so is a bit more complex.  But this example still works as an\nillustration of how to pass data into a stream consumer.)\n\n\n.. _stream-consumers:\n\nStream consumers\n----------------\n\nTo consume data from a stream, you must create a type that implements the\n:c:type:`cork_stream_consumer` interface.\n\n.. type:: struct cork_stream_consumer\n\n   An interface for consumer a stream of binary data.  The producer of\n   the stream will call the :c:func:`cork_stream_consumer_data()`\n   function repeatedly, once for each successive chunk of data in the\n   stream.  Once the stream has been exhausted, the producer will call\n   :c:func:`cork_stream_consumer_eof()` to signal the end of the stream.\n\n   .. member:: int (\\*data)(struct cork_stream_consumer \\*consumer, const void \\*buf, size_t size, bool is_first_chunk)\n\n      Process the next chunk of data in the stream.  *buf* is only\n      guaranteed to be valid for the duration of this function call.  If\n      you need to access the contents of the slice later, you must save\n      it somewhere yourself.\n\n      If there is an error processing this chunk of data, you should\n      return ``-1`` and fill in the current error condition using\n      :c:func:`cork_error_set`.\n\n   .. member:: int (\\*eof)(struct cork_stream_consumer \\*consumer)\n\n      Handle the end of the stream.  This allows you to defer any final\n      validation or error detection until all of the data has been\n      processed.\n\n      If there is an error detected at this point, you should return\n      ``-1`` and fill in the current error condition using\n      :c:func:`cork_error_set`.\n\n   .. member:: void (\\*free)(struct cork_stream_consumer \\*consumer)\n\n      Free the consumer object.\n\n\nBuilt-in stream consumers\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe provide several built-in stream consumers:\n\n.. function:: struct cork_stream_consumer \\*cork_fd_consumer_new(int fd)\n              struct cork_stream_consumer \\*cork_file_consumer_new(FILE \\*fp)\n              struct cork_stream_consumer \\*cork_file_from_path_consumer_new(const char \\*path, int flags)\n\n   Create a stream consumer that appends any data that it receives to a file.\n   The ``_fd`` and ``_file`` variants append to a file that you've already\n   opened; you are responsible for closing the file after the consumer has\n   finished processing data.  The ``_file_from_path`` variant will open the file\n   for you, using the standard ``open(2)`` function with the given *flags*.\n   This variant will close the file before returning, regardless of whether the\n   stream consumer successfully processed the data or not.\n\n\nFile stream consumer example\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAs an example, we could implement a stream consumer for the\n:c:func:`cork_file_consumer_new` function as follows::\n\n  #include <stdio.h>\n  #include <libcork/core.h>\n  #include <libcork/helpers/errors.h>\n  #include <libcork/ds.h>\n\n  struct cork_file_consumer {\n      /* cork_file_consumer implements the cork_stream_consumer interface */\n      struct cork_stream_consumer  parent;\n      /* the file to write the data into */\n      FILE  *fp;\n  };\n\n  static int\n  cork_file_consumer__data(struct cork_stream_consumer *vself,\n                           const void *buf, size_t size, bool is_first)\n  {\n      struct file_consumer  *self =\n          cork_container_of(vself, struct cork_file_consumer, parent);\n      size_t  bytes_written = fwrite(buf, 1, size, self->fp);\n      /* If there was an error writing to the file, then signal this to\n       * the producer */\n      if (bytes_written == size) {\n          return 0;\n      } else {\n          cork_system_error_set();\n          return -1;\n      }\n  }\n\n  static int\n  cork_file_consumer__eof(struct cork_stream_consumer *vself)\n  {\n      /* We don't close the file, so there's nothing special to do at\n       * end-of-stream. */\n      return 0;\n  }\n\n  static void\n  cork_file_consumer__free(struct cork_stream_consumer *vself)\n  {\n      struct file_consumer  *self =\n          cork_container_of(vself, struct cork_file_consumer, parent);\n      free(self);\n  }\n\n  struct cork_stream_consumer *\n  cork_file_consumer_new(FILE *fp)\n  {\n      struct cork_file_consumer  *self = cork_new(struct cork_file_consumer);\n      self->parent.data = cork_file_consumer__data;\n      self->parent.eof = cork_file_consumer__eof;\n      self->parent.free = cork_file_consumer__free;\n      self->fp = fp;\n      return &self->parent;\n  }\n\nNote that this stream consumer does not take care of opening or closing the\n``FILE`` object.\n"
  },
  {
    "path": "docs/old/subprocess.rst",
    "content": ".. _subprocesses:\n\n************\nSubprocesses\n************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/os.h>\n\nThe functions in this section let you fork child processes, run arbitrary\ncommands in them, and collect any output that they produce.\n\n\nSubprocess objects\n~~~~~~~~~~~~~~~~~~\n\n.. type:: struct cork_subprocess\n\n   Represents a child process.  There are several functions for creating child\n   processes, described below.\n\n\n.. function:: void cork_subprocess_free(struct cork_subprocess \\*sub)\n\n   Free a subprocess.  The subprocess must not currently be executing.\n\n\nCreating subprocesses\n~~~~~~~~~~~~~~~~~~~~~\n\nThere are several functions that you can use to create and execute child\nprocesses.\n\n.. function:: struct cork_subprocess \\*cork_subprocess_new(void \\*user_data, cork_free_f free_user_data, cork_run_f run, struct cork_stream_consumer \\*stdout, struct cork_stream_consumer \\*stderr, int \\*exit_code)\n              struct cork_subprocess \\*cork_subprocess_new_exec(struct cork_exec \\*exec, struct cork_stream_consumer \\*stdout, struct cork_stream_consumer \\*stderr, int \\*exit_code)\n\n   Create a new subprocess specification.  The first variant will execute the\n   given *run* function in the subprocess.  The second variant will execute a\n   new program in the subprocess; the details of the program to execute are\n   given by a :c:type:`cork_exec` specification object.\n\n   For both of these functions, you can collect the data that the subprocess\n   writes to its stdout and stderr streams by passing in :ref:`stream consumer\n   <stream-consumers>` instances for the *stdout* and/or *stderr* parameters.\n   If either (or both) of these parameters is ``NULL``, then the child process\n   will inherit the corresponding output stream from the current process.\n   (Usually, this means that the child's stdout or stderr will be interleaved\n   with the parent's.)\n\n   If you provide a non-``NULL`` pointer for the *exit_code* parameter, then we\n   will fill in this pointer with the exit code of the subprocess when it\n   finishes.  For :c:func:`cork_subprocess_new_exec`, the exit code is the value\n   passed to the builtin ``exit`` function, or the value returned from the\n   subprocess's ``main`` function.  For :c:func:`cork_subprocess_new`, the exit\n   code is the value returned from the thread body's *run* function.\n\n\nYou can also create *groups* of subprocesses.  This lets you start up several\nsubprocesses at the same time, and wait for them all to finish.\n\n.. type:: struct cork_subprocess_group\n\n   A group of subprocesses that will all be executed simultaneously.\n\n.. function:: struct cork_subprocess_group \\*cork_subprocess_group_new(void)\n\n   Create a new group of subprocesses.  The group will initially be empty.\n\n.. function:: void cork_subprocess_group_free(struct cork_subprocess_group \\*group)\n\n   Free a subprocess group.  This frees all of the subprocesses in the group,\n   too.  If you've started executing the subprocesses in the group, you **must\n   not** call this function until they have finished executing.  (You can use\n   the :c:func:`cork_subprocess_group_is_finished` function to see if the group\n   is still executing, and the :c:func:`cork_subprocess_group_abort` to\n   terminate the subprocesses before freeing the group.)\n\n.. function:: void cork_subprocess_group_add(struct cork_subprocess_group \\*group, struct cork_subprocess \\*sub)\n\n   Add the given subprocess to *group*.  The group takes control of the\n   subprocess; you should not try to free it yourself.\n\n\nOnce you've created your subprocesses, you can start them executing:\n\n.. function:: int cork_subprocess_start(struct cork_subprocess \\*sub)\n              int cork_subprocess_group_start(struct cork_subprocess_group \\*group)\n\n   Execute the given subprocess, or all of the subprocesses in *group*.  We\n   immediately return once the processes have been started.  You can use the\n   :c:func:`cork_subprocess_drain`, :c:func:`cork_subprocess_wait`,\n   :c:func:`cork_subprocess_group_drain`, and\n   :c:func:`cork_subprocess_group_wait` functions to wait for the subprocesses\n   to complete.\n\n   If there are any errors starting the subprocesses, we'll terminate any\n   subprocesses that we were able to start, set an :ref:`error condition\n   <errors>`, and return ``-1``.\n\n\nSince we immediately return after starting the subprocesses, you must somehow\nwait for them to finish.  There are two strategies for doing so.  If you don't\nneed to communicate with the subprocesses (by writing to their stdin streams or\nsending them signals), the simplest strategy is to just wait for them to finish:\n\n.. function:: int cork_subprocess_wait(struct cork_subprocess \\*sub)\n              int cork_subprocess_group_wait(struct cork_subprocess_group \\*group)\n\n   Wait until the given subprocess, or all of the subprocesses in *group*, have\n   finished executing.  While waiting, we'll continue to read data from the\n   subprocesses stdout and stderr streams as we can.\n\n   If there are any errors reading from the subprocesses, we'll terminate all of\n   the subprocesses that are still executing, set an :ref:`error condition\n   <errors>`, and return ``-1``.  If the group has already finished, the\n   function doesn't do anything.\n\nAs an example::\n\n    struct cork_subprocess_group  *group = /* from somewhere */;\n    /* Wait for the subprocesses to finish */\n    if (cork_subprocess_group_wait(group) == -1) {\n        /* An error occurred; handle it! */\n    }\n\n    /* At this point, we're guaranteed that the subprocesses have all been\n     * terminated; either everything finished successfully, or the subprocesses\n     * were terminated for us when an error was detected. */\n    cork_subprocess_group_free(group);\n\n\nIf you do need to communicate with the subprocesses, then you need more control\nover when we try to read from their stdout and stderr streams.  (The pipes that\nconnect the subprocesses to the parent process are fixed size, and so without\ncareful orchestration, you can easily get a deadlock.  Moreover, the right\npattern of reading and writing depends on the subprocesses that you're\nexecuting, so it's not something that we can handle for you automatically.)\n\n.. function:: struct cork_stream_consumer \\*cork_subprocess_stdin(struct cork_subprocess \\*sub)\n\n   Return a :ref:`stream consumer <stream-consumers>` that lets you write data\n   to the subprocess's stdin.  We do not buffer this data in any way; calling\n   :c:func:`cork_stream_consumer_data` immediately tries to write the given data\n   to the subprocess's stdin stream.  This can easily lead to deadlock if you do\n   not manage the subprocess's particular orchestration correctly.\n\n.. function:: bool cork_subprocess_is_finished(struct cork_subprocess \\*sub)\n              bool cork_subprocess_group_is_finished(struct cork_subprocess_group \\*group)\n\n   Return whether the given subprocess, or all of the subprocesses in *group*,\n   have finished executing.\n\n.. function:: int cork_subprocess_abort(struct cork_subprocess \\*sub)\n              int cork_subprocess_group_abort(struct cork_subprocess_group \\*group)\n\n   Immediately terminate the given subprocess, or all of the subprocesses in\n   *group*.  This can be used to clean up if you detect an error condition and\n   need to close the subprocesses early.  If the group has already finished, the\n   function doesn't do anything.\n\n.. function:: bool cork_subprocess_drain(struct cork_subprocess \\*sub)\n              bool cork_subprocess_group_drain(struct cork_subprocess_group \\*group)\n\n   Check the given subprocess, or all of the subprocesses in *group*, for any\n   output on their stdout and stderr streams.  We'll read in as much data as we\n   can from all of the subprocesses without blocking, and then return.  (Of\n   course, we only do this for those subprocesses that you provided stdout or\n   stderr consumers for.)\n\n   This function lets you pass data into the subprocesses's stdin streams, or\n   (**TODO: eventually**) send them signals, and handle any orchestration that's\n   necessarily to ensure that the subprocesses don't deadlock.\n\n   The return value indicates whether any \"progress\" was made.  We will return\n   ``true`` if we were able to read any data from any of the subprocesses, or if\n   we detected that any of the subprocesses exited.\n\n   If there are any errors reading from the subprocesses, we'll terminate all of\n   the subprocesses that are still executing, set an :ref:`error condition\n   <errors>`, and return ``false``.  If the group has already finished, the\n   function doesn't do anything.\n\nTo do this, you continue to \"drain\" the subprocesses whenever you're ready to\nread from their stdout and stderr streams.  You repeat this in a loop, writing\nto the stdin streams or sending signals as necessary, until all of the\nsubprocesses have finished::\n\n    struct cork_subprocess_group  *group = /* from somewhere */;\n    while (!cork_subprocess_group_is_finished(group)) {\n        /* Drain the stdout and stderr streams */\n        if (cork_subprocess_group_drain(group) == -1) {\n            /* An error occurred; handle it! */\n        } else {\n            /* Write to the stdin streams or send signals */\n        }\n    }\n\n    /* At this point, we're guaranteed that the subprocesses have all been\n     * terminated; either everything finished successfully, or the subprocesses\n     * were terminated for us when an error was detected. */\n    cork_subprocess_group_free(group);\n"
  },
  {
    "path": "docs/old/threads.rst",
    "content": ".. _multithreading:\n\n**********************\nMultithreading support\n**********************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/threads.h>\n\nlibcork provides several functions for handling threads and writing\nthread-aware code in a portable way.\n\n\n.. _thread-ids:\n\nThread IDs\n==========\n\n.. type:: unsigned int cork_thread_id\n\n   An identifier for a thread in the current process.  This is a portable type;\n   it is not based on the \"raw\" thread ID used by the underlying thread\n   implementation.  This type will always be equivalent to ``unsigned int``, on\n   all platforms.  Furthermore, :c:data:`CORK_THREAD_NONE` will always refer to\n   an instance of this type that we guarantee will not be used by any thread.\n\n.. var:: cork_thread_id CORK_THREAD_NONE\n\n   A :c:type:`cork_thread_id` value that will not be used as the ID of any\n   thread.  You can use this value to represent \"no thread\" in any data\n   structures you create.  Moreover, we guarantee that ``CORK_THREAD_NONE`` will\n   have the value ``0``, which lets you zero-initialize a data structure\n   containing a :c:type:`cork_thread_id`, and have its initial state\n   automatically represent \"no thread\".\n\n.. function:: cork_thread_id cork_current_thread_get_id(void)\n\n   Returns the identifier of the currently executing thread.  This function\n   works correctly for any thread in the current proces --- including the main\n   thread, and threads that weren't created by :c:func:`cork_thread_new`.\n\n\n.. _threads:\n\nCreating threads\n================\n\nThe functions in this section let you create and start new threads in the\ncurrent process.  Each libcork thread is named and has a unique :ref:`thread ID\n<thread-ids>`.  Each thread also contains a ``run`` function, which defines the\ncode that should be executed within the new thread.\n\nEvery thread goes through the same lifecycle:\n\n1) You create a new thread via :c:func:`cork_thread_new`.  At this point, the\n   thread is ready to execute, but isn't automatically started.  If you\n   encounter an error before you start the thread, you must use\n   :c:func:`cork_thread_free` to free the thread object.\n\n   When you create the thread, you give it a :c:type:`cork_run_f` function,\n   which defines the code that will be executed in the new thread.  You also\n   provide a ``user_data`` value, which it gives you a place to pass data into\n   and out of the thread.\n\n   .. note::\n\n      Any data passed into and out of the thread via the body instance is not\n      automatically synchronized or thread-safe.  You can safely pass in input\n      data before calling :c:type:`cork_thread_new`, and retrieve output data\n      after calling :c:type:`cork_thread_join`, all without requiring any extra\n      synchronization effort.  While the thread is executing, however, you must\n      implement your own synchronization or locking to access the contents of\n      the body from some other thread.\n\n2) You start the thread via :c:func:`cork_thread_start`.  You must ensure that\n   you don't try to start a thread more than once.  Once you've started a\n   thread, you no longer have responsibility for freeing it; you must ensure\n   that you don't call :c:func:`cork_thread_free` on a thread that you've\n   started.\n\n3) Once you've started a thread, you wait for it to finish via\n   :c:func:`cork_thread_join`.  Any thread can wait for any other thread to\n   finish, although you are responsible for ensuring that your threads don't\n   deadlock.  However, you can only join a particular thread once.\n\n\n\n\n.. type:: struct cork_thread\n\n   A thread within the current process.  This type is opaque; you must use the\n   functions defined below to interact with the thread.\n\n\n.. function:: struct cork_thread \\*cork_thread_new(const char \\*name, void \\*user_data, cork_free_f free_user_data, cork_run_f run)\n\n   Create a new thread with the given *name* that will execute *run*.  The\n   thread does not start running immediately.\n\n   When the thread is started, the *run* function will be called with\n   *user_data* as its only parameter.  When the thread finishes (or if it is\n   freed via :c:func:`cork_thread_free` before the thread is started), we'll use\n   the *free_user_data* function to free the *user_data* value.  You can provide\n   ``NULL`` if *user_data* shouldn't be freed, or if you want to free it\n   yourself.\n\n   .. note::\n\n      If you provide a *free_user_data* function, it will be called as soon as\n      the thread finished.  That means that if you use\n      :c:func:`cork_thread_join` to wait for the thread to finish, the\n      *user_data* value will no longer be valid when :c:func:`cork_thread_join`\n      returns.  You must either copy any necessary data out into more a more\n      persistent memory location before the thread finishes, or you should use a\n      ``NULL`` *free_user_data* function and free the *user_data* memory\n      yourself once you're sure the thread has finished.\n\n\n.. function:: void cork_thread_free(struct cork_thread \\*thread)\n\n   Free *thread*.  You can only call this function if you haven't started the\n   thread yet.  Once you start a thread, the thread is responsible for freeing\n   itself when it finishes.\n\n.. function:: struct cork_thread \\*cork_current_thread_get(void)\n\n   Return the :c:type:`cork_thread` instance for the current thread.  This\n   function returns ``NULL`` when called from the main thread (i.e., the one\n   created automatically when the process starts), or from a thread that wasn't\n   created via :c:func:`cork_thread_new`.\n\n.. function:: const char \\* cork_thread_get_name(struct cork_thread \\*thread)\n              cork_thread_id cork_thread_get_id(struct cork_thread \\*thread)\n\n   Retrieve information about the given thread.\n\n.. function:: int cork_thread_start(struct cork_thread \\*thread)\n\n   Start *thread*.  After calling this function, you must not try to free\n   *thread* yourself; the thread will automatically free itself once it has\n   finished executing and has been joined.\n\n.. function:: int cork_thread_join(struct cork_thread \\*thread)\n\n   Wait for *thread* to finish executing.  If the thread's body's ``run``\n   function an :ref:`error condition <errors>`, we will catch that error and\n   return it ourselves.  The thread is automatically freed once it finishes\n   executing.\n\n   You cannot join a thread that has not been started, and once you've started a\n   thread, you **must** join it exactly once.  (If you don't join it, there's no\n   guarantee that it will be freed.)\n\n\n.. _atomics:\n\nAtomic operations\n=================\n\nWe provide several platform-agnostic macros for implementing common\natomic operations.\n\n\nAddition\n~~~~~~~~\n\n.. function:: int cork_int_atomic_add(volatile int \\*var, int delta)\n              unsigned int cork_uint_atomic_add(volatile unsigned int \\*var, unsigned int delta)\n              size_t cork_size_atomic_add(volatile size_t \\*var, size_t delta)\n\n   Atomically add *delta* to the variable pointed to by *var*, returning\n   the result of the addition.\n\n.. function:: int cork_int_atomic_pre_add(volatile int \\*var, int delta)\n              unsigned int cork_uint_atomic_pre_add(volatile unsigned int \\*var, unsigned int delta)\n              size_t cork_size_atomic_pre_add(volatile size_t \\*var, size_t delta)\n\n   Atomically add *delta* to the variable pointed to by *var*, returning\n   the value from before the addition.\n\n\nSubtraction\n~~~~~~~~~~~\n\n.. function:: int cork_int_atomic_sub(volatile int \\*var, int delta)\n              unsigned int cork_uint_atomic_sub(volatile unsigned int \\*var, unsigned int delta)\n              size_t cork_size_atomic_sub(volatile size_t \\*var, size_t delta)\n\n   Atomically subtract *delta* from the variable pointed to by *var*,\n   returning the result of the subtraction.\n\n.. function:: int cork_int_atomic_pre_sub(volatile int \\*var, int delta)\n              unsigned int cork_uint_atomic_pre_sub(volatile unsigned int \\*var, unsigned int delta)\n              size_t cork_size_atomic_pre_sub(volatile size_t \\*var, size_t delta)\n\n   Atomically subtract *delta* from the variable pointed to by *var*,\n   returning the value from before the subtraction.\n\n\nCompare-and-swap\n~~~~~~~~~~~~~~~~\n\n.. function:: int cork_int_cas(volatile int_t \\*var, int old_value, int new_value)\n              unsigned int cork_uint_cas(volatile uint_t \\*var, unsigned int old_value, unsigned int new_value)\n              size_t cork_size_cas(volatile size_t \\*var, size_t old_value, size_t new_value)\n              TYPE \\*cork_ptr_cas(TYPE \\* volatile \\*var, TYPE \\*old_value, TYPE \\*new_value)\n\n   Atomically check whether the variable pointed to by *var* contains\n   the value *old_value*, and if so, update it to contain the value\n   *new_value*.  We return the value of *var* before the\n   compare-and-swap.  (If this value is equal to *old_value*, then the\n   compare-and-swap was successful.)\n\n\n.. _once:\n\nExecuting something once\n========================\n\nThe functions in this section let you ensure that a particular piece of\ncode is executed exactly once, even if multiple threads attempt the\nexecution at roughly the same time.\n\n.. macro:: cork_once_barrier(name)\n\n   Declares a barrier that can be used with the :c:func:`cork_once`\n   macro.\n\n.. macro:: cork_once(barrier, call)\n           cork_once_recursive(barrier, call)\n\n   Ensure that *call* (which can be an arbitrary statement) is executed\n   exactly once, regardless of how many times control reaches the call\n   to ``cork_once``.  If control reaches the ``cork_once`` call at\n   roughly the same time in multiple threads, exactly one of them will\n   be allowed to execute the code.  The call to ``cork_once`` won't\n   return until *call* has been executed.\n\n   If you have multiple calls to ``cork_once`` that use the same\n   *barrier*, then exactly one *call* will succeed.  If the *call*\n   statements are different in those ``cork_once`` invocations, then\n   it's undefined which one gets executed.\n\n   If the function that contains the ``cork_once`` call is recursive, then you\n   should call the ``_recursive`` variant of the macro.  With the ``_recursive``\n   variant, if the same thread tries to obtain the underlying lock multiple\n   times, the second and later calls will silently succeed.  With the regular\n   variant, you'll get a deadlock in this case.\n\nThese macros are usually used to initialize a static variable that will\nbe shared across multiple threads::\n\n    static struct my_type  shared_value;\n\n    static void\n    expensive_initialization(void)\n    {\n        /* do something to initialize shared_value */\n    }\n\n    cork_once_barrier(shared_value_once);\n\n    struct my_type *\n    get_shared_value(void)\n    {\n        cork_once(shared_value_once, expensive_initialization());\n        return &shared_value;\n    }\n\nEach thread can then call ``get_shared_value`` to retrieve a properly\ninitialized instance of ``struct my_type``.  Regardless of how many\nthreads call this function, and how often they call it, the value will\nbe initialized exactly once, and will be guaranteed to be initialized\nbefore any thread tries to use it.\n\n\n.. _tls:\n\nThread-local storage\n====================\n\nThe macro in this section can be used to create thread-local storage in\na platform-agnostic manner.\n\n.. macro:: cork_tls(TYPE type, SYMBOL name)\n\n   Creates a static function called :samp:`{[name]}_get`, which will\n   return a pointer to a thread-local instance of *type*.  This is a\n   static function, so it won't be visible outside of the current\n   compilation unit.\n\n   When a particular thread's instance is created for the first time, it\n   will be filled with ``0`` bytes.  If the actual type needs more\n   complex initialization before it can be used, you can create a\n   wrapper struct that contains a boolean indiciating whether that\n   initialization has happened::\n\n       struct wrapper {\n           bool  initialized;\n           struct real_type  val;\n       };\n\n       cork_tls(struct wrapper, wrapper);\n\n       static struct real_type *\n       real_type_get(void)\n       {\n           struct wrapper * wrapper = wrapper_get();\n           struct real_type * real_val = &wrapper->val;\n           if (CORK_UNLIKELY(!wrapper->initialized)) {\n               expensive_initialization(real_val);\n           }\n           return real_val;\n       }\n\n   It's also not possible to provide a finalization function; if your\n   thread-local variable acquires any resources or memory that needs to\n   be freed when the thread finishes, you must make a “thread cleanup”\n   function that you explicitly call at the end of each thread.\n\n   .. note::\n\n      On some platforms, the number of thread-local values that can be\n      created by any given process is limited (i.e., on the order of 128\n      or 256 values).  This means that you should limit the number of\n      thread-local values you create, especially in a library.\n"
  },
  {
    "path": "docs/old/timestamps.rst",
    "content": ".. _timestamps:\n\n*************************\nHigh-precision timestamps\n*************************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\n\n.. type:: uint64_t  cork_timestamp\n\n   A high-precision timestamp type.  A timestamp is represented by a\n   64-bit integer, whose unit is the *gammasecond* (γsec), where\n   :math:`1~\\textrm{γsec} = \\frac{1}{2^{32}} \\textrm{sec}`.  With this\n   representation, the upper 32 bits of a timestamp value represent the\n   timestamp truncated (towards zero) to seconds.\n\n   For this type, we don't concern ourselves with any higher-level\n   issues of clock synchronization or time zones.  ``cork_timestamp``\n   values can be used to represent any time quantity, regardless of\n   which time standard (UTC, GMT, TAI) you use, or whether it takes into\n   account the local time zone.\n\n\n.. function:: void cork_timestamp_init_sec(cork_timestamp \\*ts, uint32_t sec)\n              void cork_timestamp_init_gsec(cork_timestamp \\*ts, uint32_t sec, uint32_t gsec)\n              void cork_timestamp_init_msec(cork_timestamp \\*ts, uint32_t sec, uint32_t msec)\n              void cork_timestamp_init_usec(cork_timestamp \\*ts, uint32_t sec, uint32_t usec)\n              void cork_timestamp_init_nsec(cork_timestamp \\*ts, uint32_t sec, uint32_t nsec)\n\n   Initializes a timestamp from a separate seconds part and fractional\n   part.  For the ``_sec`` variant, the fractional part will be set to\n   ``0``.  For the ``_gsec`` variant, you provide the fractional part in\n   gammaseconds.  For the ``_msec``, ``_usec``, and ``_nsec`` variants, the\n   fractional part will be translated into gammaseconds from milliseconds,\n   microseconds, or nanoseconds, respectively.\n\n\n.. function:: void cork_timestamp_init_now(cork_timestamp \\*ts)\n\n   Initializes a timestamp with the current UTC time of day.\n\n   .. note::\n\n      The resolution of this function is system-dependent.\n\n\n.. function:: uint32_t cork_timestamp_sec(const cork_timestamp ts)\n\n   Returns the seconds portion of a timestamp.\n\n.. function:: uint32_t cork_timestamp_gsec(const cork_timestamp ts)\n              uint32_t cork_timestamp_msec(const cork_timestamp ts)\n              uint32_t cork_timestamp_usec(const cork_timestamp ts)\n              uint32_t cork_timestamp_nsec(const cork_timestamp ts)\n\n   Returns the fractional portion of a timestamp.  The variants return the\n   fractional portion in, respectively, gammaseconds, milliseconds,\n   microseconds, or nanoseconds.\n\n\n.. function:: int cork_timestamp_format_utc(const cork_timestamp ts, const char \\*format, struct cork_buffer \\*buf)\n              int cork_timestamp_format_local(const cork_timestamp ts, const char \\*format, struct cork_buffer \\*buf)\n\n   Create the string representation of the given timestamp according to\n   *format*, appending the result to the current contents of *buf*.\n\n   The ``_utc`` variant assumes that *ts* represents a UTC time, whereas the\n   ``_local`` variant assumes that it represents a time in the local time zone.\n\n   *format* is a format string whose syntax is similar to that of the POSIX\n   ``strftime`` function.  *format* must contain arbitrary text interspersed\n   with ``%`` specifiers, which will be replaced with portions of the timestamp.\n   The following specifiers are recognized (note that this list does **not**\n   include all of the specifiers supported by ``strftime``):\n\n   ============== ====================================================\n   Specifier      Replacement\n   ============== ====================================================\n   ``%%``         A literal ``%`` character\n   ``%d``         Day of month (``01``-``31``)\n   ``%[width]f``  Fractional seconds (zero-padded, limited to ``[width]``\n                  digits)\n   ``%H``         Hour in current day (``00``-``23``)\n   ``%m``         Month (``01``-``12``)\n   ``%M``         Minute in current hour (``00``-``59``)\n   ``%s``         Number of seconds since Unix epoch\n   ``%S``         Second in current minute (``00``-``60``)\n   ``%Y``         Four-digit year (including century)\n   ============== ====================================================\n\n   If the format string is invalid, we will return an :ref:`error condition\n   <errors>`.\n"
  },
  {
    "path": "docs/old/unique-ids.rst",
    "content": ".. _unique-ids:\n\n******************\nUnique identifiers\n******************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\n\nThe functions in this section let you define compile-time unique identifiers.\nThese identifiers are simple C variables, and each one is guaranteed to be\nunique within the context of a single execution of your program.  They are *not*\nappropriate for use as external identifiers --- for instance, for serializing\ninto long-term storage or sending via a communications channel to another\nprocess.\n\n\n.. type:: cork_uid\n\n   A unique identifier.\n\n\n.. macro:: cork_uid  CORK_UID_NONE\n\n   A unique identifier value that means \"no identifier\".  This is guaranteed to\n   be distinct from all other unique identifiers.  It is invalid to call\n   :c:func:`cork_uid_hash`, :c:func:`cork_uid_id`, or :c:func:`cork_uid_name` on\n   this identifier.\n\n\n.. macro:: cork_uid_define(SYMBOL id)\n           cork_uid_define_named(SYMBOL id, const char \\*name)\n\n   You use the :c:func:`cork_uid_define` macro to define a new unique identifier\n   with the given C identifier *id*.  The ``_define`` variant also uses *id* as\n   the identifier's human-readable name; the ``_define_named`` variant let's you\n   provide a separate human-readable name.  Within the context of a single\n   execution of this program, this identifier is guaranteed to be distinct from\n   any other identifier, regardless of which library the identifiers are defined\n   in.\n\n   In the same compilation unit, you can then use the C identifier *id* to\n   retrieve the :c:type:`cork_uid` instance for this identifier.\n\n   .. note::\n\n      The unique identifier objects are declared ``static``, so they are only\n      directly visible (using the C identifier *id*) in the same compilation\n      unit as the :c:func:`cork_uid_define` call that created the identifier.\n      The resulting :c:type:`cork_uid` value, however, can be passed around the\n      rest of your code however you want.\n\n\n.. function:: bool cork_uid_equal(const cork_uid id1, const cork_uid id2)\n\n   Return whether two :c:type:`cork_uid` values refer to the same unique\n   identifier.\n\n\n.. function:: cork_hash cork_uid_hash(const cork_uid id)\n\n   Return a :ref:`hash value <hash-values>` for the given identifier.\n\n\n.. function:: const char \\*cork_uid_name(const cork_uid id)\n\n   Return the name of the given unique identifier.\n\n\nExample\n=======\n\n::\n\n    #include <stdio.h>\n    #include <libcork/core.h>\n\n    cork_uid_define(test_id);\n\n    int\n    main(void)\n    {\n        cork_uid  id = test_id;\n        printf(\"Identifier %p has name %s\\n\", id, cork_uid_name(id));\n        return 0;\n    }\n"
  },
  {
    "path": "docs/old/versions.rst",
    "content": ".. _versions:\n\n***************\nLibrary version\n***************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nThe macros and functions in this section let you determine the version of the\nlibcork library at compile-time and runtime, and make it easier for you to\ndefine similar macros and functions in your own libraries.\n\n\nlibcork version\n---------------\n\n.. macro:: CORK_VERSION\n\n   The libcork library version, encoded as a single number as follows::\n\n       (major * 1000000) + (minor * 1000) + patch\n\n   For instance, version 1.2.10 would be encoded as 1002010.\n\n.. macro:: CORK_VERSION_MAJOR\n           CORK_VERSION_MINOR\n           CORK_VERSION_PATCH\n\n   The libcork library version, with each part of the version number separated\n   out into separate macros.\n\n\n.. function:: const char \\*cork_version_string(void)\n              const char \\*cork_revision_string(void)\n\n   Return the libcork library version or revision as a string.  The *version* is\n   the simple three-part version number (``major:minor:patch``).  The\n   *revision* is an opaque string that identifies the specific revision in\n   libcork's code history.  (Right now, this is a SHA-1 git commit identifier.)\n\n\n.. tip:: Compile-time vs runtime\n\n   There's an important difference between the :c:macro:`CORK_VERSION` macro and\n   :c:func:`cork_version_string` function, even though they seemingly return the\n   same information.\n\n   The macro version be evaluated by the preprocessor, and so it will return the\n   version that was available *when your code was compiled*.  If you later\n   install a newer (but backwards-compatible) version of libcork, any code that\n   called the macro will still have the original version, and not the new\n   version.\n\n   The function version, on the other hand, calculates the version information\n   *at runtime*, when the function is actually called.  That means that the\n   function result will always give you the current installed libcork version,\n   even as newer versions are installed on the system.\n\n\nConstructing version information\n--------------------------------\n\nIf you're writing a library that uses libcork, it's a good idea to provide your\nown version information, similar to how libcork does.\n\n\n.. function:: CORK_MAKE_VERSION(major, minor, patch)\n\n   Assemble a ``major.minor.patch`` version into a single number, using the same\n   pattern as :c:macro:`CORK_VERSION`.\n"
  },
  {
    "path": "docs/old/visibility.rst",
    "content": ".. _visibility:\n\n*****************\nSymbol visibility\n*****************\n\n.. highlight:: c\n\n::\n\n  #include <libcork/core.h>\n\nWhen writing a shared library, you should always be careful to explicitly mark\nwhich functions and other symbols are part of the library's public API, and\nwhich should only be used internally by the library.  There are a number of\nbenefits to doing this; there is a good summary on the `GCC wiki`_.  (Note that\neven though that summary is on the GCC wiki, the notes apply equally well to\nother compilers and platforms.)\n\n.. _GCC wiki: http://gcc.gnu.org/wiki/Visibility\n\nlibcork provides several helper macros that make it easier to do this.  We use\nthese macros ourselves to define libcork's public API.\n\n\nDefining a library's public API\n-------------------------------\n\nOn some platforms (for instance, on Windows), you must declare each public\nfunction and symbol differently depending on whether you're compiling the\nlibrary that *defines* the symbol, or a library or program that *uses* the\nsymbol.  The first is called an *export*, the second an *import*.  On other\nplatforms (for instance, GCC on Linux), the declaration of a public symbol is\nthe same regardless of whether you're exporting or importing the symbol.\nlibcork provides macros that let you explicitly declare a symbol as an export or\nan import in a platform-independent way.\n\n.. macro:: CORK_EXPORT\n           CORK_IMPORT\n\n   Explicitly declare that a symbol should be exported from the current shared\n   library, or imported from some other shared library.\n\nHowever, you will rarely need to use these macros directly.  Instead, when\nwriting a new shared library, you should declare a new preprocessor macro\n(specific to the new library), which you'll use when declaring the library's\npublic API.  For instance, if you're creating a new library called\n*libfoo*, you would declare a new preprocessor macro called ``FOO_API``::\n\n    #if !defined(FOO_API)\n    #define FOO_API  CORK_IMPORT\n    #endif\n\nThis ensures that anyone who wants to *use* libfoo doesn't need to do anything\nspecial; the ``FOO_API`` macro will default to importing the symbols from\nlibfoo's public API.\n\nWhen *building* libfoo, you must set up your build system to define this\nvariable differently; since you need to *export* the symbols in this case, the\n``FOO_API`` macro should be set to ``CORK_EXPORT``.  Each build system will have\na different way to do this.  In CMake, for instance, you'd add the following:\n\n.. code-block:: cmake\n\n    set_target_properties(libfoo PROPERTIES\n        COMPILE_DEFINITIONS FOO_API=CORK_EXPORT\n    )\n\nThen, in all of your header files, you should use your new ``FOO_API`` macro\nwhen declaring each function or symbol in the public API::\n\n    FOO_API int\n    foo_load_from_file(const char *name);\n\n    FOO_API void\n    foo_do_something_great(int flags);\n\n    extern FOO_API  const char  *foo_name;\n\n\nLocal symbols\n-------------\n\nNormally, if you need a function to be local, and not be exported as part of the\nlibrary's public API, you can just declare it ``static``::\n\n    static int\n    file_local_function(void)\n    {\n        /* This function is not visible outside of this file. */\n        return 0;\n    }\n\nThis works great as long as the function is only needed within the current\nsource file.  Sometimes, though, you need to define a function that can be used\nin other source files within the same library, but which shouldn't be visible\noutside of the library.  To do this, you should define the function using the\n:c:macro:`CORK_LOCAL` macro.\n\n.. macro:: CORK_LOCAL\n\n   Declare a symbol that should be visible in any source file within the current\n   library, but not visible outside of the library.\n\nAs an example::\n\n    CORK_LOCAL int\n    library_local_function(void)\n    {\n        /* This function is visible in other files, but not outside of the\n         * library. */\n        return 0;\n    }\n\nSince you're going to use this function in multiple files, you'll want to\ndeclare the function in a header file.  However, since the function is not part\nof the public API, this should *not* be defined in a public header file (that\nis, one that's installed along with the shared library).  Instead, you should\ninclude a private header file that's only available in your library's source\ncode archive, and which should not be installed with the other public header\nfiles.\n"
  },
  {
    "path": "extras/hashstring.py",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n# Calculates the 32-bit MurmurHash3 hash value [1] for a string provided on the\n# command line.\n#\n# [1] http://code.google.com/p/smhasher/wiki/MurmurHash3\n\ndef rotl32(a, b):\n    return (((a << (b & 0x1f)) & 0xffffffff) |\n            ((a >> (32 - (b & 0x1f))) & 0xffffffff))\n\ndef fmix(h):\n    h = h ^ (h >> 16)\n    h = (h * 0x85ebca6b) & 0xffffffff\n    h = h ^ (h >> 13)\n    h = (h * 0xc2b2ae35) & 0xffffffff\n    h = h ^ (h >> 16)\n    return h\n\ndef hash(value, seed):\n    import struct\n    length = len(value)\n    num_blocks = length / 4\n    tail_length = length % 4\n    fmt = \"<\" + (\"i\" * num_blocks) + (\"b\" * tail_length)\n    vals = struct.unpack(fmt, value)\n\n    h1 = seed\n    c1 = 0xcc9e2d51\n    c2 = 0x1b873593\n    for block in vals[:num_blocks]:\n        k1 = block\n        k1 = (k1 * c1) & 0xffffffff\n        k1 = rotl32(k1, 15)\n        k1 = (k1 * c2) & 0xffffffff\n\n        h1 = h1 ^ k1\n        h1 = rotl32(h1, 13)\n        h1 = (h1 * 5 + 0xe6546b64) & 0xffffffff\n\n    k1 = 0\n    if tail_length >= 3:\n        k1 = k1 ^ ((vals[num_blocks + 2] << 16) & 0xffffffff)\n    if tail_length >= 2:\n        k1 = k1 ^ ((vals[num_blocks + 1] <<  8) & 0xffffffff)\n    if tail_length >= 1:\n        k1 = k1 ^ ( vals[num_blocks]            & 0xffffffff)\n        k1 = (k1 * c1) & 0xffffffff\n        k1 = rotl32(k1, 15)\n        k1 = (k1 * c2) & 0xffffffff\n        h1 = h1 ^ k1\n\n    h1 = h1 ^ (length & 0xffffffff)\n    return fmix(h1)\n\n\nif __name__ == \"__main__\":\n    import sys\n    if len(sys.argv) != 2 and len(sys.argv) != 3:\n        print(\"Usage: hashstring.py <string> [<seed>]\")\n        sys.exit(1)\n\n    def myhex(v):\n        return hex(v).rstrip(\"L\")\n\n    if len(sys.argv) == 3:\n        seed = long(sys.argv[2]) & 0xffffffff\n    else:\n        seed = 0\n\n    print(myhex(hash(sys.argv[1], seed)))\n"
  },
  {
    "path": "include/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\nconfigure_file(\n    ${CMAKE_CURRENT_SOURCE_DIR}/libcork/config/version.h.in\n    ${CMAKE_CURRENT_BINARY_DIR}/libcork/config/version.h\n    ESCAPE_QUOTES @ONLY\n)\n\ninstall(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/\n    DESTINATION \"${CMAKE_INSTALL_INCLUDEDIR}\"\n    FILES_MATCHING PATTERN \"*.h\")\n\ninstall(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcork/config/version.h\n        DESTINATION include/libcork/config)\n"
  },
  {
    "path": "include/libcork/cli/commands.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_COMMANDS_H\n#define LIBCORK_COMMANDS_H\n\n#include <libcork/core/api.h>\n\n\ntypedef void\n(*cork_leaf_command_run)(int argc, char **argv);\n\ntypedef int\n(*cork_option_parser)(int argc, char **argv);\n\nenum cork_command_type {\n    CORK_COMMAND_SET,\n    CORK_LEAF_COMMAND\n};\n\nstruct cork_command {\n    enum cork_command_type  type;\n    const char  *name;\n    const char  *short_desc;\n    const char  *usage_suffix;\n    const char  *full_help;\n\n    int\n    (*parse_options)(int argc, char **argv);\n\n    struct cork_command  **set;\n    cork_leaf_command_run  run;\n};\n\n#define cork_command_set(name, sd, parse_options, set) \\\n{ \\\n    CORK_COMMAND_SET, name, sd, NULL, NULL, \\\n    parse_options, set, NULL \\\n}\n\n#define cork_leaf_command(name, sd, us, fh, parse_options, run) \\\n{ \\\n    CORK_LEAF_COMMAND, name, sd, us, fh, \\\n    parse_options, NULL, run \\\n}\n\nCORK_API void\ncork_command_show_help(struct cork_command *command, const char *message);\n\nCORK_API int\ncork_command_main(struct cork_command *root, int argc, char **argv);\n\n\n#endif /* LIBCORK_COMMANDS_H */\n"
  },
  {
    "path": "include/libcork/cli.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CLI_H\n#define LIBCORK_CLI_H\n\n/*** include all of the parts ***/\n\n#include <libcork/cli/commands.h>\n\n#endif /* LIBCORK_CLI_H */\n"
  },
  {
    "path": "include/libcork/config/arch.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_ARCH_H\n#define LIBCORK_CONFIG_ARCH_H\n\n\n/*-----------------------------------------------------------------------\n * Platform\n */\n\n#if defined(__i386__) || defined(_M_IX86)\n#define CORK_CONFIG_ARCH_X86  1\n#else\n#define CORK_CONFIG_ARCH_X86  0\n#endif\n\n#if defined(__x86_64__) || defined(_M_X64)\n#define CORK_CONFIG_ARCH_X64  1\n#else\n#define CORK_CONFIG_ARCH_X64  0\n#endif\n\n#if defined(__powerpc__) || defined(__ppc__)\n/* GCC-ish compiler */\n#define CORK_CONFIG_ARCH_PPC  1\n#elif defined(_M_PPC)\n/* VS-ish compiler */\n#define CORK_CONFIG_ARCH_PPC  1\n#elif defined(_ARCH_PPC)\n/* Something called XL C/C++? */\n#define CORK_CONFIG_ARCH_PPC  1\n#else\n#define CORK_CONFIG_ARCH_PPC  0\n#endif\n\n\n#endif /* LIBCORK_CONFIG_ARCH_H */\n"
  },
  {
    "path": "include/libcork/config/bsd.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_BSD_H\n#define LIBCORK_CONFIG_BSD_H\n\n/*-----------------------------------------------------------------------\n * Endianness\n */\n\n#include <sys/endian.h>\n\n#if BYTE_ORDER == BIG_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      1\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   0\n#elif BYTE_ORDER == LITTLE_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      0\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   1\n#else\n#error \"Cannot determine system endianness\"\n#endif\n\n#define CORK_HAVE_REALLOCF  1\n#define CORK_HAVE_PTHREADS  1\n\n\n#endif /* LIBCORK_CONFIG_BSD_H */\n"
  },
  {
    "path": "include/libcork/config/config.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_CONFIG_H\n#define LIBCORK_CONFIG_CONFIG_H\n\n\n/* If you want to skip autodetection, define this to 1, and provide a\n * libcork/config/custom.h header file. */\n\n#if !defined(CORK_CONFIG_SKIP_AUTODETECT)\n#define CORK_CONFIG_SKIP_AUTODETECT  0\n#endif\n\n\n#if CORK_CONFIG_SKIP_AUTODETECT\n/* The user has promised that they'll define everything themselves. */\n#include <libcork/config/custom.h>\n\n#else\n/* Otherwise autodetect! */\n\n\n/**** VERSION ****/\n\n#include <libcork/config/version.h>\n\n\n/**** ARCHITECTURES ****/\n\n#include <libcork/config/arch.h>\n\n\n/**** PLATFORMS ****/\n#if (defined(__unix__) || defined(unix)) && !defined(USG)\n/* We need this to test for BSD, but it's a good idea to have for\n * any brand of Unix.*/\n#include <sys/param.h>\n#endif\n\n#if defined(__linux) || defined(__FreeBSD_kernel__) || defined(__GNU__)\n/* Do some Linux, kFreeBSD or GNU/Hurd specific autodetection. */\n#include <libcork/config/linux.h>\n\n#elif defined(__APPLE__) && defined(__MACH__)\n/* Do some Mac OS X-specific autodetection. */\n#include <libcork/config/macosx.h>\n\n#elif defined(BSD) && (BSD >= 199103)\n/* Do some BSD (4.3 code base or newer)specific autodetection. */\n#include <libcork/config/bsd.h>\n\n#endif  /* platforms */\n\n\n/**** COMPILERS ****/\n\n#if defined(__GNUC__)\n/* Do some GCC-specific autodetection. */\n#include <libcork/config/gcc.h>\n\n#endif  /* compilers */\n\n\n#endif  /* autodetect or not */\n\n\n#endif /* LIBCORK_CONFIG_CONFIG_H */\n"
  },
  {
    "path": "include/libcork/config/gcc.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_GCC_H\n#define LIBCORK_CONFIG_GCC_H\n\n/* Figure out the GCC version */\n\n#if defined(__GNUC_PATCHLEVEL__)\n#define CORK_CONFIG_GCC_VERSION (__GNUC__ * 10000 \\\n                               + __GNUC_MINOR__ * 100 \\\n                               + __GNUC_PATCHLEVEL__)\n#else\n#define CORK_CONFIG_GCC_VERSION (__GNUC__ * 10000 \\\n                               + __GNUC_MINOR__ * 100)\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Compiler attributes\n */\n\n/* The GCC assembly syntax has been available basically forever. */\n\n#if !defined(CORK_CONFIG_HAVE_GCC_ASM)\n#if defined(CORK_CONFIG_GCC_VERSION)\n#define CORK_CONFIG_HAVE_GCC_ASM  1\n#else\n#define CORK_CONFIG_HAVE_GCC_ASM  0\n#endif\n#endif\n\n/* The GCC atomic instrinsics are available as of GCC 4.1.0. */\n\n#if !defined(CORK_CONFIG_HAVE_GCC_ATOMICS)\n#if CORK_CONFIG_GCC_VERSION >= 40100\n#define CORK_CONFIG_HAVE_GCC_ATOMICS  1\n#else\n#define CORK_CONFIG_HAVE_GCC_ATOMICS  0\n#endif\n#endif\n\n/* The attributes we want to use are available as of GCC 2.96. */\n\n#if !defined(CORK_CONFIG_HAVE_GCC_ATTRIBUTES)\n#if CORK_CONFIG_GCC_VERSION >= 29600\n#define CORK_CONFIG_HAVE_GCC_ATTRIBUTES  1\n#else\n#define CORK_CONFIG_HAVE_GCC_ATTRIBUTES  0\n#endif\n#endif\n\n/* C99 inline is available if we're compiling in C99 mode. */\n#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\n#define CORK_CONFIG_HAVE_C99_INLINE  1\n#else\n#define CORK_CONFIG_HAVE_C99_INLINE  0\n#endif\n\n/* __int128 seems to be available on 64-bit platforms as of GCC 4.6.  The\n * attribute((mode(TI))) syntax seems to be available as of 4.1. */\n\n#if !defined(CORK_CONFIG_HAVE_GCC_INT128)\n#if CORK_CONFIG_ARCH_X64 && CORK_CONFIG_GCC_VERSION >= 40600\n#define CORK_CONFIG_HAVE_GCC_INT128  1\n#else\n#define CORK_CONFIG_HAVE_GCC_INT128  0\n#endif\n#endif\n\n#if !defined(CORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE)\n#if CORK_CONFIG_ARCH_X64 && CORK_CONFIG_GCC_VERSION >= 40100\n#define CORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE  1\n#else\n#define CORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE  0\n#endif\n#endif\n\n/* Statement expressions have been available since GCC 3.1. */\n\n#if !defined(CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS)\n#if CORK_CONFIG_GCC_VERSION >= 30100\n#define CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS  1\n#else\n#define CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS  0\n#endif\n#endif\n\n/* Thread-local storage has been available since GCC 3.3, but not on Mac\n * OS X. */\n\n#if !defined(CORK_CONFIG_HAVE_THREAD_STORAGE_CLASS)\n#if !(defined(__APPLE__) && defined(__MACH__))\n#if CORK_CONFIG_GCC_VERSION >= 30300\n#define CORK_CONFIG_HAVE_THREAD_STORAGE_CLASS  1\n#else\n#define CORK_CONFIG_HAVE_THREAD_STORAGE_CLASS  0\n#endif\n#else\n#define CORK_CONFIG_HAVE_THREAD_STORAGE_CLASS  0\n#endif\n#endif\n\n\n#endif /* LIBCORK_CONFIG_GCC_H */\n"
  },
  {
    "path": "include/libcork/config/linux.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_LINUX_H\n#define LIBCORK_CONFIG_LINUX_H\n\n/*-----------------------------------------------------------------------\n * Endianness\n */\n\n#include <endian.h>\n\n#if __BYTE_ORDER == __BIG_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      1\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   0\n#elif __BYTE_ORDER == __LITTLE_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      0\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   1\n#else\n#error \"Cannot determine system endianness\"\n#endif\n\n#define CORK_HAVE_REALLOCF  0\n#define CORK_HAVE_PTHREADS  1\n\n\n#endif /* LIBCORK_CONFIG_LINUX_H */\n"
  },
  {
    "path": "include/libcork/config/macosx.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_MACOSX_H\n#define LIBCORK_CONFIG_MACOSX_H\n\n/*-----------------------------------------------------------------------\n * Endianness\n */\n\n#include <machine/endian.h>\n\n#if BYTE_ORDER == BIG_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      1\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   0\n#elif BYTE_ORDER == LITTLE_ENDIAN\n#define CORK_CONFIG_IS_BIG_ENDIAN      0\n#define CORK_CONFIG_IS_LITTLE_ENDIAN   1\n#else\n#error \"Cannot determine system endianness\"\n#endif\n\n#define CORK_HAVE_REALLOCF  1\n#define CORK_HAVE_PTHREADS  1\n\n\n#endif /* LIBCORK_CONFIG_MACOSX_H */\n"
  },
  {
    "path": "include/libcork/config/version.h.in",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2015, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_VERSION_H\n#define LIBCORK_CONFIG_VERSION_H\n\n\n/*-----------------------------------------------------------------------\n * Library version\n */\n\n#define CORK_CONFIG_VERSION_MAJOR   @CORK_VERSION_MAJOR@\n#define CORK_CONFIG_VERSION_MINOR   @CORK_VERSION_MINOR@\n#define CORK_CONFIG_VERSION_PATCH   @CORK_VERSION_PATCH@\n#define CORK_CONFIG_VERSION_STRING  \"@CORK_VERSION@\"\n#define CORK_CONFIG_REVISION        \"@CORK_GIT_SHA1@\"\n\n\n#endif /* LIBCORK_CONFIG_VERSION_H */\n"
  },
  {
    "path": "include/libcork/config.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CONFIG_H\n#define LIBCORK_CONFIG_H\n\n/*** include all of the parts ***/\n\n#include <libcork/config/config.h>\n\n#endif /* LIBCORK_CONFIG_H */\n"
  },
  {
    "path": "include/libcork/core/allocator.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_ALLOCATOR_H\n#define LIBCORK_CORE_ALLOCATOR_H\n\n#include <assert.h>\n#include <stdlib.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/error.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * Allocator interface\n */\n\nstruct cork_alloc;\n\ntypedef void *\n(*cork_alloc_calloc_f)(const struct cork_alloc *alloc,\n                       size_t count, size_t size);\n\ntypedef void *\n(*cork_alloc_malloc_f)(const struct cork_alloc *alloc, size_t size);\n\n/* Must not free `ptr` if allocation fails. */\ntypedef void *\n(*cork_alloc_realloc_f)(const struct cork_alloc *alloc, void *ptr,\n                        size_t old_size, size_t new_size);\n\ntypedef void\n(*cork_alloc_free_f)(const struct cork_alloc *alloc, void *ptr, size_t size);\n\nstruct cork_alloc {\n    const struct cork_alloc  *parent;\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_alloc_calloc_f  calloc;\n    cork_alloc_malloc_f  malloc;\n    cork_alloc_realloc_f  realloc;\n    cork_alloc_calloc_f  xcalloc;\n    cork_alloc_malloc_f  xmalloc;\n    cork_alloc_realloc_f  xrealloc;\n    cork_alloc_free_f  free;\n};\n\n/* NOT thread-safe; must be called before most other libcork functions.\n * Allocator will automatically be freed at process exit. */\nCORK_API struct cork_alloc *\ncork_alloc_new_alloc(const struct cork_alloc *parent);\n\n\nCORK_API void\ncork_alloc_set_user_data(struct cork_alloc *alloc,\n                         void *user_data, cork_free_f free_user_data);\n\n/* These variants must always return a valid pointer.  If allocation fails, they\n * should abort the process or transfer control in some other way to an error\n * handler or cleanup routine.\n *\n * If you only provide implementations of the `x` variants, we'll provide\n * default implementations of these that abort the process if a memory\n * allocation fails. */\n\nCORK_API void\ncork_alloc_set_calloc(struct cork_alloc *alloc, cork_alloc_calloc_f calloc);\n\nCORK_API void\ncork_alloc_set_malloc(struct cork_alloc *alloc, cork_alloc_malloc_f malloc);\n\nCORK_API void\ncork_alloc_set_realloc(struct cork_alloc *alloc, cork_alloc_realloc_f realloc);\n\n/* These variants can return a NULL pointer if allocation fails. */\n\nCORK_API void\ncork_alloc_set_xcalloc(struct cork_alloc *alloc, cork_alloc_calloc_f xcalloc);\n\nCORK_API void\ncork_alloc_set_xmalloc(struct cork_alloc *alloc, cork_alloc_malloc_f xmalloc);\n\nCORK_API void\ncork_alloc_set_xrealloc(struct cork_alloc *alloc,\n                        cork_alloc_realloc_f xrealloc);\n\n\nCORK_API void\ncork_alloc_set_free(struct cork_alloc *alloc, cork_alloc_free_f free);\n\n\n/* Low-level use of an allocator. */\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_calloc(const struct cork_alloc *alloc, size_t count, size_t size)\n{\n    return alloc->calloc(alloc, count, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_malloc(const struct cork_alloc *alloc, size_t size)\n{\n    return alloc->malloc(alloc, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_realloc(const struct cork_alloc *alloc, void *ptr,\n                   size_t old_size, size_t new_size)\n{\n    return alloc->realloc(alloc, ptr, old_size, new_size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_xcalloc(const struct cork_alloc *alloc, size_t count, size_t size)\n{\n    return alloc->xcalloc(alloc, count, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_xmalloc(const struct cork_alloc *alloc, size_t size)\n{\n    return alloc->xmalloc(alloc, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_xrealloc(const struct cork_alloc *alloc, void *ptr,\n                    size_t old_size, size_t new_size)\n{\n    return alloc->xrealloc(alloc, ptr, old_size, new_size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_alloc_xreallocf(const struct cork_alloc *alloc, void *ptr,\n                     size_t old_size, size_t new_size)\n{\n    void  *result = alloc->xrealloc(alloc, ptr, old_size, new_size);\n    if (result == NULL) {\n        alloc->free(alloc, ptr, old_size);\n        return NULL;\n    } else {\n        return result;\n    }\n}\n\nCORK_INLINE\nvoid\ncork_alloc_free(const struct cork_alloc *alloc, void *ptr, size_t size)\n{\n    return alloc->free(alloc, ptr, size);\n}\n\nCORK_INLINE\nvoid\ncork_alloc_cfree(const struct cork_alloc *alloc, void *ptr,\n                 size_t count, size_t size)\n{\n    assert(count < (SIZE_MAX / size));\n    return alloc->free(alloc, ptr, count * size);\n}\n\n#define cork_alloc_new(alloc, type) \\\n    cork_alloc_malloc((alloc), sizeof(type))\n#define cork_alloc_xnew(alloc, type) \\\n    cork_alloc_xmalloc((alloc), sizeof(type))\n#define cork_alloc_delete(alloc, type, ptr) \\\n    cork_alloc_free((alloc), (ptr), sizeof(type))\n\n/* string-related helper functions */\n\nCORK_ATTR_MALLOC\nCORK_API const char *\ncork_alloc_strdup(const struct cork_alloc *alloc, const char *str);\n\nCORK_ATTR_MALLOC\nCORK_API const char *\ncork_alloc_strndup(const struct cork_alloc *alloc,\n                   const char *str, size_t size);\n\nCORK_ATTR_MALLOC\nCORK_API const char *\ncork_alloc_xstrdup(const struct cork_alloc *alloc, const char *str);\n\nCORK_ATTR_MALLOC\nCORK_API const char *\ncork_alloc_xstrndup(const struct cork_alloc *alloc,\n                    const char *str, size_t size);\n\nCORK_API void\ncork_alloc_strfree(const struct cork_alloc *alloc, const char *str);\n\n\n/*-----------------------------------------------------------------------\n * Using the allocator interface\n */\n\n/* All of the functions that you use to actually allocate memory assume that\n * cork_current_allocator() returns the allocator instance that should be used.\n * Your easiest approach is to do nothing special; in that case, all of the\n * libcork memory allocation functions will transparently use the standard\n * malloc/free family of functions.\n *\n * If you're writing a library, and want to allow your library clients to\n * provide a separate custom memory allocator then the one they can already\n * override for libcork itself, you should declare a pair of functions for\n * getting and setting your library's current allocator (like libcork itself\n * does), and (only when compiling the source of your library) define\n * `cork_current_allocator` as a macro that aliases the getter function.  That\n * will cause the libcork memory allocation functions to use whichever allocator\n * your library user has provided.\n *\n * If you're writing an application, and want to provide a single allocator that\n * all libcork-using libraries will pick up, just call cork_set_allocator before\n * calling any other library functions.  Other libraries will use this as a\n * default and everything that uses libcork's memory allocation functions will\n * use your custom allocator. */\n\n\n/* libcork's current allocator */\n\nextern const struct cork_alloc  *cork_allocator;\n\n/* We take control and will free when the process exits.  This is *NOT*\n * thread-safe; it's only safe to call before you've called *ANY* other libcork\n * function (or any function from any other library that uses libcork).  You can\n * only call this at most once. */\nCORK_API void\ncork_set_allocator(const struct cork_alloc *alloc);\n\n\n/* The current allocator of whichever library is being compiled. */\n\n#if !defined(cork_current_allocator)\n#define cork_current_allocator()  (cork_allocator)\n#endif\n\n\n/* using an allocator */\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_calloc(size_t count, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_calloc(alloc, count, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_malloc(size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_malloc(alloc, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_realloc(void *ptr, size_t old_size, size_t new_size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_realloc(alloc, ptr, old_size, new_size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_xcalloc(size_t count, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xcalloc(alloc, count, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_xmalloc(size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xmalloc(alloc, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_xrealloc(void *ptr, size_t old_size, size_t new_size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xrealloc(alloc, ptr, old_size, new_size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nvoid *\ncork_xreallocf(void *ptr, size_t old_size, size_t new_size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xreallocf(alloc, ptr, old_size, new_size);\n}\n\nCORK_INLINE\nvoid\ncork_free(void *ptr, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    cork_alloc_free(alloc, ptr, size);\n}\n\nCORK_INLINE\nvoid\ncork_cfree(void *ptr, size_t count, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    cork_alloc_cfree(alloc, ptr, count, size);\n}\n\n#define cork_new(type)          cork_malloc(sizeof(type))\n#define cork_xnew(type)         cork_xmalloc(sizeof(type))\n#define cork_delete(type, ptr)  cork_free((ptr), sizeof(type))\n\n\n/* string-related helper functions */\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nconst char *\ncork_strdup(const char *str)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_strdup(alloc, str);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nconst char *\ncork_strndup(const char *str, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_strndup(alloc, str, size);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nconst char *\ncork_xstrdup(const char *str)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xstrdup(alloc, str);\n}\n\nCORK_ATTR_MALLOC\nCORK_INLINE\nconst char *\ncork_xstrndup(const char *str, size_t size)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_xstrndup(alloc, str, size);\n}\n\nCORK_INLINE\nvoid\ncork_strfree(const char *str)\n{\n    const struct cork_alloc  *alloc = cork_current_allocator();\n    return cork_alloc_strfree(alloc, str);\n}\n\nCORK_INLINE\nsize_t\ncork_strlen(const char *str)\n{\n    size_t* base = ((size_t*) str) - 1;\n    return *base;\n}\n\n\n/*-----------------------------------------------------------------------\n * Debugging allocator\n */\n\n/* An allocator that adds some additional debugging checks:\n *\n * - We verify that every \"free\" call (cork_free, cork_cfree, cork_delete,\n *   cork_realloc) is passed the \"correct\" size — i.e., the same size that was\n *   passed in to the correspond \"new\" call (cork_malloc, cork_calloc,\n *   cork_realloc, cork_new).\n */\n\nstruct cork_alloc *\ncork_debug_alloc_new(const struct cork_alloc *parent);\n\n\n#endif /* LIBCORK_CORE_ALLOCATOR_H */\n"
  },
  {
    "path": "include/libcork/core/api.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_API_H\n#define LIBCORK_CORE_API_H\n\n#include <libcork/config.h>\n#include <libcork/core/attributes.h>\n\n\n/*-----------------------------------------------------------------------\n * Calling conventions\n */\n\n/* If you're using libcork as a shared library, you don't need to do anything\n * special; the following will automatically set things up so that libcork's\n * public symbols are imported from the library.  When we build the shared\n * library, we define this ourselves to export the symbols. */\n\n#if !defined(CORK_API)\n#define CORK_API  CORK_IMPORT\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Library version\n */\n\n#define CORK_VERSION_MAJOR  CORK_CONFIG_VERSION_MAJOR\n#define CORK_VERSION_MINOR  CORK_CONFIG_VERSION_MINOR\n#define CORK_VERSION_PATCH  CORK_CONFIG_VERSION_PATCH\n\n#define CORK_MAKE_VERSION(major, minor, patch) \\\n    ((major * 1000000) + (minor * 1000) + patch)\n\n#define CORK_VERSION  \\\n    CORK_MAKE_VERSION(CORK_VERSION_MAJOR, \\\n                      CORK_VERSION_MINOR, \\\n                      CORK_VERSION_PATCH)\n\nCORK_API const char *\ncork_version_string(void)\n    CORK_ATTR_CONST;\n\nCORK_API const char *\ncork_revision_string(void)\n    CORK_ATTR_CONST;\n\n\n#endif /* LIBCORK_CORE_API_H */\n"
  },
  {
    "path": "include/libcork/core/attributes.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_ATTRIBUTES_H\n#define LIBCORK_CORE_ATTRIBUTES_H\n\n#include <libcork/config.h>\n\n\n/*\n * Declare a “const” function.\n *\n * A const function is one whose return value depends only on its\n * parameters.  This is slightly more strict than a “pure” function; a\n * const function is not allowed to read from global variables, whereas\n * a pure function is.\n *\n *   int square(int x) CORK_ATTR_CONST;\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_CONST  __attribute__((const))\n#else\n#define CORK_ATTR_CONST\n#endif\n\n\n/*\n * Declare a “pure” function.\n *\n * A pure function is one whose return value depends only on its\n * parameters, and global variables.\n *\n *   int square(int x) CORK_ATTR_PURE;\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_PURE  __attribute__((pure))\n#else\n#define CORK_ATTR_PURE\n#endif\n\n\n/*\n * Declare that a function returns a newly allocated pointer.\n *\n * The compiler can use this information to generate more accurate\n * aliasing information, since it can infer that the result of the\n * function cannot alias any other existing pointer.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_MALLOC  __attribute__((malloc))\n#else\n#define CORK_ATTR_MALLOC\n#endif\n\n\n/*\n * Declare that a function shouldn't be inlined.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_NOINLINE  __attribute__((noinline))\n#else\n#define CORK_ATTR_NOINLINE\n#endif\n\n\n/*\n * Declare an entity that isn't used.\n *\n * This lets you keep -Wall activated in several cases where you're\n * obligated to define something that you don't intend to use.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_UNUSED  __attribute__((unused))\n#else\n#define CORK_ATTR_UNUSED\n#endif\n\n\n/*\n * Declare a function that takes in printf-like parameters.\n *\n * When the compiler supports this attribute, it will check the format\n * string, and the following arguments, to make sure that they match.\n * format_index and args_index are 1-based.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_PRINTF(format_index, args_index) \\\n    __attribute__((format(printf, format_index, args_index)))\n#else\n#define CORK_ATTR_PRINTF(format_index, args_index)\n#endif\n\n\n/*\n * Declare a var-arg function whose last parameter must be a NULL\n * sentinel value.\n *\n * When the compiler supports this attribute, it will check the actual\n * parameters whenever this function is called, and ensure that the last\n * parameter is a @c NULL.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_ATTR_SENTINEL  __attribute__((sentinel))\n#else\n#define CORK_ATTR_SENTINEL\n#endif\n\n\n/*\n * Declare that a boolean expression is likely to be true or false.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_LIKELY(expr)  __builtin_expect((expr), 1)\n#define CORK_UNLIKELY(expr)  __builtin_expect((expr), 0)\n#else\n#define CORK_LIKELY(expr)  (expr)\n#define CORK_UNLIKELY(expr)  (expr)\n#endif\n\n/*\n * Declare that a function is part of the current library's public API, or that\n * it's internal to the current library.\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n#define CORK_EXPORT  __attribute__((visibility(\"default\")))\n#define CORK_IMPORT  __attribute__((visibility(\"default\")))\n#define CORK_LOCAL   __attribute__((visibility(\"hidden\")))\n#else\n#define CORK_EXPORT\n#define CORK_IMPORT\n#define CORK_LOCAL\n#endif\n\n/*\n * Define an inline function in a header file.  This allows the compiler to\n * inline the definition if it makes sense.  You should also provide a\n * _declaration_ in some source file, with exactly the same signature, which\n * will ensure that a single copy of the function is available to link against\n * if the compiler decides not to inline the function.\n */\n\n#if CORK_CONFIG_HAVE_C99_INLINE\n#define CORK_INLINE inline\n#else\n#define CORK_INLINE CORK_ATTR_UNUSED static\n#endif\n\n\n/*\n * Declare a static function that should automatically be called at program\n * startup.\n */\n\n/* TODO: When we implement a full Windows port, [1] describes how best to\n * implement an initialization function under Visual Studio.\n *\n * [1] http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc\n */\n\n#if CORK_CONFIG_HAVE_GCC_ATTRIBUTES\n\n#define CORK_INITIALIZER(name) \\\n__attribute__((constructor)) \\\nstatic void \\\nname(void)\n\n#define CORK_FINALIZER(name) \\\n__attribute__((destructor)) \\\nstatic void \\\nname(void)\n\n#else\n#error \"Don't know how to implement initialization functions of this platform\"\n#endif\n\n\n#endif /* LIBCORK_CORE_ATTRIBUTES_H */\n"
  },
  {
    "path": "include/libcork/core/byte-order.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_BYTE_ORDER_H\n#define LIBCORK_CORE_BYTE_ORDER_H\n\n\n#include <libcork/config.h>\n#include <libcork/core/types.h>\n\n\n/* Constants to represent big endianness and little endianness */\n#define CORK_BIG_ENDIAN  4321\n#define CORK_LITTLE_ENDIAN  1234\n\n/* Whether the current host is big- or little-endian.  HOST gives us the\n * current system's endianness; OTHER gives the opposite endianness.\n * The _NAME macros can be used in debugging messages and other\n * human-readable output.\n *\n * Note that we actually detect the endianness in the various header\n * files in the libcork/config directory, since we want to keep\n * everything detection-related separated out from what we define based\n * on that detection. */\n\n#if CORK_CONFIG_IS_BIG_ENDIAN\n#define CORK_HOST_ENDIANNESS  CORK_BIG_ENDIAN\n#define CORK_OTHER_ENDIANNESS  CORK_LITTLE_ENDIAN\n#define CORK_HOST_ENDIANNESS_NAME   \"big\"\n#define CORK_OTHER_ENDIANNESS_NAME  \"little\"\n\n#elif CORK_CONFIG_IS_LITTLE_ENDIAN\n#define CORK_HOST_ENDIANNESS  CORK_LITTLE_ENDIAN\n#define CORK_OTHER_ENDIANNESS  CORK_BIG_ENDIAN\n#define CORK_HOST_ENDIANNESS_NAME   \"little\"\n#define CORK_OTHER_ENDIANNESS_NAME  \"big\"\n\n#else\n#error \"Unknown endianness\"\n#endif\n\n\n/* Returns the byte-swapped version an integer, regardless of the\n * underlying endianness.\n *\n * These macros only require an rvalue as their parameter (which can\n * therefore be any arbitrary expression), and they don't modify the\n * original contents if it happens to be a variable.  */\n\n#define CORK_SWAP_UINT16(__u16) \\\n    (((((uint16_t) __u16) & 0xff00u) >> 8) | \\\n     ((((uint16_t) __u16) & 0x00ffu) << 8))\n\n#define CORK_SWAP_UINT32(__u32) \\\n    (((((uint32_t) __u32) & 0xff000000u) >> 24) | \\\n     ((((uint32_t) __u32) & 0x00ff0000u) >>  8) | \\\n     ((((uint32_t) __u32) & 0x0000ff00u) <<  8) | \\\n     ((((uint32_t) __u32) & 0x000000ffu) << 24))\n\n#define CORK_SWAP_UINT64(__u64) \\\n    (((((uint64_t) __u64) & UINT64_C(0xff00000000000000)) >> 56) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x00ff000000000000)) >> 40) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x0000ff0000000000)) >> 24) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x000000ff00000000)) >>  8) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x00000000ff000000)) <<  8) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x0000000000ff0000)) << 24) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x000000000000ff00)) << 40) | \\\n     ((((uint64_t) __u64) & UINT64_C(0x00000000000000ff)) << 56))\n\n/* Bytes-swaps an integer variable in place.\n *\n * These macros require an lvalue as their parameter; the contents of\n * this variable will be modified by the macro. */\n\n#define CORK_SWAP_IN_PLACE_UINT16(__u16) \\\n    do { \\\n        (__u16) = CORK_SWAP_UINT16(__u16); \\\n    } while (0)\n\n#define CORK_SWAP_IN_PLACE_UINT32(__u32) \\\n    do { \\\n        (__u32) = CORK_SWAP_UINT32(__u32); \\\n    } while (0)\n\n#define CORK_SWAP_IN_PLACE_UINT64(__u64) \\\n    do { \\\n        (__u64) = CORK_SWAP_UINT64(__u64); \\\n    } while (0)\n\n\n/*\n * A slew of swapping macros whose operation depends on the endianness\n * of the current system:\n *\n * uint16_t CORK_UINT16_BIG_TO_HOST(u16)\n * uint32_t CORK_UINT32_BIG_TO_HOST(u32)\n * uint64_t CORK_UINT64_BIG_TO_HOST(u64)\n * uint16_t CORK_UINT16_LITTLE_TO_HOST(u16)\n * uint32_t CORK_UINT32_LITTLE_TO_HOST(u32)\n * uint64_t CORK_UINT64_LITTLE_TO_HOST(u64)\n * void CORK_UINT16_BIG_TO_HOST_IN_PLACE(&u16)\n * void CORK_UINT32_BIG_TO_HOST_IN_PLACE(&u32)\n * void CORK_UINT64_BIG_TO_HOST_IN_PLACE(&u64)\n * void CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(&u16)\n * void CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(&u32)\n * void CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(&u64)\n *\n * uint16_t CORK_UINT16_HOST_TO_BIG(u16)\n * uint32_t CORK_UINT32_HOST_TO_BIG(u32)\n * uint64_t CORK_UINT64_HOST_TO_BIG(u64)\n * uint16_t CORK_UINT16_HOST_TO_LITTLE(u16)\n * uint32_t CORK_UINT32_HOST_TO_LITTLE(u32)\n * uint64_t CORK_UINT64_HOST_TO_LITTLE(u64)\n * void CORK_UINT16_HOST_TO_BIG_IN_PLACE(&u16)\n * void CORK_UINT32_HOST_TO_BIG_IN_PLACE(&u32)\n * void CORK_UINT64_HOST_TO_BIG_IN_PLACE(&u64)\n * void CORK_UINT16_HOST_TO_LITTLE_IN_PLACE(&u16)\n * void CORK_UINT32_HOST_TO_LITTLE_IN_PLACE(&u32)\n * void CORK_UINT64_HOST_TO_LITTLE_IN_PLACE(&u64)\n */\n\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n\n#define CORK_UINT16_BIG_TO_HOST(__u16) (__u16) /* nothing to do */\n#define CORK_UINT16_LITTLE_TO_HOST(__u16)  CORK_SWAP_UINT16(__u16)\n\n#define CORK_UINT32_BIG_TO_HOST(__u32) (__u32) /* nothing to do */\n#define CORK_UINT32_LITTLE_TO_HOST(__u32)  CORK_SWAP_UINT32(__u32)\n\n#define CORK_UINT64_BIG_TO_HOST(__u64) (__u64) /* nothing to do */\n#define CORK_UINT64_LITTLE_TO_HOST(__u64)  CORK_SWAP_UINT64(__u64)\n\n#define CORK_UINT16_BIG_TO_HOST_IN_PLACE(__u16) /* nothing to do */\n#define CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(__u16)  CORK_SWAP_IN_PLACE_UINT16(__u16)\n\n#define CORK_UINT32_BIG_TO_HOST_IN_PLACE(__u32) /* nothing to do */\n#define CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(__u32)  CORK_SWAP_IN_PLACE_UINT32(__u32)\n\n#define CORK_UINT64_BIG_TO_HOST_IN_PLACE(__u64) /* nothing to do */\n#define CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(__u64)  CORK_SWAP_IN_PLACE_UINT64(__u64)\n\n#elif CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN\n\n#define CORK_UINT16_BIG_TO_HOST(__u16)  CORK_SWAP_UINT16(__u16)\n#define CORK_UINT16_LITTLE_TO_HOST(__u16) (__u16) /* nothing to do */\n\n#define CORK_UINT32_BIG_TO_HOST(__u32)  CORK_SWAP_UINT32(__u32)\n#define CORK_UINT32_LITTLE_TO_HOST(__u32) (__u32) /* nothing to do */\n\n#define CORK_UINT64_BIG_TO_HOST(__u64)  CORK_SWAP_UINT64(__u64)\n#define CORK_UINT64_LITTLE_TO_HOST(__u64) (__u64) /* nothing to do */\n\n#define CORK_UINT16_BIG_TO_HOST_IN_PLACE(__u16)  CORK_SWAP_IN_PLACE_UINT16(__u16)\n#define CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(__u16) /* nothing to do */\n\n#define CORK_UINT32_BIG_TO_HOST_IN_PLACE(__u32)  CORK_SWAP_IN_PLACE_UINT32(__u32)\n#define CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(__u32) /* nothing to do */\n\n#define CORK_UINT64_BIG_TO_HOST_IN_PLACE(__u64)  CORK_SWAP_IN_PLACE_UINT64(__u64)\n#define CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(__u64) /* nothing to do */\n\n#endif\n\n\n#define CORK_UINT16_HOST_TO_BIG(__u16)  CORK_UINT16_BIG_TO_HOST(__u16)\n#define CORK_UINT32_HOST_TO_BIG(__u32)  CORK_UINT32_BIG_TO_HOST(__u32)\n#define CORK_UINT64_HOST_TO_BIG(__u64)  CORK_UINT64_BIG_TO_HOST(__u64)\n#define CORK_UINT16_HOST_TO_LITTLE(__u16)  CORK_UINT16_LITTLE_TO_HOST(__u16)\n#define CORK_UINT32_HOST_TO_LITTLE(__u32)  CORK_UINT32_LITTLE_TO_HOST(__u32)\n#define CORK_UINT64_HOST_TO_LITTLE(__u64)  CORK_UINT64_LITTLE_TO_HOST(__u64)\n#define CORK_UINT16_HOST_TO_BIG_IN_PLACE(__u16)  CORK_UINT16_BIG_TO_HOST_IN_PLACE(__u16)\n#define CORK_UINT32_HOST_TO_BIG_IN_PLACE(__u32)  CORK_UINT32_BIG_TO_HOST_IN_PLACE(__u32)\n#define CORK_UINT64_HOST_TO_BIG_IN_PLACE(__u64)  CORK_UINT64_BIG_TO_HOST_IN_PLACE(__u64)\n#define CORK_UINT16_HOST_TO_LITTLE_IN_PLACE(__u16)  CORK_UINT16_LITTLE_TO_HOST_IN_PLACE(__u16)\n#define CORK_UINT32_HOST_TO_LITTLE_IN_PLACE(__u32)  CORK_UINT32_LITTLE_TO_HOST_IN_PLACE(__u32)\n#define CORK_UINT64_HOST_TO_LITTLE_IN_PLACE(__u64)  CORK_UINT64_LITTLE_TO_HOST_IN_PLACE(__u64)\n\n\n#endif /* LIBCORK_CORE_BYTE_ORDER_H */\n"
  },
  {
    "path": "include/libcork/core/callbacks.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_CALLBACKS_H\n#define LIBCORK_CORE_CALLBACKS_H\n\n\n#include <libcork/core/hash.h>\n\n\ntypedef int\n(*cork_copy_f)(void *user_data, void *dest, const void *src);\n\ntypedef void\n(*cork_done_f)(void *user_data, void *value);\n\ntypedef void\n(*cork_free_f)(void *value);\n\ntypedef cork_hash\n(*cork_hash_f)(void *user_data, const void *value);\n\ntypedef bool\n(*cork_equals_f)(void *user_data, const void *value1, const void *value2);\n\ntypedef void\n(*cork_init_f)(void *user_data, void *value);\n\n#define cork_free_user_data(parent) \\\n    ((parent)->free_user_data == NULL? (void) 0: \\\n     (parent)->free_user_data((parent)->user_data))\n\ntypedef void *\n(*cork_new_f)(void *user_data);\n\ntypedef int\n(*cork_run_f)(void *user_data);\n\n\n#endif /* LIBCORK_CORE_CALLBACKS_H */\n"
  },
  {
    "path": "include/libcork/core/error.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_ERROR_H\n#define LIBCORK_CORE_ERROR_H\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/types.h>\n\n\n/* Should be a hash of a string representing the error code. */\ntypedef uint32_t  cork_error;\n\n/* An error code that represents “no error”. */\n#define CORK_ERROR_NONE  ((cork_error) 0)\n\nCORK_API bool\ncork_error_occurred(void);\n\nCORK_API cork_error\ncork_error_code(void);\n\nCORK_API const char *\ncork_error_message(void);\n\n\nCORK_API void\ncork_error_clear(void);\n\nCORK_API void\ncork_error_set_printf(cork_error code, const char *format, ...)\n    CORK_ATTR_PRINTF(2,3);\n\nCORK_API void\ncork_error_set_string(cork_error code, const char *str);\n\nCORK_API void\ncork_error_set_vprintf(cork_error code, const char *format, va_list args)\n    CORK_ATTR_PRINTF(2,0);\n\nCORK_API void\ncork_error_prefix_printf(const char *format, ...)\n    CORK_ATTR_PRINTF(1,2);\n\nCORK_API void\ncork_error_prefix_string(const char *str);\n\nCORK_API void\ncork_error_prefix_vprintf(const char *format, va_list arg)\n    CORK_ATTR_PRINTF(1,0);\n\n\n/* deprecated */\nCORK_API void\ncork_error_set(uint32_t error_class, unsigned int error_code,\n               const char *format, ...)\n    CORK_ATTR_PRINTF(3,4);\n\n/* deprecated */\nCORK_API void\ncork_error_prefix(const char *format, ...)\n    CORK_ATTR_PRINTF(1,2);\n\n\n/*-----------------------------------------------------------------------\n * Built-in errors\n */\n\n#define CORK_PARSE_ERROR               0x95dfd3c8\n#define CORK_REDEFINED                 0x171629cb\n#define CORK_UNDEFINED                 0xedc3d7d9\n#define CORK_UNKNOWN_ERROR             0x8cb0880d\n\n#define cork_parse_error(...) \\\n    cork_error_set_printf(CORK_PARSE_ERROR, __VA_ARGS__)\n#define cork_redefined(...) \\\n    cork_error_set_printf(CORK_REDEFINED, __VA_ARGS__)\n#define cork_undefined(...) \\\n    cork_error_set_printf(CORK_UNDEFINED, __VA_ARGS__)\n\nCORK_API void\ncork_system_error_set(void);\n\nCORK_API void\ncork_system_error_set_explicit(int err);\n\nCORK_API void\ncork_unknown_error_set_(const char *location);\n\n#define cork_unknown_error() \\\n    cork_unknown_error_set_(__func__)\n\n\n/*-----------------------------------------------------------------------\n * Abort on failure\n */\n\n#define cork_abort_(func, file, line, fmt, ...) \\\n    do { \\\n        fprintf(stderr, fmt \"\\n  in %s (%s:%u)\\n\", \\\n                __VA_ARGS__, (func), (file), (unsigned int) (line)); \\\n        abort(); \\\n    } while (0)\n\n#define cork_abort(fmt, ...) \\\n    cork_abort_(__func__, __FILE__, __LINE__, fmt, __VA_ARGS__)\n\nCORK_INLINE\nvoid *\ncork_abort_if_null_(void *ptr, const char *msg, const char *func,\n                    const char *file, unsigned int line)\n{\n    if (CORK_UNLIKELY(ptr == NULL)) {\n        cork_abort_(func, file, line, \"%s\", msg);\n    } else {\n        return ptr;\n    }\n}\n\n#define cork_abort_if_null(ptr, msg) \\\n    (cork_abort_if_null_(ptr, msg, __func__, __FILE__, __LINE__))\n\n#define cork_unreachable() \\\n    cork_abort(\"%s\", \"Code should not be reachable\")\n\n\n#endif /* LIBCORK_CORE_ERROR_H */\n"
  },
  {
    "path": "include/libcork/core/gc.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_GC_REFCOUNT_H\n#define LIBCORK_GC_REFCOUNT_H\n\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n\n\nstruct cork_gc;\n\n/* A callback for recursing through the children of a garbage-collected\n * object. */\ntypedef void\n(*cork_gc_recurser)(struct cork_gc *gc, void *obj, void *ud);\n\ntypedef void\n(*cork_gc_free_func)(void *obj);\n\ntypedef void\n(*cork_gc_recurse_func)(struct cork_gc *gc, void *self,\n                        cork_gc_recurser recurser, void *ud);\n\n/* An interface that each garbage-collected object must implement. */\nstruct cork_gc_obj_iface {\n    /* Perform additional cleanup; does *NOT* need to deallocate the\n     * object itself, or release any child references */\n    cork_gc_free_func  free;\n    cork_gc_recurse_func  recurse;\n};\n\n\nCORK_API void\ncork_gc_init(void);\n\nCORK_API void\ncork_gc_done(void);\n\n\nCORK_API void *\ncork_gc_alloc(size_t instance_size, struct cork_gc_obj_iface *iface);\n\n#define cork_gc_new_iface(obj_type, iface) \\\n    ((obj_type *) \\\n     (cork_gc_alloc(sizeof(obj_type), (iface))))\n\n#define cork_gc_new(struct_name) \\\n    (cork_gc_new_iface(struct struct_name, &struct_name##__gc))\n\n\nCORK_API void *\ncork_gc_incref(void *obj);\n\nCORK_API void\ncork_gc_decref(void *obj);\n\n\n#endif /* LIBCORK_GC_REFCOUNT_H */\n"
  },
  {
    "path": "include/libcork/core/hash.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_HASH_H\n#define LIBCORK_CORE_HASH_H\n\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/byte-order.h>\n#include <libcork/core/types.h>\n#include <libcork/core/u128.h>\n\n/* Needed for memcpy */\n#include <string.h>\n\n\ntypedef uint32_t  cork_hash;\n\ntypedef struct {\n    cork_u128  u128;\n} cork_big_hash;\n\nCORK_INLINE\nbool\ncork_big_hash_equal(const cork_big_hash h1, const cork_big_hash h2)\n{\n    return cork_u128_eq(h1.u128, h2.u128);\n}\n\n#define CORK_BIG_HASH_INIT()  {{{{0}}}}\n\n/* We currently use MurmurHash3 [1], which is public domain, as our hash\n * implementation.\n *\n * [1] http://code.google.com/p/smhasher/\n */\n\n#define CORK_ROTL32(a,b) (((a) << ((b) & 0x1f)) | ((a) >> (32 - ((b) & 0x1f))))\n#define CORK_ROTL64(a,b) (((a) << ((b) & 0x3f)) | ((a) >> (64 - ((b) & 0x3f))))\n\nCORK_INLINE\nuint32_t cork_getblock32(const uint32_t *p, int i)\n{\n    uint32_t u;\n    memcpy(&u, p + i, sizeof(u));\n    return u;\n}\n\nCORK_INLINE\nuint64_t cork_getblock64(const uint64_t *p, int i)\n{\n    uint64_t u;\n    memcpy(&u, p + i, sizeof(u));\n    return u;\n}\n\nCORK_INLINE\nuint32_t cork_fmix32(uint32_t h)\n{\n    h ^= h >> 16;\n    h *= 0x85ebca6b;\n    h ^= h >> 13;\n    h *= 0xc2b2ae35;\n    h ^= h >> 16;\n    return h;\n}\n\nCORK_INLINE\nuint64_t cork_fmix64(uint64_t k)\n{\n    k ^= k >> 33;\n    k *= UINT64_C(0xff51afd7ed558ccd);\n    k ^= k >> 33;\n    k *= UINT64_C(0xc4ceb9fe1a85ec53);\n    k ^= k >> 33;\n    return k;\n}\n\nCORK_INLINE\ncork_hash\ncork_stable_hash_buffer(cork_hash seed, const void *src, size_t len)\n{\n    typedef uint32_t __attribute__((__may_alias__))  cork_aliased_uint32_t;\n\n    /* This is exactly the same as cork_murmur_hash_x86_32, but with a byte swap\n     * to make sure that we always process the uint32s little-endian. */\n    const unsigned int  nblocks = (unsigned int)(len / 4);\n    const cork_aliased_uint32_t  *blocks = (const cork_aliased_uint32_t *) src;\n    const cork_aliased_uint32_t  *end = blocks + nblocks;\n    const cork_aliased_uint32_t  *curr;\n    const uint8_t  *tail = (const uint8_t *) end;\n\n    uint32_t  h1 = seed;\n    uint32_t  c1 = 0xcc9e2d51;\n    uint32_t  c2 = 0x1b873593;\n    uint32_t  k1 = 0;\n\n    /* body */\n    for (curr = blocks; curr != end; curr++) {\n        uint32_t  k1 = CORK_UINT32_HOST_TO_LITTLE(cork_getblock32((const uint32_t *) curr, 0));\n\n        k1 *= c1;\n        k1 = CORK_ROTL32(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = CORK_ROTL32(h1,13);\n        h1 = h1*5+0xe6546b64;\n    }\n\n    /* tail */\n    switch (len & 3) {\n        case 3: k1 ^= tail[2] << 16;\n        case 2: k1 ^= tail[1] << 8;\n        case 1: k1 ^= tail[0];\n                k1 *= c1; k1 = CORK_ROTL32(k1,15); k1 *= c2; h1 ^= k1;\n    };\n\n    /* finalization */\n    h1 ^= len;\n    h1 = cork_fmix32(h1);\n    return h1;\n}\n\n#define cork_murmur_hash_x86_32(seed, src, len, dest) \\\ndo { \\\n    typedef uint32_t __attribute__((__may_alias__))  cork_aliased_uint32_t; \\\n    \\\n    const unsigned int  nblocks = len / 4; \\\n    const cork_aliased_uint32_t  *blocks = (const cork_aliased_uint32_t *) src; \\\n    const cork_aliased_uint32_t  *end = blocks + nblocks; \\\n    const cork_aliased_uint32_t  *curr; \\\n    const uint8_t  *tail = (const uint8_t *) end; \\\n    \\\n    uint32_t  h1 = seed; \\\n    uint32_t  c1 = 0xcc9e2d51; \\\n    uint32_t  c2 = 0x1b873593; \\\n    uint32_t  k1 = 0; \\\n    \\\n    /* body */ \\\n    for (curr = blocks; curr != end; curr++) { \\\n        uint32_t  k1 = cork_getblock32((const uint32_t *) curr, 0); \\\n        \\\n        k1 *= c1; \\\n        k1 = CORK_ROTL32(k1,15); \\\n        k1 *= c2; \\\n        \\\n        h1 ^= k1; \\\n        h1 = CORK_ROTL32(h1,13); \\\n        h1 = h1*5+0xe6546b64; \\\n    } \\\n    \\\n    /* tail */ \\\n    switch (len & 3) { \\\n        case 3: k1 ^= tail[2] << 16; \\\n        case 2: k1 ^= tail[1] << 8; \\\n        case 1: k1 ^= tail[0]; \\\n                k1 *= c1; k1 = CORK_ROTL32(k1,15); k1 *= c2; h1 ^= k1; \\\n    }; \\\n    \\\n    /* finalization */ \\\n    h1 ^= len; \\\n    h1 = cork_fmix32(h1); \\\n    *(dest) = h1; \\\n} while (0)\n\n#define cork_murmur_hash_x86_128(seed, src, len, dest) \\\ndo { \\\n    typedef uint32_t __attribute__((__may_alias__))  cork_aliased_uint32_t; \\\n    \\\n    const unsigned int  nblocks = len / 16; \\\n    const cork_aliased_uint32_t  *blocks = (const cork_aliased_uint32_t *) src; \\\n    const cork_aliased_uint32_t  *end = blocks + (nblocks * 4); \\\n    const cork_aliased_uint32_t  *curr; \\\n    const uint8_t  *tail = (const uint8_t *) end; \\\n    \\\n    uint32_t  h1 = cork_u128_be32(seed.u128, 0); \\\n    uint32_t  h2 = cork_u128_be32(seed.u128, 1); \\\n    uint32_t  h3 = cork_u128_be32(seed.u128, 2); \\\n    uint32_t  h4 = cork_u128_be32(seed.u128, 3); \\\n    \\\n    uint32_t  c1 = 0x239b961b; \\\n    uint32_t  c2 = 0xab0e9789; \\\n    uint32_t  c3 = 0x38b34ae5; \\\n    uint32_t  c4 = 0xa1e38b93; \\\n    \\\n    uint32_t  k1 = 0; \\\n    uint32_t  k2 = 0; \\\n    uint32_t  k3 = 0; \\\n    uint32_t  k4 = 0; \\\n    \\\n    /* body */ \\\n    for (curr = blocks; curr != end; curr += 4) { \\\n        uint32_t  k1 = cork_getblock32((const uint32_t *) curr, 0); \\\n        uint32_t  k2 = cork_getblock32((const uint32_t *) curr, 1); \\\n        uint32_t  k3 = cork_getblock32((const uint32_t *) curr, 2); \\\n        uint32_t  k4 = cork_getblock32((const uint32_t *) curr, 3); \\\n        \\\n        k1 *= c1; k1  = CORK_ROTL32(k1,15); k1 *= c2; h1 ^= k1; \\\n        h1 = CORK_ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; \\\n        \\\n        k2 *= c2; k2  = CORK_ROTL32(k2,16); k2 *= c3; h2 ^= k2; \\\n        h2 = CORK_ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; \\\n        \\\n        k3 *= c3; k3  = CORK_ROTL32(k3,17); k3 *= c4; h3 ^= k3; \\\n        h3 = CORK_ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; \\\n        \\\n        k4 *= c4; k4  = CORK_ROTL32(k4,18); k4 *= c1; h4 ^= k4; \\\n        h4 = CORK_ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; \\\n    } \\\n    \\\n    /* tail */ \\\n    switch (len & 15) { \\\n        case 15: k4 ^= tail[14] << 16; \\\n        case 14: k4 ^= tail[13] << 8; \\\n        case 13: k4 ^= tail[12] << 0; \\\n                 k4 *= c4; k4 = CORK_ROTL32(k4,18); k4 *= c1; h4 ^= k4; \\\n        \\\n        case 12: k3 ^= tail[11] << 24; \\\n        case 11: k3 ^= tail[10] << 16; \\\n        case 10: k3 ^= tail[ 9] << 8; \\\n        case  9: k3 ^= tail[ 8] << 0; \\\n                 k3 *= c3; k3 = CORK_ROTL32(k3,17); k3 *= c4; h3 ^= k3; \\\n        \\\n        case  8: k2 ^= tail[ 7] << 24; \\\n        case  7: k2 ^= tail[ 6] << 16; \\\n        case  6: k2 ^= tail[ 5] << 8; \\\n        case  5: k2 ^= tail[ 4] << 0; \\\n                 k2 *= c2; k2 = CORK_ROTL32(k2,16); k2 *= c3; h2 ^= k2; \\\n        \\\n        case  4: k1 ^= tail[ 3] << 24; \\\n        case  3: k1 ^= tail[ 2] << 16; \\\n        case  2: k1 ^= tail[ 1] << 8; \\\n        case  1: k1 ^= tail[ 0] << 0; \\\n                 k1 *= c1; k1 = CORK_ROTL32(k1,15); k1 *= c2; h1 ^= k1; \\\n    }; \\\n    \\\n    /* finalization */ \\\n    \\\n    h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; \\\n    \\\n    h1 += h2; h1 += h3; h1 += h4; \\\n    h2 += h1; h3 += h1; h4 += h1; \\\n    \\\n    h1 = cork_fmix32(h1); \\\n    h2 = cork_fmix32(h2); \\\n    h3 = cork_fmix32(h3); \\\n    h4 = cork_fmix32(h4); \\\n    \\\n    h1 += h2; h1 += h3; h1 += h4; \\\n    h2 += h1; h3 += h1; h4 += h1; \\\n    \\\n    (dest)->u128 = cork_u128_from_32(h1, h2, h3, h4); \\\n} while (0)\n\n#define cork_murmur_hash_x64_128(seed, src, len, dest) \\\ndo { \\\n    typedef uint64_t __attribute__((__may_alias__))  cork_aliased_uint64_t; \\\n    \\\n    const unsigned int  nblocks = len / 16; \\\n    const cork_aliased_uint64_t  *blocks = (const cork_aliased_uint64_t *) src; \\\n    const cork_aliased_uint64_t  *end = blocks + (nblocks * 2); \\\n    const cork_aliased_uint64_t  *curr; \\\n    const uint8_t  *tail = (const uint8_t *) end; \\\n    \\\n    uint64_t  h1 = cork_u128_be64(seed.u128, 0); \\\n    uint64_t  h2 = cork_u128_be64(seed.u128, 1); \\\n    \\\n    uint64_t  c1 = UINT64_C(0x87c37b91114253d5); \\\n    uint64_t  c2 = UINT64_C(0x4cf5ad432745937f); \\\n    \\\n    uint64_t k1 = 0; \\\n    uint64_t k2 = 0; \\\n    \\\n    /* body */ \\\n    for (curr = blocks; curr != end; curr += 2) { \\\n        uint64_t  k1 = cork_getblock64((const uint64_t *) curr, 0); \\\n        uint64_t  k2 = cork_getblock64((const uint64_t *) curr, 1); \\\n    \\\n        k1 *= c1; k1  = CORK_ROTL64(k1,31); k1 *= c2; h1 ^= k1; \\\n        h1 = CORK_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; \\\n    \\\n        k2 *= c2; k2  = CORK_ROTL64(k2,33); k2 *= c1; h2 ^= k2; \\\n        h2 = CORK_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; \\\n    } \\\n    \\\n    /* tail */ \\\n    switch (len & 15) { \\\n        case 15: k2 ^= (uint64_t) (tail[14]) << 48; \\\n        case 14: k2 ^= (uint64_t) (tail[13]) << 40; \\\n        case 13: k2 ^= (uint64_t) (tail[12]) << 32; \\\n        case 12: k2 ^= (uint64_t) (tail[11]) << 24; \\\n        case 11: k2 ^= (uint64_t) (tail[10]) << 16; \\\n        case 10: k2 ^= (uint64_t) (tail[ 9]) << 8; \\\n        case  9: k2 ^= (uint64_t) (tail[ 8]) << 0; \\\n                 k2 *= c2; k2 = CORK_ROTL64(k2,33); k2 *= c1; h2 ^= k2; \\\n        \\\n        case  8: k1 ^= (uint64_t) (tail[ 7]) << 56; \\\n        case  7: k1 ^= (uint64_t) (tail[ 6]) << 48; \\\n        case  6: k1 ^= (uint64_t) (tail[ 5]) << 40; \\\n        case  5: k1 ^= (uint64_t) (tail[ 4]) << 32; \\\n        case  4: k1 ^= (uint64_t) (tail[ 3]) << 24; \\\n        case  3: k1 ^= (uint64_t) (tail[ 2]) << 16; \\\n        case  2: k1 ^= (uint64_t) (tail[ 1]) << 8; \\\n        case  1: k1 ^= (uint64_t) (tail[ 0]) << 0; \\\n                 k1 *= c1; k1 = CORK_ROTL64(k1,31); k1 *= c2; h1 ^= k1; \\\n    }; \\\n    \\\n    /* finalization */ \\\n    \\\n    h1 ^= len; h2 ^= len; \\\n    \\\n    h1 += h2; \\\n    h2 += h1; \\\n    \\\n    h1 = cork_fmix64(h1); \\\n    h2 = cork_fmix64(h2); \\\n    \\\n    h1 += h2; \\\n    h2 += h1; \\\n    \\\n    (dest)->u128 = cork_u128_from_64(h1, h2); \\\n} while (0)\n\n\nCORK_INLINE\ncork_hash\ncork_hash_buffer(cork_hash seed, const void *src, size_t len)\n{\n#if CORK_SIZEOF_POINTER == 8\n    cork_big_hash  big_seed = {cork_u128_from_32(seed, seed, seed, seed)};\n    cork_big_hash  hash;\n    cork_murmur_hash_x64_128(big_seed, src, (unsigned int)len, &hash);\n    return cork_u128_be32(hash.u128, 0);\n#else\n    cork_hash  hash = 0;\n    cork_murmur_hash_x86_32(seed, src, (unsigned int)len, &hash);\n    return hash;\n#endif\n}\n\n\nCORK_INLINE\ncork_big_hash\ncork_big_hash_buffer(cork_big_hash seed, const void *src, size_t len)\n{\n    cork_big_hash  result;\n#if CORK_SIZEOF_POINTER == 8\n    cork_murmur_hash_x64_128(seed, src, (unsigned int)len, &result);\n#else\n    cork_murmur_hash_x86_128(seed, src, (unsigned int)len, &result);\n#endif\n    return result;\n}\n\n\n#define cork_hash_variable(seed, val) \\\n    (cork_hash_buffer((seed), &(val), sizeof((val))))\n#define cork_stable_hash_variable(seed, val) \\\n    (cork_stable_hash_buffer((seed), &(val), sizeof((val))))\n#define cork_big_hash_variable(seed, val) \\\n    (cork_big_hash_buffer((seed), &(val), sizeof((val))))\n\n\n#endif /* LIBCORK_CORE_HASH_H */\n"
  },
  {
    "path": "include/libcork/core/id.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_ID_H\n#define LIBCORK_CORE_ID_H\n\n#include <libcork/core/attributes.h>\n#include <libcork/core/hash.h>\n\n\nstruct cork_uid {\n    const char  *name;\n};\n\ntypedef const struct cork_uid  *cork_uid;\n\n#define CORK_UID_NONE  ((cork_uid) NULL)\n\n#define cork_uid_define_named(c_name, name) \\\n    static const struct cork_uid  c_name##__id = { name }; \\\n    static cork_uid  c_name = &c_name##__id;\n#define cork_uid_define(c_name) \\\n    cork_uid_define_named(c_name, #c_name)\n\nCORK_INLINE\nbool\ncork_uid_equal(const cork_uid id1, const cork_uid id2)\n{\n    return id1 == id2;\n}\n\nCORK_INLINE\ncork_hash\ncork_uid_hash(const cork_uid id)\n{\n    return (cork_hash) (uintptr_t) id;\n}\n\nCORK_INLINE\nconst char*\ncork_uid_name(const cork_uid id)\n{\n    return id->name;\n}\n\n\n#endif /* LIBCORK_CORE_ID_H */\n"
  },
  {
    "path": "include/libcork/core/mempool.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORK_MEMPOOL_H\n#define LIBCORK_CORK_MEMPOOL_H\n\n\n#include <libcork/config.h>\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/types.h>\n\n\n#define CORK_MEMPOOL_DEFAULT_BLOCK_SIZE  4096\n\n\nstruct cork_mempool;\n\n\nCORK_API struct cork_mempool *\ncork_mempool_new_size_ex(size_t element_size, size_t block_size);\n\nCORK_INLINE\nstruct cork_mempool*\ncork_mempool_new_size(size_t element_size)\n{\n    return cork_mempool_new_size_ex(\n            element_size, CORK_MEMPOOL_DEFAULT_BLOCK_SIZE);\n}\n\n#define cork_mempool_new_ex(type, block_size) \\\n    (cork_mempool_new_size_ex(sizeof(type), (block_size)))\n\n#define cork_mempool_new(type) \\\n    (cork_mempool_new_size(sizeof(type)))\n\nCORK_API void\ncork_mempool_free(struct cork_mempool *mp);\n\n\nCORK_API void\ncork_mempool_set_user_data(struct cork_mempool *mp,\n                           void *user_data, cork_free_f free_user_data);\n\nCORK_API void\ncork_mempool_set_init_object(struct cork_mempool *mp, cork_init_f init_object);\n\nCORK_API void\ncork_mempool_set_done_object(struct cork_mempool *mp, cork_done_f done_object);\n\n/* Deprecated; you should now use separate calls to cork_mempool_set_user_data,\n * cork_mempool_set_init_object, and cork_mempool_set_done_object. */\nCORK_API void\ncork_mempool_set_callbacks(struct cork_mempool *mp,\n                           void *user_data, cork_free_f free_user_data,\n                           cork_init_f init_object,\n                           cork_done_f done_object);\n\n\nCORK_API void *\ncork_mempool_new_object(struct cork_mempool *mp);\n\n\nCORK_API void\ncork_mempool_free_object(struct cork_mempool *mp, void *ptr);\n\n\n#endif /* LIBCORK_CORK_MEMPOOL_H */\n"
  },
  {
    "path": "include/libcork/core/net-addresses.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_NET_ADDRESSES_H\n#define LIBCORK_CORE_NET_ADDRESSES_H\n\n\n#include <string.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/error.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * IP addresses\n */\n\nstruct cork_ipv4 {\n    union {\n        uint8_t  u8[4];\n        uint16_t  u16[2];\n        uint32_t  u32;\n    } _;\n};\n\nstruct cork_ipv6 {\n    union {\n        uint8_t  u8[16];\n        uint16_t  u16[8];\n        uint32_t  u32[4];\n        uint64_t  u64[2];\n    } _;\n};\n\nstruct cork_ip {\n    /* Which version of IP address this is. */\n    unsigned int  version;\n    union {\n        struct cork_ipv4  v4;\n        struct cork_ipv6  v6;\n    } ip;\n};\n\n\n#define CORK_IPV4_STRING_LENGTH  (sizeof \"xxx.xxx.xxx.xxx\")\n#define CORK_IPV6_STRING_LENGTH \\\n    (sizeof \"ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255\")\n#define CORK_IP_STRING_LENGTH  CORK_IPV6_STRING_LENGTH\n\n\n/*** IPv4 ***/\n\n/* src must be well-formed: 4 bytes, big-endian */\nCORK_INLINE\nvoid\ncork_ipv4_copy(struct cork_ipv4* addr, const void* src)\n{\n    memcpy(addr, src, sizeof(struct cork_ipv4));\n}\n\nCORK_INLINE\nbool\ncork_ipv4_equal(const struct cork_ipv4* addr1, const struct cork_ipv4* addr2)\n{\n    return addr1->_.u32 == addr2->_.u32;\n}\n\nCORK_API int\ncork_ipv4_init(struct cork_ipv4 *addr, const char *str);\n\nCORK_API bool\ncork_ipv4_equal_(const struct cork_ipv4 *addr1, const struct cork_ipv4 *addr2);\n\nCORK_API void\ncork_ipv4_to_raw_string(const struct cork_ipv4 *addr, char *dest);\n\nCORK_API bool\ncork_ipv4_is_valid_network(const struct cork_ipv4 *addr,\n                           unsigned int cidr_prefix);\n\n\n/*** IPv6 ***/\n\n/* src must be well-formed: 16 bytes, big-endian */\nCORK_INLINE\nvoid\ncork_ipv6_copy(struct cork_ipv6* addr, const void* src)\n{\n    memcpy(addr, src, sizeof(struct cork_ipv6));\n}\n\nCORK_INLINE\nbool\ncork_ipv6_equal(const struct cork_ipv6* addr1, const struct cork_ipv6* addr2)\n{\n    return addr1->_.u64[0] == addr2->_.u64[0] &&\n        addr1->_.u64[1] == addr2->_.u64[1];\n}\n\nCORK_API int\ncork_ipv6_init(struct cork_ipv6 *addr, const char *str);\n\nCORK_API bool\ncork_ipv6_equal_(const struct cork_ipv6 *addr1, const struct cork_ipv6 *addr2);\n\nCORK_API void\ncork_ipv6_to_raw_string(const struct cork_ipv6 *addr, char *dest);\n\nCORK_API bool\ncork_ipv6_is_valid_network(const struct cork_ipv6 *addr,\n                           unsigned int cidr_prefix);\n\n\n/*** Generic IP ***/\n\nCORK_INLINE\nbool\ncork_ip_equal(const struct cork_ip* addr1, const struct cork_ip* addr2)\n{\n    if (addr1->version != addr2->version)\n        return false;\n    else if (addr1->version == 4) {\n        return cork_ipv4_equal(&addr1->ip.v4, &addr2->ip.v4);\n    } else {\n        return cork_ipv6_equal(&addr1->ip.v6, &addr2->ip.v6);\n    }\n}\n\n/* src must be well-formed: 4 bytes, big-endian */\nCORK_INLINE\nvoid\ncork_ip_from_ipv4(struct cork_ip* addr, const void* src)\n{\n    addr->version = 4;\n    cork_ipv4_copy(&addr->ip.v4, src);\n}\n\n/* src must be well-formed: 16 bytes, big-endian */\nCORK_INLINE\nvoid\ncork_ip_from_ipv6(struct cork_ip* addr, const void* src)\n{\n    addr->version = 6;\n    cork_ipv6_copy(&addr->ip.v6, src);\n}\n\nCORK_API int\ncork_ip_init(struct cork_ip *addr, const char *str);\n\nCORK_API void\ncork_ip_to_raw_string(const struct cork_ip *addr, char *dest);\n\nCORK_API bool\ncork_ip_is_valid_network(const struct cork_ip *addr, unsigned int cidr_prefix);\n\n\n#endif /* LIBCORK_CORE_NET_ADDRESSES_H */\n"
  },
  {
    "path": "include/libcork/core/timestamp.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_TIMESTAMP_H\n#define LIBCORK_CORE_TIMESTAMP_H\n\n\n#include <libcork/core/api.h>\n#include <libcork/core/error.h>\n#include <libcork/core/types.h>\n#include <libcork/ds/buffer.h>\n\n\ntypedef uint64_t  cork_timestamp;\n\n\nCORK_INLINE\nvoid\ncork_timestamp_init_sec(cork_timestamp* ts, uint64_t sec)\n{\n    *ts = sec << 32;\n}\n\nCORK_INLINE\nvoid\ncork_timestamp_init_gsec(cork_timestamp* ts, uint64_t sec, uint64_t gsec)\n{\n    *ts = (sec << 32) | (gsec & 0xffffffff);\n}\n\nCORK_INLINE\nvoid\ncork_timestamp_init_msec(cork_timestamp* ts, uint64_t sec, uint64_t msec)\n{\n    *ts = (sec << 32) | ((msec << 32) / 1000);\n}\n\nCORK_INLINE\nvoid\ncork_timestamp_init_usec(cork_timestamp* ts, uint64_t sec, uint64_t usec)\n{\n    *ts = (sec << 32) | ((usec << 32) / 1000000);\n}\n\nCORK_INLINE\nvoid\ncork_timestamp_init_nsec(cork_timestamp* ts, uint64_t sec, uint64_t nsec)\n{\n    *ts = (sec << 32) | ((nsec << 32) / 1000000000);\n}\n\n\nCORK_API void\ncork_timestamp_init_now(cork_timestamp *ts);\n\n\nCORK_INLINE\nuint32_t\ncork_timestamp_sec(const cork_timestamp ts)\n{\n    return (uint32_t) (ts >> 32);\n}\n\nCORK_INLINE\nuint32_t\ncork_timestamp_gsec(const cork_timestamp ts)\n{\n    return (uint32_t) (ts & 0xffffffff);\n}\n\nCORK_INLINE\nuint64_t\ncork_timestamp_gsec_to_units(const cork_timestamp ts, uint64_t denom)\n{\n    uint64_t  half = ((uint64_t) 1 << 31) / denom;\n    uint64_t  gsec = cork_timestamp_gsec(ts);\n    gsec += half;\n    gsec *= denom;\n    gsec >>= 32;\n    return gsec;\n}\n\nCORK_INLINE\nuint64_t\ncork_timestamp_msec(const cork_timestamp ts)\n{\n    return cork_timestamp_gsec_to_units(ts, 1000);\n}\n\nCORK_INLINE\nuint64_t\ncork_timestamp_usec(const cork_timestamp ts)\n{\n    return cork_timestamp_gsec_to_units(ts, 1000000);\n}\n\nCORK_INLINE\nuint64_t\ncork_timestamp_nsec(const cork_timestamp ts)\n{\n    return cork_timestamp_gsec_to_units(ts, 1000000000);\n}\n\n\nCORK_API int\ncork_timestamp_format_utc(const cork_timestamp ts, const char *format,\n                          struct cork_buffer *dest);\n\nCORK_API int\ncork_timestamp_format_local(const cork_timestamp ts, const char *format,\n                            struct cork_buffer *dest);\n\n\n#endif /* LIBCORK_CORE_TIMESTAMP_H */\n"
  },
  {
    "path": "include/libcork/core/types.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_TYPES_H\n#define LIBCORK_CORE_TYPES_H\n\n/* For now, we assume that the C99 integer types are available using the\n * standard headers. */\n\n#include <limits.h>\n#include <inttypes.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n\n/* Define preprocessor macros that contain the size of several built-in\n * types.  Again, we assume that we have the C99 definitions available. */\n\n#if SHRT_MAX == INT8_MAX\n#define CORK_SIZEOF_SHORT  1\n#elif SHRT_MAX == INT16_MAX\n#define CORK_SIZEOF_SHORT  2\n#elif SHRT_MAX == INT32_MAX\n#define CORK_SIZEOF_SHORT  4\n#elif SHRT_MAX == INT64_MAX\n#define CORK_SIZEOF_SHORT  8\n#else\n#error \"Cannot determine size of short\"\n#endif\n\n#if INT_MAX == INT8_MAX\n#define CORK_SIZEOF_INT  1\n#elif INT_MAX == INT16_MAX\n#define CORK_SIZEOF_INT  2\n#elif INT_MAX == INT32_MAX\n#define CORK_SIZEOF_INT  4\n#elif INT_MAX == INT64_MAX\n#define CORK_SIZEOF_INT  8\n#else\n#error \"Cannot determine size of int\"\n#endif\n\n#if LONG_MAX == INT8_MAX\n#define CORK_SIZEOF_LONG  1\n#elif LONG_MAX == INT16_MAX\n#define CORK_SIZEOF_LONG  2\n#elif LONG_MAX == INT32_MAX\n#define CORK_SIZEOF_LONG  4\n#elif LONG_MAX == INT64_MAX\n#define CORK_SIZEOF_LONG  8\n#else\n#error \"Cannot determine size of long\"\n#endif\n\n#if INTPTR_MAX == INT8_MAX\n#define CORK_SIZEOF_POINTER  1\n#elif INTPTR_MAX == INT16_MAX\n#define CORK_SIZEOF_POINTER  2\n#elif INTPTR_MAX == INT32_MAX\n#define CORK_SIZEOF_POINTER  4\n#elif INTPTR_MAX == INT64_MAX\n#define CORK_SIZEOF_POINTER  8\n#else\n#error \"Cannot determine size of void *\"\n#endif\n\n\n/* Return a pointer to a @c struct, given a pointer to one of its\n * fields. */\n#define cork_container_of(field, struct_type, field_name) \\\n    ((struct_type *) (- offsetof(struct_type, field_name) + \\\n                      (void *) (field)))\n\n#endif /* LIBCORK_CORE_TYPES_H */\n"
  },
  {
    "path": "include/libcork/core/u128.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_U128_H\n#define LIBCORK_CORE_U128_H\n\n\n#include <libcork/config.h>\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/byte-order.h>\n#include <libcork/core/types.h>\n\ntypedef struct {\n    union {\n        uint8_t  u8[16];\n        uint16_t  u16[8];\n        uint32_t  u32[4];\n        uint64_t  u64[2];\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n        struct { uint64_t hi; uint64_t lo; } be64;\n#else\n        struct { uint64_t lo; uint64_t hi; } be64;\n#endif\n#if CORK_CONFIG_HAVE_GCC_INT128\n#define CORK_U128_HAVE_U128  1\n        unsigned __int128  u128;\n#elif CORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE\n#define CORK_U128_HAVE_U128  1\n        unsigned int  u128 __attribute__((mode(TI)));\n#else\n#define CORK_U128_HAVE_U128  0\n#endif\n    } _;\n} cork_u128;\n\n\n/* i0-3 are given in big-endian order, regardless of host endianness */\nCORK_INLINE\ncork_u128\ncork_u128_from_32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3)\n{\n    cork_u128  value;\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n    value._.u32[0] = i0;\n    value._.u32[1] = i1;\n    value._.u32[2] = i2;\n    value._.u32[3] = i3;\n#else\n    value._.u32[3] = i0;\n    value._.u32[2] = i1;\n    value._.u32[1] = i2;\n    value._.u32[0] = i3;\n#endif\n    return value;\n}\n\n/* i0-1 are given in big-endian order, regardless of host endianness */\nCORK_INLINE\ncork_u128\ncork_u128_from_64(uint64_t i0, uint64_t i1)\n{\n    cork_u128  value;\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n    value._.u64[0] = i0;\n    value._.u64[1] = i1;\n#else\n    value._.u64[1] = i0;\n    value._.u64[0] = i1;\n#endif\n    return value;\n}\n\nCORK_INLINE\ncork_u128\ncork_u128_zero(void)\n{\n    return cork_u128_from_64(0, 0);\n}\n\n\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n#define cork_u128_be8(val, idx)   ((val)._.u8[(idx)])\n#define cork_u128_be16(val, idx)  ((val)._.u16[(idx)])\n#define cork_u128_be32(val, idx)  ((val)._.u32[(idx)])\n#define cork_u128_be64(val, idx)  ((val)._.u64[(idx)])\n#else\n#define cork_u128_be8(val, idx)   ((val)._.u8[15 - (idx)])\n#define cork_u128_be16(val, idx)  ((val)._.u16[7 - (idx)])\n#define cork_u128_be32(val, idx)  ((val)._.u32[3 - (idx)])\n#define cork_u128_be64(val, idx)  ((val)._.u64[1 - (idx)])\n#endif\n\n#define CORK_SWAP_UINT128(__u128)                                              \\\n  (cork_u128_from_64(CORK_SWAP_UINT64(cork_u128_be64((__u128), 1)),            \\\n                     CORK_SWAP_UINT64(cork_u128_be64((__u128), 0))))\n\n#define CORK_SWAP_IN_PLACE_UINT128(__u128) \\\n    do { \\\n        (__u128) = CORK_SWAP_UINT128(__u128); \\\n    } while (0)\n\n#if CORK_HOST_ENDIANNESS == CORK_BIG_ENDIAN\n#define CORK_UINT128_BIG_TO_HOST(__u128) (__u128) /* nothing to do */\n#define CORK_UINT128_LITTLE_TO_HOST(__u128)  CORK_SWAP_UINT128(__u128)\n#define CORK_UINT128_BIG_TO_HOST_IN_PLACE(__u128) /* nothing to do */\n#define CORK_UINT128_LITTLE_TO_HOST_IN_PLACE(__u128)                           \\\n  CORK_SWAP_IN_PLACE_UINT128(__u128)\n#elif CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN\n#define CORK_UINT128_BIG_TO_HOST(__u128)  CORK_SWAP_UINT128(__u128)\n#define CORK_UINT128_LITTLE_TO_HOST(__u128) (__u128) /* nothing to do */\n#define CORK_UINT128_BIG_TO_HOST_IN_PLACE(__u128)                              \\\n  CORK_SWAP_IN_PLACE_UINT128(__u128)\n#define CORK_UINT128_LITTLE_TO_HOST_IN_PLACE(__u128) /* nothing to do */\n#endif\n\n#define CORK_UINT128_HOST_TO_BIG(__u128) CORK_UINT128_BIG_TO_HOST(__u128)\n#define CORK_UINT128_HOST_TO_LITTLE(__u128) CORK_UINT128_LITTLE_TO_HOST(__u128)\n#define CORK_UINT128_HOST_TO_BIG_IN_PLACE(__u128)                              \\\n  CORK_UINT128_BIG_TO_HOST_IN_PLACE(__u128)\n#define CORK_UINT128_HOST_TO_LITTLE_IN_PLACE(__u128)                           \\\n  CORK_UINT128_LITTLE_TO_HOST_IN_PLACE(__u128)\n\nCORK_INLINE\nbool\ncork_u128_eq(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 == b._.u128);\n#else\n    return (a._.be64.hi == b._.be64.hi) && (a._.be64.lo == b._.be64.lo);\n#endif\n}\n\nCORK_INLINE\nbool\ncork_u128_ne(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 != b._.u128);\n#else\n    return (a._.be64.hi != b._.be64.hi) || (a._.be64.lo != b._.be64.lo);\n#endif\n}\n\nCORK_INLINE\nbool\ncork_u128_lt(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 < b._.u128);\n#else\n    if (a._.be64.hi == b._.be64.hi) {\n        return a._.be64.lo < b._.be64.lo;\n    } else {\n        return a._.be64.hi < b._.be64.hi;\n    }\n#endif\n}\n\nCORK_INLINE\nbool\ncork_u128_le(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 <= b._.u128);\n#else\n    if (a._.be64.hi == b._.be64.hi) {\n        return a._.be64.lo <= b._.be64.lo;\n    } else {\n        return a._.be64.hi <= b._.be64.hi;\n    }\n#endif\n}\n\nCORK_INLINE\nbool\ncork_u128_gt(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 > b._.u128);\n#else\n    if (a._.be64.hi == b._.be64.hi) {\n        return a._.be64.lo > b._.be64.lo;\n    } else {\n        return a._.be64.hi > b._.be64.hi;\n    }\n#endif\n}\n\nCORK_INLINE\nbool\ncork_u128_ge(cork_u128 a, cork_u128 b)\n{\n#if CORK_U128_HAVE_U128\n    return (a._.u128 >= b._.u128);\n#else\n    if (a._.be64.hi == b._.be64.hi) {\n        return a._.be64.lo >= b._.be64.lo;\n    } else {\n        return a._.be64.hi >= b._.be64.hi;\n    }\n#endif\n}\n\n\nCORK_INLINE\ncork_u128\ncork_u128_shl(cork_u128 a, unsigned int b)\n{\n#if CORK_U128_HAVE_U128\n    cork_u128  result;\n    result._.u128 = a._.u128 << b;\n    return result;\n#else\n    if (b == 0) {\n        return a;\n    }\n    if (b == 64) {\n        return cork_u128_from_64(a._.be64.lo, 0);\n    }\n    if (b >= 128) {\n        /* This is undefined behavior */\n        return cork_u128_zero();\n    }\n    if (b >= 64) {\n        return cork_u128_from_64(a._.be64.lo << (b - 64), 0);\n    }\n    return cork_u128_from_64(\n        (a._.be64.hi << b) + (a._.be64.lo >> (64 - b)),\n        a._.be64.lo << b);\n#endif\n}\n\nCORK_INLINE\ncork_u128\ncork_u128_shr(cork_u128 a, unsigned int b)\n{\n#if CORK_U128_HAVE_U128\n    cork_u128  result;\n    result._.u128 = a._.u128 >> b;\n    return result;\n#else\n    if (b == 0) {\n        return a;\n    }\n    if (b == 64) {\n        return cork_u128_from_64(0, a._.be64.hi);\n    }\n    if (b >= 128) {\n        /* This is undefined behavior */\n        return cork_u128_zero();\n    }\n    if (b >= 64) {\n        return cork_u128_from_64(0, a._.be64.hi >> (b - 64));\n    }\n    return cork_u128_from_64(\n        a._.be64.hi >> b,\n        (a._.be64.lo >> b) + (a._.be64.hi << (64 - b)));\n#endif\n}\n\n\nCORK_INLINE\ncork_u128\ncork_u128_add(cork_u128 a, cork_u128 b)\n{\n    cork_u128  result;\n#if CORK_U128_HAVE_U128\n    result._.u128 = a._.u128 + b._.u128;\n#else\n    result._.be64.lo = a._.be64.lo + b._.be64.lo;\n    result._.be64.hi =\n        a._.be64.hi + b._.be64.hi + (result._.be64.lo < a._.be64.lo);\n#endif\n    return result;\n}\n\nCORK_INLINE\ncork_u128\ncork_u128_sub(cork_u128 a, cork_u128 b)\n{\n    cork_u128  result;\n#if CORK_U128_HAVE_U128\n    result._.u128 = a._.u128 - b._.u128;\n#else\n    result._.be64.lo = a._.be64.lo - b._.be64.lo;\n    result._.be64.hi =\n        a._.be64.hi - b._.be64.hi - (result._.be64.lo > a._.be64.lo);\n#endif\n    return result;\n}\n\n\n/* log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322 */\n#define CORK_U128_DECIMAL_LENGTH  44  /* ~= 128 / 3 + 1 + 1 */\n\nCORK_API const char *\ncork_u128_to_decimal(char *buf, cork_u128 val);\n\n\n#define CORK_U128_HEX_LENGTH  33\n\nCORK_API const char *\ncork_u128_to_hex(char *buf, cork_u128 val);\n\nCORK_API const char *\ncork_u128_to_padded_hex(char *buf, cork_u128 val);\n\n\n#endif /* LIBCORK_CORE_U128_H */\n"
  },
  {
    "path": "include/libcork/core.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_H\n#define LIBCORK_CORE_H\n\n/*** include all of the parts ***/\n\n#include <libcork/core/allocator.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/byte-order.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/error.h>\n#include <libcork/core/gc.h>\n#include <libcork/core/hash.h>\n#include <libcork/core/id.h>\n#include <libcork/core/mempool.h>\n#include <libcork/core/net-addresses.h>\n#include <libcork/core/timestamp.h>\n#include <libcork/core/types.h>\n#include <libcork/core/u128.h>\n\n#endif /* LIBCORK_CORE_H */\n"
  },
  {
    "path": "include/libcork/ds/array.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_ARRAY_H\n#define LIBCORK_DS_ARRAY_H\n\n\n#include <libcork/core/api.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * Resizable arrays\n */\n\nstruct cork_array_priv;\n\nstruct cork_raw_array {\n    void  *items;\n    size_t  size;\n    struct cork_array_priv  *priv;\n};\n\nCORK_API void\ncork_raw_array_init(struct cork_raw_array *array, size_t element_size);\n\nCORK_API void\ncork_raw_array_done(struct cork_raw_array *array);\n\nCORK_API void\ncork_raw_array_set_callback_data(struct cork_raw_array *array,\n                                 void *user_data, cork_free_f free_user_data);\n\nCORK_API void\ncork_raw_array_set_init(struct cork_raw_array *array, cork_init_f init);\n\nCORK_API void\ncork_raw_array_set_done(struct cork_raw_array *array, cork_done_f done);\n\nCORK_API void\ncork_raw_array_set_reuse(struct cork_raw_array *array, cork_init_f reuse);\n\nCORK_API void\ncork_raw_array_set_remove(struct cork_raw_array *array, cork_done_f remove);\n\nCORK_API size_t\ncork_raw_array_element_size(const struct cork_raw_array *array);\n\nCORK_API void\ncork_raw_array_clear(struct cork_raw_array *array);\n\nCORK_API void *\ncork_raw_array_elements(const struct cork_raw_array *array);\n\nCORK_API void *\ncork_raw_array_at(const struct cork_raw_array *array, size_t index);\n\nCORK_API size_t\ncork_raw_array_size(const struct cork_raw_array *array);\n\nCORK_API bool\ncork_raw_array_is_empty(const struct cork_raw_array *array);\n\nCORK_API void\ncork_raw_array_ensure_size(struct cork_raw_array *array, size_t count);\n\nCORK_API void *\ncork_raw_array_append(struct cork_raw_array *array);\n\nCORK_API void\ncork_raw_array_remove_range(struct cork_raw_array* array, size_t index,\n                            size_t count);\n\nCORK_INLINE\nvoid\ncork_raw_array_remove(struct cork_raw_array *array, size_t index)\n{\n    cork_raw_array_remove_range(array, index, 1);\n}\n\nCORK_API int\ncork_raw_array_copy(struct cork_raw_array *dest,\n                    const struct cork_raw_array *src,\n                    cork_copy_f copy, void *user_data);\n\n\n/*-----------------------------------------------------------------------\n * Type-checked resizable arrays\n */\n\n#define cork_array(T) \\\n    struct { \\\n        T  *items; \\\n        size_t  size; \\\n        struct cork_array_priv  *priv; \\\n    }\n\n#define cork_array_element_size(arr)  (sizeof((arr)->items[0]))\n#define cork_array_elements(arr)  ((arr)->items)\n#define cork_array_at(arr, i)     ((arr)->items[(i)])\n#define cork_array_size(arr)      ((arr)->size)\n#define cork_array_is_empty(arr)  ((arr)->size == 0)\n#define cork_array_to_raw(arr)    ((struct cork_raw_array *) (void *) (arr))\n\n#define cork_array_init(arr) \\\n    (cork_raw_array_init(cork_array_to_raw(arr), cork_array_element_size(arr)))\n#define cork_array_done(arr) \\\n    (cork_raw_array_done(cork_array_to_raw(arr)))\n\n#define cork_array_set_callback_data(arr, ud, fud) \\\n    (cork_raw_array_set_callback_data(cork_array_to_raw(arr), (ud), (fud)))\n#define cork_array_set_init(arr, i) \\\n    (cork_raw_array_set_init(cork_array_to_raw(arr), (i)))\n#define cork_array_set_done(arr, d) \\\n    (cork_raw_array_set_done(cork_array_to_raw(arr), (d)))\n#define cork_array_set_reuse(arr, r) \\\n    (cork_raw_array_set_reuse(cork_array_to_raw(arr), (r)))\n#define cork_array_set_remove(arr, r) \\\n    (cork_raw_array_set_remove(cork_array_to_raw(arr), (r)))\n\n#define cork_array_clear(arr) \\\n    (cork_raw_array_clear(cork_array_to_raw(arr)))\n#define cork_array_copy(d, s, c, ud) \\\n    (cork_raw_array_copy(cork_array_to_raw(d), cork_array_to_raw(s), (c), (ud)))\n\n#define cork_array_ensure_size(arr, count) \\\n    (cork_raw_array_ensure_size(cork_array_to_raw(arr), (count)))\n\n#define cork_array_append(arr, element) \\\n    (cork_raw_array_append(cork_array_to_raw(arr)), \\\n     ((arr)->items[(arr)->size - 1] = (element), (void) 0))\n\n#define cork_array_append_get(arr) \\\n    (cork_raw_array_append(cork_array_to_raw(arr)), \\\n     &(arr)->items[(arr)->size - 1])\n\n#define cork_array_remove(arr, element)                                        \\\n    (cork_raw_array_remove(cork_array_to_raw(arr), (element)))\n#define cork_array_remove_range(arr, element, count)                           \\\n    (cork_raw_array_remove_range(cork_array_to_raw(arr), (element), (count)))\n\n\n/*-----------------------------------------------------------------------\n * Builtin array types\n */\n\nCORK_API void\ncork_raw_pointer_array_init(struct cork_raw_array *array, cork_free_f free);\n\n#define cork_pointer_array_init(arr, f) \\\n    (cork_raw_pointer_array_init(cork_array_to_raw(arr), (f)))\n\nstruct cork_string_array {\n    const char  **items;\n    size_t  size;\n    struct cork_array_priv  *priv;\n};\n\nCORK_API void\ncork_string_array_init(struct cork_string_array *array);\n\nCORK_API void\ncork_string_array_append(struct cork_string_array *array, const char *str);\n\nCORK_API void\ncork_string_array_copy(struct cork_string_array *dest,\n                       const struct cork_string_array *src);\n\n\n#endif /* LIBCORK_DS_ARRAY_H */\n"
  },
  {
    "path": "include/libcork/ds/bitset.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_BITS_H\n#define LIBCORK_DS_BITS_H\n\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * Bit sets\n */\n\nstruct cork_bitset {\n    uint8_t  *bits;\n    size_t  bit_count;\n    size_t  byte_count;\n};\n\nCORK_API struct cork_bitset *\ncork_bitset_new(size_t bit_count);\n\nCORK_API void\ncork_bitset_init(struct cork_bitset *set, size_t bit_count);\n\nCORK_API void\ncork_bitset_free(struct cork_bitset *set);\n\nCORK_API void\ncork_bitset_done(struct cork_bitset *set);\n\nCORK_API void\ncork_bitset_clear(struct cork_bitset *set);\n\n/* Extract the byte that contains a particular bit in an array. */\n#define cork_bitset_byte_for_bit(set, i) \\\n    ((set)->bits[(i) / 8])\n\n/* Create a bit mask that extracts a particular bit from the byte that it lives\n * in. */\n#define cork_bitset_pos_mask_for_bit(i) \\\n    (0x80 >> ((i) % 8))\n\n/* Create a bit mask that extracts everything except for a particular bit from\n * the byte that it lives in. */\n#define cork_bitset_neg_mask_for_bit(i) \\\n    (~cork_bitset_pos_mask_for_bit(i))\n\n/* Return whether a particular bit is set in a byte array.  Bits are numbered\n * from 0, in a big-endian order. */\n#define cork_bitset_get(set, i) \\\n    ((cork_bitset_byte_for_bit(set, i) & cork_bitset_pos_mask_for_bit(i)) != 0)\n\n/* Set (or unset) a particular bit is set in a byte array.  Bits are numbered\n * from 0, in a big-endian order. */\n#define cork_bitset_set(set, i, val) \\\n    (cork_bitset_byte_for_bit(set, i) = \\\n     (cork_bitset_byte_for_bit(set, i) & cork_bitset_neg_mask_for_bit(i)) \\\n     | ((val)? cork_bitset_pos_mask_for_bit(i): 0))\n\n\n#endif /* LIBCORK_DS_BITS_H */\n"
  },
  {
    "path": "include/libcork/ds/buffer.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_BUFFER_H\n#define LIBCORK_DS_BUFFER_H\n\n\n#include <stdarg.h>\n#include <string.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/types.h>\n\n\nstruct cork_buffer {\n    /* The current contents of the buffer. */\n    void  *buf;\n    /* The current size of the buffer. */\n    size_t  size;\n    /* The amount of space allocated for buf. */\n    size_t  allocated_size;\n};\n\n\nCORK_INLINE\nvoid\ncork_buffer_init(struct cork_buffer* buffer)\n{\n    buffer->buf = NULL;\n    buffer->size = 0;\n    buffer->allocated_size = 0;\n}\n\n#define CORK_BUFFER_INIT()  { NULL, 0, 0 }\n\nCORK_API struct cork_buffer *\ncork_buffer_new(void);\n\nCORK_API void\ncork_buffer_done(struct cork_buffer *buffer);\n\nCORK_API void\ncork_buffer_free(struct cork_buffer *buffer);\n\n\nCORK_API bool\ncork_buffer_equal(const struct cork_buffer *buffer1,\n                  const struct cork_buffer *buffer2);\n\n\nCORK_API\nvoid\ncork_buffer_ensure_size_(struct cork_buffer* buffer, size_t desired_size);\n\nCORK_INLINE\nvoid\ncork_buffer_ensure_size(struct cork_buffer* buffer, size_t desired_size)\n{\n    if (CORK_UNLIKELY(buffer->allocated_size < desired_size)) {\n        cork_buffer_ensure_size_(buffer, desired_size);\n    }\n}\n\n\nCORK_INLINE\nvoid\ncork_buffer_clear(struct cork_buffer* buffer)\n{\n    buffer->size = 0;\n    if (buffer->buf != NULL) {\n        ((char*) buffer->buf)[0] = '\\0';\n    }\n}\n\nCORK_INLINE\nvoid\ncork_buffer_truncate(struct cork_buffer* buffer, size_t length)\n{\n    if (buffer->size > length) {\n        buffer->size = length;\n        if (buffer->buf != NULL) {\n            ((char*) buffer->buf)[length] = '\\0';\n        }\n    }\n}\n\n#define cork_buffer_byte(buffer, i)  (((const uint8_t *) (buffer)->buf)[(i)])\n#define cork_buffer_char(buffer, i)  (((const char *) (buffer)->buf)[(i)])\n\n\n/*-----------------------------------------------------------------------\n * A whole bunch of methods for adding data\n */\n\nCORK_INLINE\nvoid\ncork_buffer_set(struct cork_buffer* buffer, const void* src, size_t length)\n{\n    cork_buffer_ensure_size(buffer, length + 1);\n    memcpy(buffer->buf, src, length);\n    ((char*) buffer->buf)[length] = '\\0';\n    buffer->size = length;\n}\n\nCORK_INLINE\nvoid\ncork_buffer_copy(struct cork_buffer* dest, const struct cork_buffer* src)\n{\n    cork_buffer_set(dest, src->buf, src->size);\n}\n\nCORK_INLINE\nvoid\ncork_buffer_append(struct cork_buffer* buffer, const void* src, size_t length)\n{\n    cork_buffer_ensure_size(buffer, buffer->size + length + 1);\n    memcpy(buffer->buf + buffer->size, src, length);\n    buffer->size += length;\n    ((char*) buffer->buf)[buffer->size] = '\\0';\n}\n\nCORK_INLINE\nvoid\ncork_buffer_append_copy(struct cork_buffer* dest, const struct cork_buffer* src)\n{\n    cork_buffer_append(dest, src->buf, src->size);\n}\n\n\nCORK_INLINE\nvoid\ncork_buffer_set_string(struct cork_buffer* buffer, const char* str)\n{\n    cork_buffer_set(buffer, str, strlen(str));\n}\n\nCORK_INLINE\nvoid\ncork_buffer_append_string(struct cork_buffer* buffer, const char* str)\n{\n    cork_buffer_append(buffer, str, strlen(str));\n}\n\n#define cork_buffer_set_literal(buffer, str) \\\n    (cork_buffer_set((buffer), (str), sizeof((str)) - 1))\n\n#define cork_buffer_append_literal(buffer, str) \\\n    (cork_buffer_append((buffer), (str), sizeof((str)) - 1))\n\n\nCORK_API void\ncork_buffer_printf(struct cork_buffer *buffer, const char *format, ...)\n    CORK_ATTR_PRINTF(2,3);\n\nCORK_API void\ncork_buffer_append_printf(struct cork_buffer *buffer, const char *format, ...)\n    CORK_ATTR_PRINTF(2,3);\n\nCORK_API void\ncork_buffer_vprintf(struct cork_buffer *buffer, const char *format,\n                    va_list args)\n    CORK_ATTR_PRINTF(2,0);\n\nCORK_API void\ncork_buffer_append_vprintf(struct cork_buffer *buffer, const char *format,\n                           va_list args)\n    CORK_ATTR_PRINTF(2,0);\n\n\n/*-----------------------------------------------------------------------\n * Some helpers for pretty-printing data\n */\n\nCORK_API void\ncork_buffer_append_indent(struct cork_buffer *buffer, size_t indent);\n\nCORK_API void\ncork_buffer_append_c_string(struct cork_buffer *buffer,\n                            const char *src, size_t length);\n\nCORK_API void\ncork_buffer_append_hex_dump(struct cork_buffer *buffer, size_t indent,\n                            const char *src, size_t length);\n\nCORK_API void\ncork_buffer_append_multiline(struct cork_buffer *buffer, size_t indent,\n                             const char *src, size_t length);\n\nCORK_API void\ncork_buffer_append_binary(struct cork_buffer *buffer, size_t indent,\n                          const char *src, size_t length);\n\n\n/*-----------------------------------------------------------------------\n * Buffer's managed buffer/slice implementation\n */\n\n#include <libcork/ds/managed-buffer.h>\n#include <libcork/ds/slice.h>\n\nCORK_API struct cork_managed_buffer *\ncork_buffer_to_managed_buffer(struct cork_buffer *buffer);\n\nCORK_API int\ncork_buffer_to_slice(struct cork_buffer *buffer, struct cork_slice *slice);\n\n\n/*-----------------------------------------------------------------------\n * Buffer's stream consumer implementation\n */\n\n#include <libcork/ds/stream.h>\n\nCORK_API struct cork_stream_consumer *\ncork_buffer_to_stream_consumer(struct cork_buffer *buffer);\n\n\n#endif /* LIBCORK_DS_BUFFER_H */\n"
  },
  {
    "path": "include/libcork/ds/dllist.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_DLLIST_H\n#define LIBCORK_DS_DLLIST_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n\n\nstruct cork_dllist_item {\n    /* A pointer to the next element in the list. */\n    struct cork_dllist_item  *next;\n    /* A pointer to the previous element in the list. */\n    struct cork_dllist_item  *prev;\n};\n\n\nstruct cork_dllist {\n    /* The sentinel element for this list. */\n    struct cork_dllist_item  head;\n};\n\n#define CORK_DLLIST_INIT(list)  { { &(list).head, &(list).head } }\n\n#define cork_dllist_init(list) \\\n    do { \\\n        (list)->head.next = &(list)->head; \\\n        (list)->head.prev = &(list)->head; \\\n    } while (0)\n\n\n\n/* DEPRECATED!  Use cork_dllist_foreach or cork_dllist_visit instead. */\ntypedef void\n(*cork_dllist_map_func)(struct cork_dllist_item *element, void *user_data);\n\nCORK_API void\ncork_dllist_map(struct cork_dllist *list,\n                cork_dllist_map_func func, void *user_data);\n\n\ntypedef int\ncork_dllist_visit_f(void *ud, struct cork_dllist_item *element);\n\nCORK_API int\ncork_dllist_visit(struct cork_dllist *list, void *ud,\n                  cork_dllist_visit_f *visit);\n\n\n#define cork_dllist_foreach_void(list, curr, _next) \\\n    for ((curr) = cork_dllist_start((list)), (_next) = (curr)->next; \\\n         !cork_dllist_is_end((list), (curr)); \\\n         (curr) = (_next), (_next) = (curr)->next)\n\n#define cork_dllist_foreach(list, curr, _next, etype, element, item_field) \\\n    for ((curr) = cork_dllist_start((list)), (_next) = (curr)->next, \\\n         (element) = cork_container_of((curr), etype, item_field); \\\n         !cork_dllist_is_end((list), (curr)); \\\n         (curr) = (_next), (_next) = (curr)->next, \\\n         (element) = cork_container_of((curr), etype, item_field))\n\n\nCORK_API size_t\ncork_dllist_size(const struct cork_dllist *list);\n\n\n#define cork_dllist_add_after(pred, element) \\\n    do { \\\n        (element)->prev = (pred); \\\n        (element)->next = (pred)->next; \\\n        (pred)->next->prev = (element); \\\n        (pred)->next = (element); \\\n    } while (0)\n\n#define cork_dllist_add_before(succ, element) \\\n    do { \\\n        (element)->next = (succ); \\\n        (element)->prev = (succ)->prev; \\\n        (succ)->prev->next = (element); \\\n        (succ)->prev = (element); \\\n    } while (0)\n\n#define cork_dllist_add_to_head(list, element) \\\n    cork_dllist_add_after(&(list)->head, (element))\n\n#define cork_dllist_add_to_tail(list, element) \\\n    cork_dllist_add_before(&(list)->head, (element))\n\n#define cork_dllist_add  cork_dllist_add_to_tail\n\n\n#define cork_dllist_add_list_to_head(dest, src) \\\n    do { \\\n        struct cork_dllist_item  *dest_start = cork_dllist_start(dest); \\\n        struct cork_dllist_item  *src_start = cork_dllist_start(src); \\\n        dest_start->prev = &(src)->head; \\\n        src_start->prev = &(dest)->head; \\\n        (src)->head.next = dest_start; \\\n        (dest)->head.next = src_start; \\\n        cork_dllist_remove(&(src)->head); \\\n        cork_dllist_init(src); \\\n    } while (0)\n\n#define cork_dllist_add_list_to_tail(dest, src) \\\n    do { \\\n        struct cork_dllist_item  *dest_end = cork_dllist_end(dest); \\\n        struct cork_dllist_item  *src_end = cork_dllist_end(src); \\\n        dest_end->next = &(src)->head; \\\n        src_end->next = &(dest)->head; \\\n        (src)->head.prev = dest_end; \\\n        (dest)->head.prev = src_end; \\\n        cork_dllist_remove(&(src)->head); \\\n        cork_dllist_init(src); \\\n    } while (0)\n\n\n#define cork_dllist_remove(element) \\\n    do { \\\n        (element)->prev->next = (element)->next; \\\n        (element)->next->prev = (element)->prev; \\\n    } while (0)\n\n\n#define cork_dllist_is_empty(list) \\\n    (cork_dllist_is_end((list), cork_dllist_start((list))))\n\n\n#define cork_dllist_head(list) \\\n    (((list)->head.next == &(list)->head)? NULL: (list)->head.next)\n#define cork_dllist_tail(list) \\\n    (((list)->head.prev == &(list)->head)? NULL: (list)->head.prev)\n\n#define cork_dllist_start(list) \\\n    ((list)->head.next)\n#define cork_dllist_end(list) \\\n    ((list)->head.prev)\n\n#define cork_dllist_is_start(list, element) \\\n    ((element) == &(list)->head)\n#define cork_dllist_is_end(list, element) \\\n    ((element) == &(list)->head)\n\n\n#endif /* LIBCORK_DS_DLLIST_H */\n"
  },
  {
    "path": "include/libcork/ds/hash-table.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_HASH_TABLE_H\n#define LIBCORK_DS_HASH_TABLE_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/hash.h>\n#include <libcork/core/mempool.h>\n#include <libcork/core/types.h>\n#include <libcork/ds/dllist.h>\n\n\n/*-----------------------------------------------------------------------\n * Hash tables\n */\n\nstruct cork_hash_table_entry {\n    cork_hash  hash;\n    void  *key;\n    void  *value;\n};\n\n\nstruct cork_hash_table;\n\nCORK_API struct cork_hash_table *\ncork_hash_table_new(size_t initial_size, unsigned int flags);\n\nCORK_API void\ncork_hash_table_free(struct cork_hash_table *table);\n\n\nCORK_API void\ncork_hash_table_set_user_data(struct cork_hash_table *table,\n                              void *user_data, cork_free_f free_user_data);\n\nCORK_API void\ncork_hash_table_set_equals(struct cork_hash_table *table, cork_equals_f equals);\n\nCORK_API void\ncork_hash_table_set_free_key(struct cork_hash_table *table, cork_free_f free);\n\nCORK_API void\ncork_hash_table_set_free_value(struct cork_hash_table *table, cork_free_f free);\n\nCORK_API void\ncork_hash_table_set_hash(struct cork_hash_table *table, cork_hash_f hash);\n\n\nCORK_API void\ncork_hash_table_clear(struct cork_hash_table *table);\n\n\nCORK_API void\ncork_hash_table_ensure_size(struct cork_hash_table *table,\n                            size_t desired_count);\n\nCORK_API size_t\ncork_hash_table_size(const struct cork_hash_table *table);\n\n\nCORK_API void *\ncork_hash_table_get(const struct cork_hash_table *table, const void *key);\n\nCORK_API void *\ncork_hash_table_get_hash(const struct cork_hash_table *table,\n                         cork_hash hash, const void *key);\n\nCORK_API struct cork_hash_table_entry *\ncork_hash_table_get_entry(const struct cork_hash_table *table,\n                          const void *key);\n\nCORK_API struct cork_hash_table_entry *\ncork_hash_table_get_entry_hash(const struct cork_hash_table *table,\n                               cork_hash hash, const void *key);\n\nCORK_API struct cork_hash_table_entry *\ncork_hash_table_get_or_create(struct cork_hash_table *table,\n                              void *key, bool *is_new);\n\nCORK_API struct cork_hash_table_entry *\ncork_hash_table_get_or_create_hash(struct cork_hash_table *table,\n                                   cork_hash hash, void *key, bool *is_new);\n\nCORK_API void\ncork_hash_table_put(struct cork_hash_table *table,\n                    void *key, void *value,\n                    bool *is_new, void **old_key, void **old_value);\n\nCORK_API void\ncork_hash_table_put_hash(struct cork_hash_table *table,\n                         cork_hash hash, void *key, void *value,\n                         bool *is_new, void **old_key, void **old_value);\n\nCORK_API void\ncork_hash_table_delete_entry(struct cork_hash_table *table,\n                             struct cork_hash_table_entry *entry);\n\nCORK_API bool\ncork_hash_table_delete(struct cork_hash_table *table, const void *key,\n                       void **deleted_key, void **deleted_value);\n\nCORK_API bool\ncork_hash_table_delete_hash(struct cork_hash_table *table,\n                            cork_hash hash, const void *key,\n                            void **deleted_key, void **deleted_value);\n\n\nenum cork_hash_table_map_result {\n    /* Abort the current @ref cork_hash_table_map operation. */\n    CORK_HASH_TABLE_MAP_ABORT = 0,\n    /* Continue on to the next entry in the hash table. */\n    CORK_HASH_TABLE_MAP_CONTINUE = 1,\n    /* Delete the entry that was just processed, and then continue on to\n     * the next entry in the hash table. */\n    CORK_HASH_TABLE_MAP_DELETE = 2\n};\n\ntypedef enum cork_hash_table_map_result\n(*cork_hash_table_map_f)(void *user_data, struct cork_hash_table_entry *entry);\n\nCORK_API void\ncork_hash_table_map(struct cork_hash_table *table, void *user_data,\n                    cork_hash_table_map_f mapper);\n\n\nstruct cork_hash_table_iterator {\n    struct cork_hash_table  *table;\n    void  *priv;\n};\n\nCORK_API void\ncork_hash_table_iterator_init(struct cork_hash_table *table,\n                              struct cork_hash_table_iterator *iterator);\n\nCORK_API struct cork_hash_table_entry *\ncork_hash_table_iterator_next(struct cork_hash_table_iterator *iterator);\n\n\n/*-----------------------------------------------------------------------\n * Built-in key types\n */\n\nCORK_API struct cork_hash_table *\ncork_string_hash_table_new(size_t initial_size, unsigned int flags);\n\nCORK_API struct cork_hash_table *\ncork_pointer_hash_table_new(size_t initial_size, unsigned int flags);\n\n\n#endif /* LIBCORK_DS_HASH_TABLE_H */\n"
  },
  {
    "path": "include/libcork/ds/managed-buffer.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_MANAGED_BUFFER_H\n#define LIBCORK_DS_MANAGED_BUFFER_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n#include <libcork/ds/slice.h>\n\n\n/*-----------------------------------------------------------------------\n * Managed buffers\n */\n\nstruct cork_managed_buffer;\n\nstruct cork_managed_buffer_iface {\n    /* Free the contents of a managed buffer, and the managed buffer\n     * object itself. */\n    void\n    (*free)(struct cork_managed_buffer *buf);\n};\n\n\nstruct cork_managed_buffer {\n    /* The buffer that this instance manages */\n    const void  *buf;\n    /* The size of buf */\n    size_t  size;\n    /* A reference count for the buffer.  If this drops to 0, the buffer\n     * will be finalized. */\n    volatile int  ref_count;\n    /* The managed buffer implementation for this instance. */\n    struct cork_managed_buffer_iface  *iface;\n};\n\n\nCORK_API struct cork_managed_buffer *\ncork_managed_buffer_new_copy(const void *buf, size_t size);\n\n\ntypedef void\n(*cork_managed_buffer_freer)(void *buf, size_t size);\n\nCORK_API struct cork_managed_buffer *\ncork_managed_buffer_new(const void *buf, size_t size,\n                        cork_managed_buffer_freer free);\n\n\nCORK_API struct cork_managed_buffer *\ncork_managed_buffer_ref(struct cork_managed_buffer *buf);\n\nCORK_API void\ncork_managed_buffer_unref(struct cork_managed_buffer *buf);\n\n\nCORK_API int\ncork_managed_buffer_slice(struct cork_slice *dest,\n                          struct cork_managed_buffer *buffer,\n                          size_t offset, size_t length);\n\nCORK_API int\ncork_managed_buffer_slice_offset(struct cork_slice *dest,\n                                 struct cork_managed_buffer *buffer,\n                                 size_t offset);\n\n\n#endif /* LIBCORK_DS_MANAGED_BUFFER_H */\n"
  },
  {
    "path": "include/libcork/ds/ring-buffer.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_RING_BUFFER_H\n#define LIBCORK_DS_RING_BUFFER_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n\n\nstruct cork_ring_buffer {\n    /* The elements of the ring buffer */\n    void  **elements;\n    /* The number of elements that can be stored in this ring\n     * buffer. */\n    size_t  allocated_size;\n    /* The actual number of elements currently in the ring buffer. */\n    size_t  size;\n    /* The index of the next element to read from the buffer */\n    size_t  read_index;\n    /* The index of the next element to write into the buffer */\n    size_t  write_index;\n};\n\n\nCORK_API int\ncork_ring_buffer_init(struct cork_ring_buffer *buf, size_t size);\n\nCORK_API struct cork_ring_buffer *\ncork_ring_buffer_new(size_t size);\n\nCORK_API void\ncork_ring_buffer_done(struct cork_ring_buffer *buf);\n\nCORK_API void\ncork_ring_buffer_free(struct cork_ring_buffer *buf);\n\n\n#define cork_ring_buffer_is_empty(buf) ((buf)->size == 0)\n#define cork_ring_buffer_is_full(buf) ((buf)->size == (buf)->allocated_size)\n\n\nCORK_API int\ncork_ring_buffer_add(struct cork_ring_buffer *buf, void *element);\n\nCORK_API void *\ncork_ring_buffer_pop(struct cork_ring_buffer *buf);\n\nCORK_API void *\ncork_ring_buffer_peek(struct cork_ring_buffer *buf);\n\n\n#endif /* LIBCORK_DS_RING_BUFFER_H */\n"
  },
  {
    "path": "include/libcork/ds/slice.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_SLICE_H\n#define LIBCORK_DS_SLICE_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * Error handling\n */\n\n/* hash of \"libcork/ds/slice.h\" */\n#define CORK_SLICE_ERROR  0x960ca750\n\nenum cork_slice_error {\n    /* Trying to slice a nonexistent subset of a buffer */\n    CORK_SLICE_INVALID_SLICE\n};\n\n\n/*-----------------------------------------------------------------------\n * Slices\n */\n\nstruct cork_slice;\n\nstruct cork_slice_iface {\n    /* Free the slice.  Can be NULL if you don't need to free any\n     * underlying buffer. */\n    void\n    (*free)(struct cork_slice *self);\n\n    /* Create a copy of a slice.  You can assume that offset and length\n     * refer to a valid subset of the buffer. */\n    int\n    (*copy)(struct cork_slice *dest, const struct cork_slice *self,\n            size_t offset, size_t length);\n\n    /* Create a “light” copy of a slice.  A light copy is not allowed to exist\n     * longer than the slice that it was copied from, which can sometimes let\n     * you perform less work to produce the copy.  You can assume that offset\n     * and length refer to a valid subset of the buffer. */\n    int\n    (*light_copy)(struct cork_slice *dest, const struct cork_slice *self,\n                  size_t offset, size_t length);\n\n    /* Update the current slice to point at a different subset.  You can\n     * assume that offset and length refer to a valid subset of the\n     * buffer.  Can be NULL if you don't need to do anything special to\n     * the underlying buffer; in this case, we'll update the slice's buf\n     * and size fields for you. */\n    int\n    (*slice)(struct cork_slice *self, size_t offset, size_t length);\n};\n\n\nstruct cork_slice {\n    /* The beginning of the sliced portion of the buffer. */\n    const void  *buf;\n    /* The length of the sliced portion of the buffer. */\n    size_t  size;\n    /* The slice implementation of the underlying buffer. */\n    struct cork_slice_iface  *iface;\n    /* An opaque pointer used by the slice implementation to refer to\n     * the underlying buffer. */\n    void  *user_data;\n};\n\n\nCORK_API void\ncork_slice_clear(struct cork_slice *slice);\n\nCORK_INLINE\nbool\ncork_slice_is_empty(const struct cork_slice* slice)\n{\n    return slice->buf == NULL;\n}\n\n\nCORK_API int\ncork_slice_copy(struct cork_slice *dest, const struct cork_slice *slice,\n                size_t offset, size_t length);\n\nCORK_INLINE\nint\ncork_slice_copy_fast(struct cork_slice* dest, const struct cork_slice* slice,\n                     size_t offset, size_t length)\n{\n    return slice->iface->copy(dest, slice, offset, length);\n}\n\nCORK_API int\ncork_slice_copy_offset(struct cork_slice *dest, const struct cork_slice *slice,\n                       size_t offset);\n\nCORK_INLINE\nint\ncork_slice_copy_offset_fast(struct cork_slice *dest,\n                            const struct cork_slice *slice, size_t offset)\n{\n    return slice->iface->copy(dest, slice, offset, slice->size - offset);\n}\n\n\nCORK_API int\ncork_slice_light_copy(struct cork_slice *dest, const struct cork_slice *slice,\n                      size_t offset, size_t length);\n\nCORK_INLINE\nint\ncork_slice_light_copy_fast(struct cork_slice *dest,\n                           const struct cork_slice *slice, size_t offset,\n                           size_t length)\n{\n    return slice->iface->light_copy(dest, slice, offset, length);\n}\n\nCORK_API int\ncork_slice_light_copy_offset(struct cork_slice *dest,\n                             const struct cork_slice *slice, size_t offset);\n\nCORK_INLINE\nint\ncork_slice_light_copy_offset_fast(struct cork_slice *dest,\n                                  const struct cork_slice *slice,\n                                  size_t offset)\n{\n    return slice->iface->light_copy(dest, slice, offset, slice->size - offset);\n}\n\n\nCORK_API int\ncork_slice_slice(struct cork_slice *slice, size_t offset, size_t length);\n\nCORK_INLINE\nint\ncork_slice_slice_fast(struct cork_slice *slice, size_t offset, size_t length)\n{\n    if (CORK_LIKELY(slice->iface->slice == NULL)) {\n        slice->buf += offset;\n        slice->size = length;\n        return 0;\n    } else {\n        return slice->iface->slice(slice, offset, length);\n    }\n}\n\nCORK_API int\ncork_slice_slice_offset(struct cork_slice *slice, size_t offset);\n\nCORK_INLINE\nint\ncork_slice_slice_offset_fast(struct cork_slice *slice, size_t offset)\n{\n    if (CORK_LIKELY(slice->iface->slice == NULL)) {\n        slice->buf += offset;\n        slice->size -= offset;\n        return 0;\n    } else {\n        return slice->iface->slice(slice, offset, slice->size - offset);\n    }\n}\n\nCORK_API const void*\ncork_slice_advance_checked(struct cork_slice* slice, size_t offset);\n\nCORK_INLINE\nconst void*\ncork_slice_advance(struct cork_slice* slice, size_t offset)\n{\n    if (CORK_LIKELY(slice->iface->slice == NULL)) {\n        const void* buf = slice->buf;\n        slice->buf += offset;\n        slice->size -= offset;\n        return buf;\n    } else {\n        const void* buf = slice->buf;\n        int rc = slice->iface->slice(slice, offset, slice->size - offset);\n        if (CORK_UNLIKELY(rc != 0)) {\n            return NULL;\n        }\n        return buf;\n    }\n}\n\n\nCORK_API void\ncork_slice_finish(struct cork_slice *slice);\n\nCORK_API bool\ncork_slice_equal(const struct cork_slice *slice1,\n                 const struct cork_slice *slice2);\n\nCORK_API void\ncork_slice_init_static(struct cork_slice *dest, const void *buf, size_t size);\n\nCORK_API void\ncork_slice_init_copy_once(struct cork_slice *dest, const void *buf,\n                          size_t size);\n\n\n#endif /* LIBCORK_DS_SLICE_H */\n"
  },
  {
    "path": "include/libcork/ds/stream.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_STREAM_H\n#define LIBCORK_DS_STREAM_H\n\n#include <stdio.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/types.h>\n\n\nstruct cork_stream_consumer {\n    int\n    (*data)(struct cork_stream_consumer *consumer,\n            const void *buf, size_t size, bool is_first_chunk);\n\n    int\n    (*eof)(struct cork_stream_consumer *consumer);\n\n    void\n    (*free)(struct cork_stream_consumer *consumer);\n};\n\n\nCORK_INLINE\nint\ncork_stream_consumer_data(struct cork_stream_consumer* consumer,\n                          const void *buf, size_t size, bool is_first_chunk)\n{\n    return consumer->data(consumer, buf, size, is_first_chunk);\n}\n\nCORK_INLINE\nint\ncork_stream_consumer_eof(struct cork_stream_consumer *consumer)\n{\n    return consumer->eof(consumer);\n}\n\nCORK_INLINE\nvoid\ncork_stream_consumer_free(struct cork_stream_consumer *consumer)\n{\n    consumer->free(consumer);\n}\n\n\nCORK_API int\ncork_consume_fd(struct cork_stream_consumer *consumer, int fd);\n\nCORK_API int\ncork_consume_file(struct cork_stream_consumer *consumer, FILE *fp);\n\nCORK_API int\ncork_consume_file_from_path(struct cork_stream_consumer *consumer,\n                            const char *path, int flags);\n\n\nCORK_API struct cork_stream_consumer *\ncork_fd_consumer_new(int fd);\n\nCORK_API struct cork_stream_consumer *\ncork_file_consumer_new(FILE *fp);\n\nCORK_API struct cork_stream_consumer *\ncork_file_from_path_consumer_new(const char *path, int flags);\n\n\n#endif /* LIBCORK_DS_STREAM_H */\n"
  },
  {
    "path": "include/libcork/ds.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_DS_H\n#define LIBCORK_DS_H\n\n/*** include all of the parts ***/\n\n#include <libcork/ds/array.h>\n#include <libcork/ds/bitset.h>\n#include <libcork/ds/buffer.h>\n#include <libcork/ds/dllist.h>\n#include <libcork/ds/hash-table.h>\n#include <libcork/ds/managed-buffer.h>\n#include <libcork/ds/ring-buffer.h>\n#include <libcork/ds/slice.h>\n#include <libcork/ds/stream.h>\n\n#endif /* LIBCORK_DS_H */\n"
  },
  {
    "path": "include/libcork/helpers/errors.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_HELPERS_ERRORS_H\n#define LIBCORK_HELPERS_ERRORS_H\n\n\n/* This header is *not* automatically included when you include\n * libcork/core.h, since we define some macros that don't include a\n * cork_ or CORK_ prefix.  Don't want to pollute your namespace unless\n * you ask for it! */\n\n\n#include <libcork/core/allocator.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/error.h>\n\n\n#if !defined(CORK_PRINT_ERRORS)\n#define CORK_PRINT_ERRORS 0\n#endif\n\n#if !defined(CORK_PRINT_ERROR)\n#if CORK_PRINT_ERRORS\n#include <stdio.h>\n#define CORK_PRINT_ERROR_(func, file, line) \\\n    fprintf(stderr, \"---\\nError in %s (%s:%u)\\n  %s\\n\", \\\n            (func), (file), (unsigned int) (line), \\\n            cork_error_message());\n#define CORK_PRINT_ERROR()  CORK_PRINT_ERROR_(__func__, __FILE__, __LINE__)\n#else\n#define CORK_PRINT_ERROR()  /* do nothing */\n#endif\n#endif\n\n\n/* A bunch of macros for calling a function that returns an error.  If\n * an error occurs, it will automatically be propagated out as the\n * result of your own function.  With these macros, you won't have a\n * check to check or modify the error condition; it's returned as-is.\n *\n *   XZ_check\n *\n * where:\n *\n *   X = what happens if an error occurs\n *       \"e\" = jump to the \"error\" label\n *       \"rY\" = return a default error result (Y defined below)\n *       \"x\" = return an error result that you specify\n *\n *   Y = your return type\n *       \"i\" = int\n *       \"p\" = some pointer type\n *\n *   Z = the return type of the function you're calling\n *       \"e\" = use cork_error_occurred() to check\n *       \"i\" = int\n *       \"p\" = some pointer type\n *\n * In all cases, we assume that your function has a cork_error parameter\n * called \"err\".\n */\n\n\n/* jump to \"error\" label */\n\n#define ee_check(call) \\\n    do { \\\n        (call); \\\n        if (CORK_UNLIKELY(cork_error_occurred())) { \\\n            CORK_PRINT_ERROR(); \\\n            goto error; \\\n        } \\\n    } while (0)\n\n#define ei_check(call) \\\n    do { \\\n        int  __rc = (call); \\\n        if (CORK_UNLIKELY(__rc != 0)) { \\\n            CORK_PRINT_ERROR(); \\\n            goto error; \\\n        } \\\n    } while (0)\n\n#define ep_check(call) \\\n    do { \\\n        const void  *__result = (call); \\\n        if (CORK_UNLIKELY(__result == NULL)) { \\\n            CORK_PRINT_ERROR(); \\\n            goto error; \\\n        } \\\n    } while (0)\n\n\n/* return specific error code */\n\n#define xe_check(result, call) \\\n    do { \\\n        (call); \\\n        if (CORK_UNLIKELY(cork_error_occurred())) { \\\n            CORK_PRINT_ERROR(); \\\n            return result; \\\n        } \\\n    } while (0)\n\n#define xi_check(result, call) \\\n    do { \\\n        int  __rc = (call); \\\n        if (CORK_UNLIKELY(__rc != 0)) { \\\n            CORK_PRINT_ERROR(); \\\n            return result; \\\n        } \\\n    } while (0)\n\n#define xp_check(result, call) \\\n    do { \\\n        const void  *__result = (call); \\\n        if (CORK_UNLIKELY(__result == NULL)) { \\\n            CORK_PRINT_ERROR(); \\\n            return result; \\\n        } \\\n    } while (0)\n\n\n/* return default error code */\n\n#define rie_check(call)  xe_check(-1, call)\n#define rii_check(call)  xi_check(__rc, call)\n#define rip_check(call)  xp_check(-1, call)\n#define rpe_check(call)  xe_check(NULL, call)\n#define rpi_check(call)  xi_check(NULL, call)\n#define rpp_check(call)  xp_check(NULL, call)\n\n\n#endif /* LIBCORK_HELPERS_ERRORS_H */\n"
  },
  {
    "path": "include/libcork/helpers/gc.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_HELPERS_REFCOUNT_H\n#define LIBCORK_HELPERS_REFCOUNT_H\n\n\n#include <libcork/core/gc.h>\n#include <libcork/core/types.h>\n\n\n#define _free_(name) \\\nstatic void \\\nname##__free(void *obj)\n\n\n#define _recurse_(name) \\\nstatic void \\\nname##__recurse(struct cork_gc *gc, void *obj, \\\n                cork_gc_recurser recurse, void *ud)\n\n\n#define _gc_(name) \\\nstatic struct cork_gc_obj_iface  name##__gc = { \\\n    name##__free, name##__recurse \\\n};\n\n#define _gc_no_free_(name) \\\nstatic struct cork_gc_obj_iface  name##__gc = { \\\n    NULL, name##__recurse \\\n};\n\n#define _gc_no_recurse_(name) \\\nstatic struct cork_gc_obj_iface  name##__gc = { \\\n    name##__free, NULL \\\n};\n\n#define _gc_leaf_(name) \\\nstatic struct cork_gc_obj_iface  name##__gc = { \\\n    NULL, NULL \\\n};\n\n\n#endif /* LIBCORK_HELPERS_REFCOUNT_H */\n"
  },
  {
    "path": "include/libcork/helpers/posix.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_HELPERS_POSIX_H\n#define LIBCORK_HELPERS_POSIX_H\n\n/* This header is *not* automatically included when you include\n * libcork/core.h, since we define some macros that don't include a\n * cork_ or CORK_ prefix.  Don't want to pollute your namespace unless\n * you ask for it! */\n\n#include <errno.h>\n\n#include <libcork/core/allocator.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/error.h>\n\n\n#if !defined(CORK_PRINT_ERRORS)\n#define CORK_PRINT_ERRORS 0\n#endif\n\n#if !defined(CORK_PRINT_ERROR)\n#if CORK_PRINT_ERRORS\n#include <stdio.h>\n#define CORK_PRINT_ERROR_(func, file, line) \\\n    fprintf(stderr, \"---\\nError in %s (%s:%u)\\n  %s\\n\", \\\n            (func), (file), (unsigned int) (line), \\\n            cork_error_message());\n#define CORK_PRINT_ERROR()  CORK_PRINT_ERROR_(__func__, __FILE__, __LINE__)\n#else\n#define CORK_PRINT_ERROR()  /* do nothing */\n#endif\n#endif\n\n\n#define xi_check_posix(call, on_error) \\\n    do { \\\n        while (true) { \\\n            if ((call) == -1) { \\\n                if (errno == EINTR) { \\\n                    continue; \\\n                } else { \\\n                    cork_system_error_set(); \\\n                    CORK_PRINT_ERROR(); \\\n                    on_error; \\\n                } \\\n            } else { \\\n                break; \\\n            } \\\n        } \\\n    } while (0)\n\n#define xp_check_posix(call, on_error) \\\n    do { \\\n        while (true) { \\\n            if ((call) == NULL) { \\\n                if (errno == EINTR) { \\\n                    continue; \\\n                } else { \\\n                    cork_system_error_set(); \\\n                    CORK_PRINT_ERROR(); \\\n                    on_error; \\\n                } \\\n            } else { \\\n                break; \\\n            } \\\n        } \\\n    } while (0)\n\n\n#define ei_check_posix(call)  xi_check_posix(call, goto error)\n#define rii_check_posix(call) xi_check_posix(call, return -1)\n#define rpi_check_posix(call) xi_check_posix(call, return NULL)\n\n#define ep_check_posix(call)  xp_check_posix(call, goto error)\n#define rip_check_posix(call) xp_check_posix(call, return -1)\n#define rpp_check_posix(call) xp_check_posix(call, return NULL)\n\n\n#endif /* LIBCORK_HELPERS_POSIX_H */\n"
  },
  {
    "path": "include/libcork/os/files.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_FILES_H\n#define LIBCORK_CORE_FILES_H\n\n#include <libcork/core/api.h>\n#include <libcork/core/types.h>\n\n\n/*-----------------------------------------------------------------------\n * Paths\n */\n\nstruct cork_path;\n\n/* path can be relative or absolute */\nCORK_API struct cork_path *\ncork_path_new(const char *path);\n\nCORK_API struct cork_path *\ncork_path_clone(const struct cork_path *other);\n\nCORK_API void\ncork_path_free(struct cork_path *path);\n\n\nCORK_API void\ncork_path_set(struct cork_path *path, const char *content);\n\nCORK_API const char *\ncork_path_get(const struct cork_path *path);\n\n\nCORK_API int\ncork_path_set_cwd(struct cork_path *path);\n\nCORK_API struct cork_path *\ncork_path_cwd(void);\n\n\nCORK_API int\ncork_path_set_absolute(struct cork_path *path);\n\nCORK_API struct cork_path *\ncork_path_absolute(const struct cork_path *other);\n\n\nCORK_API void\ncork_path_append(struct cork_path *path, const char *more);\n\nCORK_API void\ncork_path_append_path(struct cork_path *path, const struct cork_path *more);\n\nCORK_API struct cork_path *\ncork_path_join(const struct cork_path *other, const char *more);\n\nCORK_API struct cork_path *\ncork_path_join_path(const struct cork_path *other,\n                    const struct cork_path *more);\n\n\nCORK_API void\ncork_path_set_basename(struct cork_path *path);\n\nCORK_API struct cork_path *\ncork_path_basename(const struct cork_path *other);\n\n\nCORK_API void\ncork_path_set_dirname(struct cork_path *path);\n\nCORK_API struct cork_path *\ncork_path_dirname(const struct cork_path *other);\n\n\n/*-----------------------------------------------------------------------\n * Lists of paths\n */\n\nstruct cork_path_list;\n\nCORK_API struct cork_path_list *\ncork_path_list_new_empty(void);\n\n/* list must be a colon-separated list of paths */\nCORK_API struct cork_path_list *\ncork_path_list_new(const char *list);\n\nCORK_API void\ncork_path_list_free(struct cork_path_list *list);\n\nCORK_API const char *\ncork_path_list_to_string(const struct cork_path_list *list);\n\n/* Takes control of path.  path must not already be in the list. */\nCORK_API void\ncork_path_list_add(struct cork_path_list *list, struct cork_path *path);\n\nCORK_API size_t\ncork_path_list_size(const struct cork_path_list *list);\n\n/* The list still owns path; you must not free it or modify it. */\nCORK_API const struct cork_path *\ncork_path_list_get(const struct cork_path_list *list, size_t index);\n\n\n/*-----------------------------------------------------------------------\n * Files\n */\n\n#define CORK_FILE_RECURSIVE   0x0001\n#define CORK_FILE_PERMISSIVE  0x0002\n\ntypedef unsigned int  cork_file_mode;\n\nenum cork_file_type {\n    CORK_FILE_MISSING = 0,\n    CORK_FILE_REGULAR = 1,\n    CORK_FILE_DIRECTORY = 2,\n    CORK_FILE_SYMLINK = 3,\n    CORK_FILE_UNKNOWN = 4\n};\n\nstruct cork_file;\n\nCORK_API struct cork_file *\ncork_file_new(const char *path);\n\n/* Takes control of path */\nCORK_API struct cork_file *\ncork_file_new_from_path(struct cork_path *path);\n\nCORK_API void\ncork_file_free(struct cork_file *file);\n\n/* File owns the result; you should not free it */\nCORK_API const struct cork_path *\ncork_file_path(struct cork_file *file);\n\nCORK_API int\ncork_file_exists(struct cork_file *file, bool *exists);\n\nCORK_API int\ncork_file_type(struct cork_file *file, enum cork_file_type *type);\n\n\ntypedef int\n(*cork_file_directory_iterator)(struct cork_file *child, const char *rel_name,\n                                void *user_data);\n\nCORK_API int\ncork_file_iterate_directory(struct cork_file *file,\n                            cork_file_directory_iterator iterator,\n                            void *user_data);\n\n/* If flags includes CORK_FILE_RECURSIVE, this creates parent directories,\n * if needed.  If flags doesn't include CORK_FILE_PERMISSIVE, then it's an error\n * if the directory already exists. */\nCORK_API int\ncork_file_mkdir(struct cork_file *file, cork_file_mode mode,\n                unsigned int flags);\n\n/* Removes a file or directory.  If file is a directory, and flags contains\n * CORK_FILE_RECURSIVE, then all of the directory's contents are removed, too.\n * Otherwise, the directory must already be empty. */\nCORK_API int\ncork_file_remove(struct cork_file *file, unsigned int flags);\n\n\nCORK_API struct cork_file *\ncork_path_list_find_file(const struct cork_path_list *list,\n                         const char *rel_path);\n\n\n/*-----------------------------------------------------------------------\n * Lists of files\n */\n\nstruct cork_file_list;\n\nCORK_API struct cork_file_list *\ncork_file_list_new_empty(void);\n\nCORK_API struct cork_file_list *\ncork_file_list_new(struct cork_path_list *path_list);\n\nCORK_API void\ncork_file_list_free(struct cork_file_list *list);\n\n/* Takes control of file.  file must not already be in the list. */\nCORK_API void\ncork_file_list_add(struct cork_file_list *list, struct cork_file *file);\n\nCORK_API size_t\ncork_file_list_size(struct cork_file_list *list);\n\n/* The list still owns file; you must not free it.  Editing the file updates the\n * entry in the list. */\nCORK_API struct cork_file *\ncork_file_list_get(struct cork_file_list *list, size_t index);\n\n\nCORK_API struct cork_file_list *\ncork_path_list_find_files(const struct cork_path_list *list,\n                          const char *rel_path);\n\n\n/*-----------------------------------------------------------------------\n * Walking a directory tree\n */\n\n#define CORK_SKIP_DIRECTORY  1\n\nstruct cork_dir_walker {\n    int\n    (*enter_directory)(struct cork_dir_walker *walker, const char *full_path,\n                       const char *rel_path, const char *base_name);\n\n    int\n    (*file)(struct cork_dir_walker *walker, const char *full_path,\n            const char *rel_path, const char *base_name);\n\n    int\n    (*leave_directory)(struct cork_dir_walker *walker, const char *full_path,\n                       const char *rel_path, const char *base_name);\n};\n\n#define cork_dir_walker_enter_directory(w, fp, rp, bn) \\\n    ((w)->enter_directory((w), (fp), (rp), (bn)))\n\n#define cork_dir_walker_file(w, fp, rp, bn) \\\n    ((w)->file((w), (fp), (rp), (bn)))\n\n#define cork_dir_walker_leave_directory(w, fp, rp, bn) \\\n    ((w)->leave_directory((w), (fp), (rp), (bn)))\n\n\nCORK_API int\ncork_walk_directory(const char *path, struct cork_dir_walker *walker);\n\n\n/*-----------------------------------------------------------------------\n * Standard paths and path lists\n */\n\nCORK_API struct cork_path *\ncork_path_home(void);\n\n\nCORK_API struct cork_path_list *\ncork_path_config_paths(void);\n\nCORK_API struct cork_path_list *\ncork_path_data_paths(void);\n\nCORK_API struct cork_path *\ncork_path_user_cache_path(void);\n\nCORK_API struct cork_path *\ncork_path_user_runtime_path(void);\n\n\n#endif /* LIBCORK_CORE_FILES_H */\n"
  },
  {
    "path": "include/libcork/os/process.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_CORE_PROCESS_H\n#define LIBCORK_CORE_PROCESS_H\n\n#include <libcork/core/api.h>\n\n\ntypedef void\n(*cork_cleanup_function)(void);\n\nCORK_API void\ncork_cleanup_at_exit_named(const char *name, int priority,\n                           cork_cleanup_function function);\n\n#define cork_cleanup_at_exit(priority, function) \\\n    cork_cleanup_at_exit_named(#function, priority, function)\n\n\n#endif /* LIBCORK_CORE_PROCESS_H */\n"
  },
  {
    "path": "include/libcork/os/subprocess.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_OS_SUBPROCESS_H\n#define LIBCORK_OS_SUBPROCESS_H\n\n#include <stdarg.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/core/types.h>\n#include <libcork/ds/stream.h>\n#include <libcork/threads/basics.h>\n\n\n/*-----------------------------------------------------------------------\n * Environments\n */\n\nstruct cork_env;\n\nCORK_API struct cork_env *\ncork_env_new(void);\n\nCORK_API struct cork_env *\ncork_env_clone_current(void);\n\nCORK_API void\ncork_env_free(struct cork_env *env);\n\n\nCORK_API void\ncork_env_replace_current(struct cork_env *env);\n\n\n/* For all of the following, if env is NULL, these functions access or update\n * the actual environment of the current process.  Otherwise, they act on the\n * given environment instance. */\n\nCORK_API const char *\ncork_env_get(struct cork_env *env, const char *name);\n\nCORK_API void\ncork_env_add(struct cork_env *env, const char *name, const char *value);\n\nCORK_API void\ncork_env_add_printf(struct cork_env *env, const char *name,\n                    const char *format, ...)\n    CORK_ATTR_PRINTF(3,4);\n\nCORK_API void\ncork_env_add_vprintf(struct cork_env *env, const char *name,\n                     const char *format, va_list args)\n    CORK_ATTR_PRINTF(3,0);\n\nCORK_API void\ncork_env_remove(struct cork_env *env, const char *name);\n\n\n/*-----------------------------------------------------------------------\n * Executing another process\n */\n\nstruct cork_exec;\n\nCORK_API struct cork_exec *\ncork_exec_new(const char *program);\n\nCORK_ATTR_SENTINEL\nCORK_API struct cork_exec *\ncork_exec_new_with_params(const char *program, ...);\n\nCORK_API struct cork_exec *\ncork_exec_new_with_param_array(const char *program, char * const *params);\n\nCORK_API void\ncork_exec_free(struct cork_exec *exec);\n\nCORK_API const char *\ncork_exec_description(struct cork_exec *exec);\n\nCORK_API const char *\ncork_exec_program(struct cork_exec *exec);\n\nCORK_API size_t\ncork_exec_param_count(struct cork_exec *exec);\n\nCORK_API const char *\ncork_exec_param(struct cork_exec *exec, size_t index);\n\nCORK_API void\ncork_exec_add_param(struct cork_exec *exec, const char *param);\n\n/* Can return NULL */\nCORK_API struct cork_env *\ncork_exec_env(struct cork_exec *exec);\n\n/* Takes control of env */\nCORK_API void\ncork_exec_set_env(struct cork_exec *exec, struct cork_env *env);\n\n/* Can return NULL */\nCORK_API const char *\ncork_exec_cwd(struct cork_exec *exec);\n\nCORK_API void\ncork_exec_set_cwd(struct cork_exec *exec, const char *directory);\n\nCORK_API int\ncork_exec_run(struct cork_exec *exec);\n\n\n/*-----------------------------------------------------------------------\n * Subprocesses\n */\n\nstruct cork_subprocess;\n\n/* If env is NULL, we use the environment variables of the calling process. */\n\n/* Takes control of body */\nCORK_API struct cork_subprocess *\ncork_subprocess_new(void *user_data, cork_free_f free_user_data,\n                    cork_run_f run,\n                    struct cork_stream_consumer *stdout_consumer,\n                    struct cork_stream_consumer *stderr_consumer,\n                    int *exit_code);\n\n/* Takes control of exec */\nCORK_API struct cork_subprocess *\ncork_subprocess_new_exec(struct cork_exec *exec,\n                         struct cork_stream_consumer *stdout_consumer,\n                         struct cork_stream_consumer *stderr_consumer,\n                         int *exit_code);\n\nCORK_API void\ncork_subprocess_free(struct cork_subprocess *sub);\n\nCORK_API struct cork_stream_consumer *\ncork_subprocess_stdin(struct cork_subprocess *sub);\n\nCORK_API int\ncork_subprocess_start(struct cork_subprocess *sub);\n\nCORK_API bool\ncork_subprocess_is_finished(struct cork_subprocess *sub);\n\nCORK_API int\ncork_subprocess_abort(struct cork_subprocess *sub);\n\nCORK_API bool\ncork_subprocess_drain(struct cork_subprocess *sub);\n\nCORK_API int\ncork_subprocess_wait(struct cork_subprocess *sub);\n\n\n/*-----------------------------------------------------------------------\n * Groups of subprocesses\n */\n\nstruct cork_subprocess_group;\n\nCORK_API struct cork_subprocess_group *\ncork_subprocess_group_new(void);\n\nCORK_API void\ncork_subprocess_group_free(struct cork_subprocess_group *group);\n\n/* Takes control of sub */\nCORK_API void\ncork_subprocess_group_add(struct cork_subprocess_group *group,\n                          struct cork_subprocess *sub);\n\nCORK_API int\ncork_subprocess_group_start(struct cork_subprocess_group *group);\n\nCORK_API bool\ncork_subprocess_group_is_finished(struct cork_subprocess_group *group);\n\nCORK_API int\ncork_subprocess_group_abort(struct cork_subprocess_group *group);\n\nCORK_API bool\ncork_subprocess_group_drain(struct cork_subprocess_group *group);\n\nCORK_API int\ncork_subprocess_group_wait(struct cork_subprocess_group *group);\n\n\n#endif /* LIBCORK_OS_SUBPROCESS_H */\n"
  },
  {
    "path": "include/libcork/os.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_OS_H\n#define LIBCORK_OS_H\n\n/*** include all of the parts ***/\n\n#include <libcork/os/files.h>\n#include <libcork/os/process.h>\n#include <libcork/os/subprocess.h>\n\n#endif /* LIBCORK_OS_H */\n"
  },
  {
    "path": "include/libcork/threads/atomics.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_THREADS_ATOMICS_H\n#define LIBCORK_THREADS_ATOMICS_H\n\n#include <libcork/config.h>\n#include <libcork/core/types.h>\n\n/*-----------------------------------------------------------------------\n * GCC intrinsics\n */\n\n/* Ideally we can use GCC's intrinsics to define everything */\n#if defined(CORK_CONFIG_HAVE_GCC_ATOMICS)\n\n#define cork_int_atomic_add        __sync_add_and_fetch\n#define cork_uint_atomic_add       __sync_add_and_fetch\n#define cork_size_atomic_add       __sync_add_and_fetch\n#define cork_int_atomic_pre_add    __sync_fetch_and_add\n#define cork_uint_atomic_pre_add   __sync_fetch_and_add\n#define cork_size_atomic_pre_add   __sync_fetch_and_add\n#define cork_int_atomic_sub        __sync_sub_and_fetch\n#define cork_uint_atomic_sub       __sync_sub_and_fetch\n#define cork_size_atomic_sub       __sync_sub_and_fetch\n#define cork_int_atomic_pre_sub    __sync_fetch_and_sub\n#define cork_uint_atomic_pre_sub   __sync_fetch_and_sub\n#define cork_size_atomic_pre_sub   __sync_fetch_and_sub\n#define cork_int_cas               __sync_val_compare_and_swap\n#define cork_uint_cas              __sync_val_compare_and_swap\n#define cork_size_cas              __sync_val_compare_and_swap\n#define cork_ptr_cas               __sync_val_compare_and_swap\n\n\n/*-----------------------------------------------------------------------\n * End of atomic implementations\n */\n#else\n#error \"No atomics implementation!\"\n#endif\n\n\n#endif /* LIBCORK_THREADS_ATOMICS_H */\n"
  },
  {
    "path": "include/libcork/threads/basics.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_THREADS_BASICS_H\n#define LIBCORK_THREADS_BASICS_H\n\n#include <assert.h>\n\n#include <libcork/core/api.h>\n#include <libcork/core/attributes.h>\n#include <libcork/core/callbacks.h>\n#include <libcork/threads/atomics.h>\n\n\n/*-----------------------------------------------------------------------\n * Thread IDs\n */\n\ntypedef unsigned int  cork_thread_id;\n\n#define CORK_THREAD_NONE  ((cork_thread_id) 0)\n\n/* Returns a valid ID for any thread — even the main thread and threads that\n * aren't created by libcork. */\nCORK_API cork_thread_id\ncork_current_thread_get_id(void);\n\n\n/*-----------------------------------------------------------------------\n * Threads\n */\n\nstruct cork_thread;\n\n/* Returns NULL for the main thread, and for any thread not created via\n * cork_thread_new/cork_thread_start. */\nCORK_API struct cork_thread *\ncork_current_thread_get(void);\n\nCORK_API struct cork_thread *\ncork_thread_new(const char *name,\n                void *user_data, cork_free_f free_user_data,\n                cork_run_f run);\n\n/* Thread must not have been started yet. */\nCORK_API void\ncork_thread_free(struct cork_thread *thread);\n\nCORK_API const char *\ncork_thread_get_name(struct cork_thread *thread);\n\nCORK_API cork_thread_id\ncork_thread_get_id(struct cork_thread *thread);\n\n/* Can only be called once per thread.  Thread will automatically be freed when\n * its done. */\nCORK_API int\ncork_thread_start(struct cork_thread *thread);\n\n/* Can only be called once per thread; must be called after cork_thread_start. */\nCORK_API int\ncork_thread_join(struct cork_thread *thread);\n\n\n/*-----------------------------------------------------------------------\n * Executing something once\n */\n\n#if CORK_CONFIG_HAVE_GCC_ASM && (CORK_CONFIG_ARCH_X86 || CORK_CONFIG_ARCH_X64)\n#define cork_pause() \\\n    do { \\\n        __asm__ __volatile__ (\"pause\"); \\\n    } while (0)\n#else\n#define cork_pause()  do { /* do nothing */ } while (0)\n#endif\n\n\n#define cork_once_barrier(name) \\\n    static struct { \\\n        volatile int  barrier; \\\n        cork_thread_id  initializing_thread; \\\n    } name##__once;\n\n#define cork_once(name, call) \\\n    do { \\\n        if (CORK_LIKELY(name##__once.barrier == 2)) { \\\n            /* already initialized */ \\\n        } else { \\\n            /* Try to claim the ability to perform the initialization */ \\\n            int  prior_state = cork_int_cas(&name##__once.barrier, 0, 1); \\\n            if (CORK_LIKELY(prior_state == 0)) { \\\n                CORK_ATTR_UNUSED int  result; \\\n                /* we get to initialize */ \\\n                call; \\\n                result = cork_int_cas(&name##__once.barrier, 1, 2); \\\n                assert(result == 1); \\\n            } else { \\\n                /* someone else is initializing, spin/wait until done */ \\\n                while (name##__once.barrier != 2) { cork_pause(); } \\\n            } \\\n        } \\\n    } while (0)\n\n#define cork_once_recursive(name, call) \\\n    do { \\\n        if (CORK_LIKELY(name##__once.barrier == 2)) { \\\n            /* already initialized */ \\\n        } else { \\\n            /* Try to claim the ability to perform the initialization */ \\\n            int  prior_state = cork_int_cas(&name##__once.barrier, 0, 1); \\\n            if (CORK_LIKELY(prior_state == 0)) { \\\n                CORK_ATTR_UNUSED int  result; \\\n                /* we get to initialize */ \\\n                name##__once.initializing_thread = \\\n                    cork_current_thread_get_id(); \\\n                call; \\\n                result = cork_int_cas(&name##__once.barrier, 1, 2); \\\n                assert(result == 1); \\\n            } else { \\\n                /* someone else is initializing, is it us? */ \\\n                if (name##__once.initializing_thread == \\\n                    cork_current_thread_get_id()) { \\\n                    /* yep, fall through to let our recursion continue */ \\\n                } else { \\\n                    /* nope; wait for the initialization to finish */ \\\n                    while (name##__once.barrier != 2) { cork_pause(); } \\\n                } \\\n            } \\\n        } \\\n    } while (0)\n\n\n/*-----------------------------------------------------------------------\n * Thread-local storage\n */\n\n/* Prefer, in order:\n *\n * 1) __thread storage class\n * 2) pthread_key_t\n */\n\n#if CORK_CONFIG_HAVE_THREAD_STORAGE_CLASS\n#define cork_tls(TYPE, NAME) \\\nstatic __thread TYPE  NAME##__tls; \\\n\\\nstatic TYPE * \\\nNAME##_get(void) \\\n{ \\\n    return &NAME##__tls; \\\n}\n\n#define cork_tls_with_alloc(TYPE, NAME, allocate, deallocate) \\\n    cork_tls(TYPE, NAME)\n\n#elif CORK_HAVE_PTHREADS\n#include <stdlib.h>\n#include <pthread.h>\n\n#include <libcork/core/allocator.h>\n\n#define cork_tls_with_alloc(TYPE, NAME, allocate, deallocate) \\\nstatic pthread_key_t  NAME##__tls_key; \\\ncork_once_barrier(NAME##__tls_barrier); \\\n\\\nstatic void \\\nNAME##__tls_destroy(void *self) \\\n{ \\\n    deallocate(self); \\\n} \\\n\\\nstatic void \\\nNAME##__create_key(void) \\\n{ \\\n    CORK_ATTR_UNUSED int  rc; \\\n    rc = pthread_key_create(&NAME##__tls_key, &NAME##__tls_destroy); \\\n    assert(rc == 0); \\\n} \\\n\\\nstatic TYPE * \\\nNAME##_get(void) \\\n{ \\\n    TYPE  *self; \\\n    cork_once(NAME##__tls_barrier, NAME##__create_key()); \\\n    self = pthread_getspecific(NAME##__tls_key); \\\n    if (CORK_UNLIKELY(self == NULL)) { \\\n        self = allocate(); \\\n        pthread_setspecific(NAME##__tls_key, self); \\\n    } \\\n    return self; \\\n}\n\n#define cork_tls(TYPE, NAME) \\\n\\\nstatic TYPE * \\\nNAME##__tls_allocate(void) \\\n{ \\\n    return cork_calloc(1, sizeof(TYPE)); \\\n} \\\n\\\nstatic void \\\nNAME##__tls_deallocate(void *vself) \\\n{ \\\n    cork_cfree(vself, 1, sizeof(TYPE)); \\\n} \\\n\\\ncork_tls_with_alloc(TYPE, NAME, NAME##__tls_allocate, NAME##__tls_deallocate);\n\n#else\n#error \"No thread-local storage implementation!\"\n#endif\n\n\n#endif /* LIBCORK_THREADS_BASICS_H */\n"
  },
  {
    "path": "include/libcork/threads.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef LIBCORK_THREADS_H\n#define LIBCORK_THREADS_H\n\n/*** include all of the parts ***/\n\n#include <libcork/threads/atomics.h>\n#include <libcork/threads/basics.h>\n\n#endif /* LIBCORK_THREADS_H */\n"
  },
  {
    "path": "m4/ax_pthread.m4",
    "content": "# ===========================================================================\n#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])\n#\n# DESCRIPTION\n#\n#   This macro figures out how to build C programs using POSIX threads. It\n#   sets the PTHREAD_LIBS output variable to the threads library and linker\n#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler\n#   flags that are needed. (The user can also force certain compiler\n#   flags/libs to be tested by setting these environment variables.)\n#\n#   Also sets PTHREAD_CC to any special C compiler that is needed for\n#   multi-threaded programs (defaults to the value of CC otherwise). (This\n#   is necessary on AIX to use the special cc_r compiler alias.)\n#\n#   NOTE: You are assumed to not only compile your program with these flags,\n#   but also to link with them as well. For example, you might link with\n#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS\n#\n#   If you are only building threaded programs, you may wish to use these\n#   variables in your default LIBS, CFLAGS, and CC:\n#\n#     LIBS=\"$PTHREAD_LIBS $LIBS\"\n#     CFLAGS=\"$CFLAGS $PTHREAD_CFLAGS\"\n#     CC=\"$PTHREAD_CC\"\n#\n#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant\n#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to\n#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).\n#\n#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the\n#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with\n#   PTHREAD_CFLAGS.\n#\n#   ACTION-IF-FOUND is a list of shell commands to run if a threads library\n#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it\n#   is not found. If ACTION-IF-FOUND is not specified, the default action\n#   will define HAVE_PTHREAD.\n#\n#   Please let the authors know if this macro fails on any platform, or if\n#   you have any other suggestions or comments. This macro was based on work\n#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help\n#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by\n#   Alejandro Forero Cuervo to the autoconf macro repository. We are also\n#   grateful for the helpful feedback of numerous users.\n#\n#   Updated for Autoconf 2.68 by Daniel Richard G.\n#\n# LICENSE\n#\n#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>\n#   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>\n#\n#   This program is free software: you can redistribute it and/or modify it\n#   under the terms of the GNU General Public License as published by the\n#   Free Software Foundation, either version 3 of the License, or (at your\n#   option) any later version.\n#\n#   This program is distributed in the hope that it will be useful, but\n#   WITHOUT ANY WARRANTY; without even the implied warranty of\n#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General\n#   Public License for more details.\n#\n#   You should have received a copy of the GNU General Public License along\n#   with this program. If not, see <https://www.gnu.org/licenses/>.\n#\n#   As a special exception, the respective Autoconf Macro's copyright owner\n#   gives unlimited permission to copy, distribute and modify the configure\n#   scripts that are the output of Autoconf when processing the Macro. You\n#   need not follow the terms of the GNU General Public License when using\n#   or distributing such scripts, even though portions of the text of the\n#   Macro appear in them. The GNU General Public License (GPL) does govern\n#   all other use of the material that constitutes the Autoconf Macro.\n#\n#   This special exception to the GPL applies to versions of the Autoconf\n#   Macro released by the Autoconf Archive. When you make and distribute a\n#   modified version of the Autoconf Macro, you may extend this special\n#   exception to the GPL to apply to your modified version as well.\n\n#serial 24\n\nAU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])\nAC_DEFUN([AX_PTHREAD], [\nAC_REQUIRE([AC_CANONICAL_HOST])\nAC_REQUIRE([AC_PROG_CC])\nAC_REQUIRE([AC_PROG_SED])\nAC_LANG_PUSH([C])\nax_pthread_ok=no\n\n# We used to check for pthread.h first, but this fails if pthread.h\n# requires special compiler flags (e.g. on Tru64 or Sequent).\n# It gets checked for in the link test anyway.\n\n# First of all, check if the user has set any of the PTHREAD_LIBS,\n# etcetera environment variables, and if threads linking works using\n# them:\nif test \"x$PTHREAD_CFLAGS$PTHREAD_LIBS\" != \"x\"; then\n        ax_pthread_save_CC=\"$CC\"\n        ax_pthread_save_CFLAGS=\"$CFLAGS\"\n        ax_pthread_save_LIBS=\"$LIBS\"\n        AS_IF([test \"x$PTHREAD_CC\" != \"x\"], [CC=\"$PTHREAD_CC\"])\n        CFLAGS=\"$CFLAGS $PTHREAD_CFLAGS\"\n        LIBS=\"$PTHREAD_LIBS $LIBS\"\n        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])\n        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])\n        AC_MSG_RESULT([$ax_pthread_ok])\n        if test \"x$ax_pthread_ok\" = \"xno\"; then\n                PTHREAD_LIBS=\"\"\n                PTHREAD_CFLAGS=\"\"\n        fi\n        CC=\"$ax_pthread_save_CC\"\n        CFLAGS=\"$ax_pthread_save_CFLAGS\"\n        LIBS=\"$ax_pthread_save_LIBS\"\nfi\n\n# We must check for the threads library under a number of different\n# names; the ordering is very important because some systems\n# (e.g. DEC) have both -lpthread and -lpthreads, where one of the\n# libraries is broken (non-POSIX).\n\n# Create a list of thread flags to try.  Items starting with a \"-\" are\n# C compiler flags, and other items are library names, except for \"none\"\n# which indicates that we try without any flags at all, and \"pthread-config\"\n# which is a program returning the flags for the Pth emulation library.\n\nax_pthread_flags=\"pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config\"\n\n# The ordering *is* (sometimes) important.  Some notes on the\n# individual items follow:\n\n# pthreads: AIX (must check this before -lpthread)\n# none: in case threads are in libc; should be tried before -Kthread and\n#       other compiler flags to prevent continual compiler warnings\n# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)\n# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64\n#           (Note: HP C rejects this with \"bad form for `-t' option\")\n# -pthreads: Solaris/gcc (Note: HP C also rejects)\n# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it\n#      doesn't hurt to check since this sometimes defines pthreads and\n#      -D_REENTRANT too), HP C (must be checked before -lpthread, which\n#      is present but should not be used directly; and before -mthreads,\n#      because the compiler interprets this as \"-mt\" + \"-hreads\")\n# -mthreads: Mingw32/gcc, Lynx/gcc\n# pthread: Linux, etcetera\n# --thread-safe: KAI C++\n# pthread-config: use pthread-config program (for GNU Pth library)\n\ncase $host_os in\n\n        freebsd*)\n\n        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)\n        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)\n\n        ax_pthread_flags=\"-kthread lthread $ax_pthread_flags\"\n        ;;\n\n        hpux*)\n\n        # From the cc(1) man page: \"[-mt] Sets various -D flags to enable\n        # multi-threading and also sets -lpthread.\"\n\n        ax_pthread_flags=\"-mt -pthread pthread $ax_pthread_flags\"\n        ;;\n\n        openedition*)\n\n        # IBM z/OS requires a feature-test macro to be defined in order to\n        # enable POSIX threads at all, so give the user a hint if this is\n        # not set. (We don't define these ourselves, as they can affect\n        # other portions of the system API in unpredictable ways.)\n\n        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],\n            [\n#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)\n             AX_PTHREAD_ZOS_MISSING\n#            endif\n            ],\n            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])\n        ;;\n\n        solaris*)\n\n        # On Solaris (at least, for some versions), libc contains stubbed\n        # (non-functional) versions of the pthreads routines, so link-based\n        # tests will erroneously succeed. (N.B.: The stubs are missing\n        # pthread_cleanup_push, or rather a function called by this macro,\n        # so we could check for that, but who knows whether they'll stub\n        # that too in a future libc.)  So we'll check first for the\n        # standard Solaris way of linking pthreads (-mt -lpthread).\n\n        ax_pthread_flags=\"-mt,pthread pthread $ax_pthread_flags\"\n        ;;\nesac\n\n# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)\n\nAS_IF([test \"x$GCC\" = \"xyes\"],\n      [ax_pthread_flags=\"-pthread -pthreads $ax_pthread_flags\"])\n\n# The presence of a feature test macro requesting re-entrant function\n# definitions is, on some systems, a strong hint that pthreads support is\n# correctly enabled\n\ncase $host_os in\n        darwin* | hpux* | linux* | osf* | solaris*)\n        ax_pthread_check_macro=\"_REENTRANT\"\n        ;;\n\n        aix*)\n        ax_pthread_check_macro=\"_THREAD_SAFE\"\n        ;;\n\n        *)\n        ax_pthread_check_macro=\"--\"\n        ;;\nesac\nAS_IF([test \"x$ax_pthread_check_macro\" = \"x--\"],\n      [ax_pthread_check_cond=0],\n      [ax_pthread_check_cond=\"!defined($ax_pthread_check_macro)\"])\n\n# Are we compiling with Clang?\n\nAC_CACHE_CHECK([whether $CC is Clang],\n    [ax_cv_PTHREAD_CLANG],\n    [ax_cv_PTHREAD_CLANG=no\n     # Note that Autoconf sets GCC=yes for Clang as well as GCC\n     if test \"x$GCC\" = \"xyes\"; then\n        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],\n            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */\n#            if defined(__clang__) && defined(__llvm__)\n             AX_PTHREAD_CC_IS_CLANG\n#            endif\n            ],\n            [ax_cv_PTHREAD_CLANG=yes])\n     fi\n    ])\nax_pthread_clang=\"$ax_cv_PTHREAD_CLANG\"\n\nax_pthread_clang_warning=no\n\n# Clang needs special handling, because older versions handle the -pthread\n# option in a rather... idiosyncratic way\n\nif test \"x$ax_pthread_clang\" = \"xyes\"; then\n\n        # Clang takes -pthread; it has never supported any other flag\n\n        # (Note 1: This will need to be revisited if a system that Clang\n        # supports has POSIX threads in a separate library.  This tends not\n        # to be the way of modern systems, but it's conceivable.)\n\n        # (Note 2: On some systems, notably Darwin, -pthread is not needed\n        # to get POSIX threads support; the API is always present and\n        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But\n        # -pthread does define _REENTRANT, and while the Darwin headers\n        # ignore this macro, third-party headers might not.)\n\n        PTHREAD_CFLAGS=\"-pthread\"\n        PTHREAD_LIBS=\n\n        ax_pthread_ok=yes\n\n        # However, older versions of Clang make a point of warning the user\n        # that, in an invocation where only linking and no compilation is\n        # taking place, the -pthread option has no effect (\"argument unused\n        # during compilation\").  They expect -pthread to be passed in only\n        # when source code is being compiled.\n        #\n        # Problem is, this is at odds with the way Automake and most other\n        # C build frameworks function, which is that the same flags used in\n        # compilation (CFLAGS) are also used in linking.  Many systems\n        # supported by AX_PTHREAD require exactly this for POSIX threads\n        # support, and in fact it is often not straightforward to specify a\n        # flag that is used only in the compilation phase and not in\n        # linking.  Such a scenario is extremely rare in practice.\n        #\n        # Even though use of the -pthread flag in linking would only print\n        # a warning, this can be a nuisance for well-run software projects\n        # that build with -Werror.  So if the active version of Clang has\n        # this misfeature, we search for an option to squash it.\n\n        AC_CACHE_CHECK([whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread],\n            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],\n            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown\n             # Create an alternate version of $ac_link that compiles and\n             # links in two steps (.c -> .o, .o -> exe) instead of one\n             # (.c -> exe), because the warning occurs only in the second\n             # step\n             ax_pthread_save_ac_link=\"$ac_link\"\n             ax_pthread_sed='s/conftest\\.\\$ac_ext/conftest.$ac_objext/g'\n             ax_pthread_link_step=`$as_echo \"$ac_link\" | sed \"$ax_pthread_sed\"`\n             ax_pthread_2step_ac_link=\"($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)\"\n             ax_pthread_save_CFLAGS=\"$CFLAGS\"\n             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do\n                AS_IF([test \"x$ax_pthread_try\" = \"xunknown\"], [break])\n                CFLAGS=\"-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS\"\n                ac_link=\"$ax_pthread_save_ac_link\"\n                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],\n                    [ac_link=\"$ax_pthread_2step_ac_link\"\n                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],\n                         [break])\n                    ])\n             done\n             ac_link=\"$ax_pthread_save_ac_link\"\n             CFLAGS=\"$ax_pthread_save_CFLAGS\"\n             AS_IF([test \"x$ax_pthread_try\" = \"x\"], [ax_pthread_try=no])\n             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=\"$ax_pthread_try\"\n            ])\n\n        case \"$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG\" in\n                no | unknown) ;;\n                *) PTHREAD_CFLAGS=\"$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS\" ;;\n        esac\n\nfi # $ax_pthread_clang = yes\n\nif test \"x$ax_pthread_ok\" = \"xno\"; then\nfor ax_pthread_try_flag in $ax_pthread_flags; do\n\n        case $ax_pthread_try_flag in\n                none)\n                AC_MSG_CHECKING([whether pthreads work without any flags])\n                ;;\n\n                -mt,pthread)\n                AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])\n                PTHREAD_CFLAGS=\"-mt\"\n                PTHREAD_LIBS=\"-lpthread\"\n                ;;\n\n                -*)\n                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])\n                PTHREAD_CFLAGS=\"$ax_pthread_try_flag\"\n                ;;\n\n                pthread-config)\n                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])\n                AS_IF([test \"x$ax_pthread_config\" = \"xno\"], [continue])\n                PTHREAD_CFLAGS=\"`pthread-config --cflags`\"\n                PTHREAD_LIBS=\"`pthread-config --ldflags` `pthread-config --libs`\"\n                ;;\n\n                *)\n                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])\n                PTHREAD_LIBS=\"-l$ax_pthread_try_flag\"\n                ;;\n        esac\n\n        ax_pthread_save_CFLAGS=\"$CFLAGS\"\n        ax_pthread_save_LIBS=\"$LIBS\"\n        CFLAGS=\"$CFLAGS $PTHREAD_CFLAGS\"\n        LIBS=\"$PTHREAD_LIBS $LIBS\"\n\n        # Check for various functions.  We must include pthread.h,\n        # since some functions may be macros.  (On the Sequent, we\n        # need a special flag -Kthread to make this header compile.)\n        # We check for pthread_join because it is in -lpthread on IRIX\n        # while pthread_create is in libc.  We check for pthread_attr_init\n        # due to DEC craziness with -lpthreads.  We check for\n        # pthread_cleanup_push because it is one of the few pthread\n        # functions on Solaris that doesn't have a non-functional libc stub.\n        # We try pthread_create on general principles.\n\n        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>\n#                       if $ax_pthread_check_cond\n#                        error \"$ax_pthread_check_macro must be defined\"\n#                       endif\n                        static void routine(void *a) { a = 0; }\n                        static void *start_routine(void *a) { return a; }],\n                       [pthread_t th; pthread_attr_t attr;\n                        pthread_create(&th, 0, start_routine, 0);\n                        pthread_join(th, 0);\n                        pthread_attr_init(&attr);\n                        pthread_cleanup_push(routine, 0);\n                        pthread_cleanup_pop(0) /* ; */])],\n            [ax_pthread_ok=yes],\n            [])\n\n        CFLAGS=\"$ax_pthread_save_CFLAGS\"\n        LIBS=\"$ax_pthread_save_LIBS\"\n\n        AC_MSG_RESULT([$ax_pthread_ok])\n        AS_IF([test \"x$ax_pthread_ok\" = \"xyes\"], [break])\n\n        PTHREAD_LIBS=\"\"\n        PTHREAD_CFLAGS=\"\"\ndone\nfi\n\n# Various other checks:\nif test \"x$ax_pthread_ok\" = \"xyes\"; then\n        ax_pthread_save_CFLAGS=\"$CFLAGS\"\n        ax_pthread_save_LIBS=\"$LIBS\"\n        CFLAGS=\"$CFLAGS $PTHREAD_CFLAGS\"\n        LIBS=\"$PTHREAD_LIBS $LIBS\"\n\n        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.\n        AC_CACHE_CHECK([for joinable pthread attribute],\n            [ax_cv_PTHREAD_JOINABLE_ATTR],\n            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown\n             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do\n                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],\n                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],\n                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],\n                                [])\n             done\n            ])\n        AS_IF([test \"x$ax_cv_PTHREAD_JOINABLE_ATTR\" != \"xunknown\" && \\\n               test \"x$ax_cv_PTHREAD_JOINABLE_ATTR\" != \"xPTHREAD_CREATE_JOINABLE\" && \\\n               test \"x$ax_pthread_joinable_attr_defined\" != \"xyes\"],\n              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],\n                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],\n                                  [Define to necessary symbol if this constant\n                                   uses a non-standard name on your system.])\n               ax_pthread_joinable_attr_defined=yes\n              ])\n\n        AC_CACHE_CHECK([whether more special flags are required for pthreads],\n            [ax_cv_PTHREAD_SPECIAL_FLAGS],\n            [ax_cv_PTHREAD_SPECIAL_FLAGS=no\n             case $host_os in\n             solaris*)\n             ax_cv_PTHREAD_SPECIAL_FLAGS=\"-D_POSIX_PTHREAD_SEMANTICS\"\n             ;;\n             esac\n            ])\n        AS_IF([test \"x$ax_cv_PTHREAD_SPECIAL_FLAGS\" != \"xno\" && \\\n               test \"x$ax_pthread_special_flags_added\" != \"xyes\"],\n              [PTHREAD_CFLAGS=\"$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS\"\n               ax_pthread_special_flags_added=yes])\n\n        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],\n            [ax_cv_PTHREAD_PRIO_INHERIT],\n            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],\n                                             [[int i = PTHREAD_PRIO_INHERIT;]])],\n                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],\n                            [ax_cv_PTHREAD_PRIO_INHERIT=no])\n            ])\n        AS_IF([test \"x$ax_cv_PTHREAD_PRIO_INHERIT\" = \"xyes\" && \\\n               test \"x$ax_pthread_prio_inherit_defined\" != \"xyes\"],\n              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])\n               ax_pthread_prio_inherit_defined=yes\n              ])\n\n        CFLAGS=\"$ax_pthread_save_CFLAGS\"\n        LIBS=\"$ax_pthread_save_LIBS\"\n\n        # More AIX lossage: compile with *_r variant\n        if test \"x$GCC\" != \"xyes\"; then\n            case $host_os in\n                aix*)\n                AS_CASE([\"x/$CC\"],\n                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],\n                    [#handle absolute path differently from PATH based program lookup\n                     AS_CASE([\"x$CC\"],\n                         [x/*],\n                         [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC=\"${CC}_r\"])],\n                         [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])\n                ;;\n            esac\n        fi\nfi\n\ntest -n \"$PTHREAD_CC\" || PTHREAD_CC=\"$CC\"\n\nAC_SUBST([PTHREAD_LIBS])\nAC_SUBST([PTHREAD_CFLAGS])\nAC_SUBST([PTHREAD_CC])\n\n# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:\nif test \"x$ax_pthread_ok\" = \"xyes\"; then\n        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])\n        :\nelse\n        ax_pthread_ok=no\n        $2\nfi\nAC_LANG_POP\n])dnl AX_PTHREAD\n"
  },
  {
    "path": "m4/ax_valgrind_check.m4",
    "content": "# ===========================================================================\n#     http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html\n# ===========================================================================\n#\n# SYNOPSIS\n#\n#   AX_VALGRIND_DFLT(memcheck|helgrind|drd|sgcheck, on|off)\n#   AX_VALGRIND_CHECK()\n#\n# DESCRIPTION\n#\n#   AX_VALGRIND_CHECK checks whether Valgrind is present and, if so, allows\n#   running `make check` under a variety of Valgrind tools to check for\n#   memory and threading errors.\n#\n#   Defines VALGRIND_CHECK_RULES which should be substituted in your\n#   Makefile; and $enable_valgrind which can be used in subsequent configure\n#   output. VALGRIND_ENABLED is defined and substituted, and corresponds to\n#   the value of the --enable-valgrind option, which defaults to being\n#   enabled if Valgrind is installed and disabled otherwise. Individual\n#   Valgrind tools can be disabled via --disable-valgrind-<tool>, the\n#   default is configurable via the AX_VALGRIND_DFLT command or is to use\n#   all commands not disabled via AX_VALGRIND_DFLT. All AX_VALGRIND_DFLT\n#   calls must be made before the call to AX_VALGRIND_CHECK.\n#\n#   If unit tests are written using a shell script and automake's\n#   LOG_COMPILER system, the $(VALGRIND) variable can be used within the\n#   shell scripts to enable Valgrind, as described here:\n#\n#     https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html\n#\n#   Usage example:\n#\n#   configure.ac:\n#\n#     AX_VALGRIND_DFLT([sgcheck], [off])\n#     AX_VALGRIND_CHECK\n#\n#   Makefile.am:\n#\n#     @VALGRIND_CHECK_RULES@\n#     VALGRIND_SUPPRESSIONS_FILES = my-project.supp\n#     EXTRA_DIST = my-project.supp\n#\n#   This results in a \"check-valgrind\" rule being added to any Makefile.am\n#   which includes \"@VALGRIND_CHECK_RULES@\" (assuming the module has been\n#   configured with --enable-valgrind). Running `make check-valgrind` in\n#   that directory will run the module's test suite (`make check`) once for\n#   each of the available Valgrind tools (out of memcheck, helgrind and drd)\n#   while the sgcheck will be skipped unless enabled again on the\n#   commandline with --enable-valgrind-sgcheck. The results for each check\n#   will be output to test-suite-$toolname.log. The target will succeed if\n#   there are zero errors and fail otherwise.\n#\n#   Alternatively, a \"check-valgrind-$TOOL\" rule will be added, for $TOOL in\n#   memcheck, helgrind, drd and sgcheck. These are useful because often only\n#   some of those tools can be ran cleanly on a codebase.\n#\n#   The macro supports running with and without libtool.\n#\n# LICENSE\n#\n#   Copyright (c) 2014, 2015, 2016 Philip Withnall <philip.withnall@collabora.co.uk>\n#\n#   Copying and distribution of this file, with or without modification, are\n#   permitted in any medium without royalty provided the copyright notice\n#   and this notice are preserved.  This file is offered as-is, without any\n#   warranty.\n\n#serial 13.1\n\ndnl Configured tools\nm4_define([valgrind_tool_list], [[memcheck], [helgrind], [drd], [sgcheck]])\nm4_set_add_all([valgrind_exp_tool_set], [sgcheck])\nm4_foreach([vgtool], [valgrind_tool_list],\n           [m4_define([en_dflt_valgrind_]vgtool, [on])])\n\nAC_DEFUN([AX_VALGRIND_DFLT],[\n\tm4_define([en_dflt_valgrind_$1], [$2])\n])dnl\n\nAC_DEFUN([AX_VALGRIND_CHECK],[\n\tdnl Check for --enable-valgrind\n\tAC_ARG_ENABLE([valgrind],\n\t              [AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])],\n\t              [enable_valgrind=$enableval],[enable_valgrind=])\n\n\tAS_IF([test \"$enable_valgrind\" != \"no\"],[\n\t\t# Check for Valgrind.\n\t\tAC_CHECK_PROG([VALGRIND],[valgrind],[valgrind])\n\t\tAS_IF([test \"$VALGRIND\" = \"\"],[\n\t\t\tAS_IF([test \"$enable_valgrind\" = \"yes\"],[\n\t\t\t\tAC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind])\n\t\t\t],[\n\t\t\t\tenable_valgrind=no\n\t\t\t])\n\t\t],[\n\t\t\tenable_valgrind=yes\n\t\t])\n\t])\n\n\tAM_CONDITIONAL([VALGRIND_ENABLED],[test \"$enable_valgrind\" = \"yes\"])\n\tAC_SUBST([VALGRIND_ENABLED],[$enable_valgrind])\n\n\t# Check for Valgrind tools we care about.\n\t[valgrind_enabled_tools=]\n\tm4_foreach([vgtool],[valgrind_tool_list],[\n\t\tAC_ARG_ENABLE([valgrind-]vgtool,\n\t\t    m4_if(m4_defn([en_dflt_valgrind_]vgtool),[off],dnl\n[AS_HELP_STRING([--enable-valgrind-]vgtool, [Whether to use ]vgtool[ during the Valgrind tests])],dnl\n[AS_HELP_STRING([--disable-valgrind-]vgtool, [Whether to skip ]vgtool[ during the Valgrind tests])]),\n\t\t              [enable_valgrind_]vgtool[=$enableval],\n\t\t              [enable_valgrind_]vgtool[=])\n\t\tAS_IF([test \"$enable_valgrind\" = \"no\"],[\n\t\t\tenable_valgrind_]vgtool[=no],\n\t\t      [test \"$enable_valgrind_]vgtool[\" ]dnl\nm4_if(m4_defn([en_dflt_valgrind_]vgtool), [off], [= \"yes\"], [!= \"no\"]),[\n\t\t\tAC_CACHE_CHECK([for Valgrind tool ]vgtool,\n\t\t\t               [ax_cv_valgrind_tool_]vgtool,[\n\t\t\t\tax_cv_valgrind_tool_]vgtool[=no\n\t\t\t\tm4_set_contains([valgrind_exp_tool_set],vgtool,\n\t\t\t\t    [m4_define([vgtoolx],[exp-]vgtool)],\n\t\t\t\t    [m4_define([vgtoolx],vgtool)])\n\t\t\t\tAS_IF([`$VALGRIND --tool=]vgtoolx[ --help >/dev/null 2>&1`],[\n\t\t\t\t\tax_cv_valgrind_tool_]vgtool[=yes\n\t\t\t\t])\n\t\t\t])\n\t\t\tAS_IF([test \"$ax_cv_valgrind_tool_]vgtool[\" = \"no\"],[\n\t\t\t\tAS_IF([test \"$enable_valgrind_]vgtool[\" = \"yes\"],[\n\t\t\t\t\tAC_MSG_ERROR([Valgrind does not support ]vgtool[; reconfigure with --disable-valgrind-]vgtool)\n\t\t\t\t],[\n\t\t\t\t\tenable_valgrind_]vgtool[=no\n\t\t\t\t])\n\t\t\t],[\n\t\t\t\tenable_valgrind_]vgtool[=yes\n\t\t\t])\n\t\t])\n\t\tAS_IF([test \"$enable_valgrind_]vgtool[\" = \"yes\"],[\n\t\t\tvalgrind_enabled_tools=\"$valgrind_enabled_tools ]m4_bpatsubst(vgtool,[^exp-])[\"\n\t\t])\n\t\tAC_SUBST([ENABLE_VALGRIND_]vgtool,[$enable_valgrind_]vgtool)\n\t])\n\tAC_SUBST([valgrind_tools],[\"]m4_join([ ], valgrind_tool_list)[\"])\n\tAC_SUBST([valgrind_enabled_tools],[$valgrind_enabled_tools])\n\n[VALGRIND_CHECK_RULES='\n# Valgrind check\n#\n# Optional:\n#  - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions\n#    files to load. (Default: empty)\n#  - VALGRIND_FLAGS: General flags to pass to all Valgrind tools.\n#    (Default: --num-callers=30)\n#  - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of:\n#    memcheck, helgrind, drd, sgcheck). (Default: various)\n\n# Optional variables\nVALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES))\nVALGRIND_FLAGS ?= --num-callers=30\nVALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no\nVALGRIND_helgrind_FLAGS ?= --history-level=approx\nVALGRIND_drd_FLAGS ?=\nVALGRIND_sgcheck_FLAGS ?=\n\n# Internal use\nvalgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools)))\n\nvalgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS)\nvalgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS)\nvalgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS)\nvalgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS)\n\nvalgrind_quiet = $(valgrind_quiet_$(V))\nvalgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY))\nvalgrind_quiet_0 = --quiet\nvalgrind_v_use   = $(valgrind_v_use_$(V))\nvalgrind_v_use_  = $(valgrind_v_use_$(AM_DEFAULT_VERBOSITY))\nvalgrind_v_use_0 = @echo \"  USE   \" $(patsubst check-valgrind-%,%,$''@):;\n\n# Support running with and without libtool.\nifneq ($(LIBTOOL),)\nvalgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute\nelse\nvalgrind_lt =\nendif\n\n# Use recursive makes in order to ignore errors during check\ncheck-valgrind:\nifeq ($(VALGRIND_ENABLED),yes)\n\t-$(A''M_V_at)$(foreach tool,$(valgrind_enabled_tools), \\\n\t\t$(MAKE) $(AM_MAKEFLAGS) -k check-valgrind-$(tool); \\\n\t)\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\n\n# Valgrind running\nVALGRIND_TESTS_ENVIRONMENT = \\\n\t$(TESTS_ENVIRONMENT) \\\n\tenv VALGRIND=$(VALGRIND) \\\n\tG_SLICE=always-malloc,debug-blocks \\\n\tG_DEBUG=fatal-warnings,fatal-criticals,gc-friendly\n\nVALGRIND_LOG_COMPILER = \\\n\t$(valgrind_lt) \\\n\t$(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS)\n\ndefine valgrind_tool_rule\ncheck-valgrind-$(1):\nifeq ($$(VALGRIND_ENABLED)-$$(ENABLE_VALGRIND_$(1)),yes-yes)\n\t$$(valgrind_v_use)$$(MAKE) check-TESTS \\\n\t\tTESTS_ENVIRONMENT=\"$$(VALGRIND_TESTS_ENVIRONMENT)\" \\\n\t\tLOG_COMPILER=\"$$(VALGRIND_LOG_COMPILER)\" \\\n\t\tLOG_FLAGS=\"$$(valgrind_$(1)_flags)\" \\\n\t\tTEST_SUITE_LOG=test-suite-$(1).log\nelse ifeq ($$(VALGRIND_ENABLED),yes)\n\t@echo \"Need to reconfigure with --enable-valgrind-$(1)\"\nelse\n\t@echo \"Need to reconfigure with --enable-valgrind\"\nendif\nendef\n\n$(foreach tool,$(valgrind_tools),$(eval $(call valgrind_tool_rule,$(tool))))\n\nA''M_DISTCHECK_CONFIGURE_FLAGS ?=\nA''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind\n\nMOSTLYCLEANFILES ?=\nMOSTLYCLEANFILES += $(valgrind_log_files)\n\n.PHONY: check-valgrind $(add-prefix check-valgrind-,$(valgrind_tools))\n']\n\n\tAC_SUBST([VALGRIND_CHECK_RULES])\n\tm4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])])\n])\n"
  },
  {
    "path": "make-dist.sh",
    "content": "#!/bin/sh\n\nPROJECT=libcork\n\nCOMMIT=\"$1\"\nif [ -z \"$COMMIT\" ]; then\n    COMMIT=\"HEAD\"\nfi\n\nVERSION=$(git describe ${COMMIT})\ngit archive --prefix=${PROJECT}-${VERSION}/ --format=tar ${COMMIT} | \\\n    bzip2 -c > ${PROJECT}-${VERSION}.tar.bz2\n"
  },
  {
    "path": "run.sh",
    "content": "#!/bin/sh\n# Usage: run.sh [debug|release] program arguments\n#\n# Runs a program from one of the build directories, with\n# LD_LIBRARY_PATH set correctly so that it can find all of the shared\n# libraries before they're installed.\n\n\n# Check that there are enough command-line parameters.\n\nif [ $# -lt 1 ]; then\n    echo \"Usage: run.sh [debug|release] program arguments\"\n    exit 1\nfi\n\n\n# Verify that the user chose a valid build type.\n\nBUILD=\"$1\"\nshift\n\ncase \"$BUILD\" in\n    debug)\n        ;;\n    release)\n        ;;\n    *)\n        echo \"Unknown build type $BUILD\"\n        exit 1\n        ;;\nesac\n\n\n# Find all of the src subdirectories in the build directory, and use\n# those as the LD_LIBRARY_PATH.\n\nSRC_DIRS=$(find build/$BUILD -name src)\nJOINED=$(echo $SRC_DIRS | perl -ne 'print join(\":\", split)')\n\n\n# Run the desired program, and pass on any command-line arguments\n# as-is.\n\nLD_LIBRARY_PATH=\"$JOINED:$LD_LIBRARY_PATH\" \\\nDYLD_LIBRARY_PATH=\"$JOINED:$DYLD_LIBRARY_PATH\" \\\n  \"$@\"\n"
  },
  {
    "path": "scripts/install",
    "content": "#!/bin/sh\n\nset -e\n\nif [ \"$OS_NAME\" = \"ubuntu-latest\" ]; then\n    sudo dpkg --add-architecture i386\n    sudo apt-get update\n    sudo apt-get install -y check check:i386 gcc-multilib valgrind\nelif [ \"$OS_NAME\" = osx ]; then\n    brew install --universal check\nfi\n"
  },
  {
    "path": "scripts/test",
    "content": "#!/bin/bash\n\nset -e\n\n# Defaults\nENABLE_SHARED_TESTS=NO\nSRCDIR=\"$PWD\"\n: ${TMPDIR:=/tmp}\n\nif [ \"$COMPILER\" = clang ]; then\n    export CC=/usr/bin/clang\nelse\n    export CC=/usr/bin/gcc\nfi\n\nif [ \"$OS_NAME\" = \"ubuntu-latest\" ]; then\n    if [ \"$ARCH\" = i386 ]; then\n        ARCH_FLAGS=\"-m32\"\n        export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig\n    else\n        ARCH_FLAGS=\"\"\n    fi\nelif [ \"$OS_NAME\" = osx ]; then\n    if [ \"$ARCH\" = i386 ]; then\n        ARCH_FLAGS=\"-arch i386\"\n    else\n        ARCH_FLAGS=\"-arch x86_64\"\n    fi\nfi\n\nbuild_autotools () {\n  BUILDDIR=$(mktemp -d \"$TMPDIR\"/build-autotools-XXXXXX)\n  echo \"Using autotools to build in $BUILDDIR\"\n  echo \"$ autogen.sh\"\n  \"$SRCDIR\"/autogen.sh\n  cd \"$BUILDDIR\"\n  echo \"$ configure\"\n  CFLAGS=\"-g -O3 $ARCH_FLAGS\" \"$SRCDIR\"/configure\n  echo \"$ make\"\n  make\n  echo \"$ make check\"\n  make check VERBOSE=1\n  echo \"$ make distcheck\"\n  make distcheck\n}\n\nbuild_cmake () {\n  BUILDDIR=$(mktemp -d \"$TMPDIR\"/build-cmake-XXXXXX)\n  echo \"Using cmake to build in $BUILDDIR\"\n  cd \"$BUILDDIR\"\n  echo \"$ cmake\"\n  cmake \"$SRCDIR\" \\\n      -DCMAKE_BUILD_TYPE=RelWithDebInfo \\\n      -DCMAKE_C_FLAGS_RELWITHDEBINFO=\"-g -O3 $ARCH_FLAGS $EXTRA_FLAGS\" \\\n      -DENABLE_SHARED_TESTS=\"$ENABLE_SHARED_TESTS\"\n  echo \"$ make\"\n  make\n  echo \"$ make test\"\n  CTEST_OUTPUT_ON_FAILURE=1 make test\n}\n\nbuild_cmake_from_dist () {\n  DISTDIR=$(mktemp -d \"$TMPDIR\"/build-dist-XXXXXX)\n  echo \"Using autotools to create dist tarball in $DISTDIR\"\n  \"$SRCDIR\"/autogen.sh\n  cd \"$DISTDIR\"\n  echo \"$ configure\"\n  CFLAGS=\"-g -O3 $ARCH_FLAGS\" \"$SRCDIR\"/configure\n  echo \"$ make dist\"\n  make dist\n  # We should end up with exactly one *.tar.xz file\n  TARBALL=$(ls *.tar.xz | head -n 1)\n  UNPACKED=${TARBALL%.tar.xz}\n\n  UNPACKEDDIR=$(mktemp -d \"$TMPDIR\"/build-unpacked-XXXXXX)\n  echo \"Unpacking dist tarball $UNPACKED into $UNPACKEDDIR\"\n  cd \"$UNPACKEDDIR\"\n  tar xvf \"$DISTDIR\"/\"$TARBALL\"\n\n  BUILDDIR=$(mktemp -d \"$TMPDIR\"/build-cmake-XXXXXX)\n  echo \"Using cmake to build from dist tarball in $BUILDDIR\"\n  cd \"$BUILDDIR\"\n  echo \"$ cmake\"\n  cmake \"$UNPACKEDDIR\"/\"$UNPACKED\" \\\n      -DCMAKE_BUILD_TYPE=RelWithDebInfo \\\n      -DCMAKE_C_FLAGS_RELWITHDEBINFO=\"-g -O3 $ARCH_FLAGS $EXTRA_FLAGS\"\n  echo \"$ make\"\n  make\n  echo \"$ make test\"\n  CTEST_OUTPUT_ON_FAILURE=1 make test\n}\n\n# Flavors\ncase $FLAVOR in\n  autotools)\n    BUILDER=autotools\n    ;;\n  cmake)\n    BUILDER=cmake\n    ;;\n  shared-cmake)\n    BUILDER=cmake\n    ENABLE_SHARED_TESTS=yes\n    ;;\n  fallback-u128)\n    BUILDER=cmake\n    EXTRA_FLAGS=\"$EXTRA_FLAGS -DCORK_CONFIG_HAVE_GCC_INT128=0\"\n    EXTRA_FLAGS=\"$EXTRA_FLAGS -DCORK_CONFIG_HAVE_GCC_MODE_ATTRIBUTE=0\"\n    ;;\n  cmake-from-dist)\n    BUILDER=cmake_from_dist\n    ;;\n  *)\n    echo \"Unknown build flavor $FLAVOR!\" >&2\n    exit 1\n    ;;\nesac\n\nbuild_$BUILDER\n"
  },
  {
    "path": "share/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2012, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\ninstall(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/valgrind\n    DESTINATION share\n    FILES_MATCHING PATTERN \"*.supp\")\n"
  },
  {
    "path": "share/valgrind/libcork.supp",
    "content": "# Valgrind suppressions for libcork\n\n{\n   libcork/cork_gc_get\n   Memcheck:Leak\n   fun:calloc\n   fun:cork_gc_get\n}\n"
  },
  {
    "path": "src/APPNAME.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=${prefix}\nlibdir=${exec_prefix}/lib\nincludedir=${prefix}/include\nsharedir=${prefix}/share\n\nName: APPNAME\nDescription: FILL_THIS_IN\nVersion: @VERSION@\nURL: FILL_THIS_IN\nLibs: -L${libdir} -lAPPNAME\nCflags: -I${includedir}\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n#-----------------------------------------------------------------------\n# libcork\n\n# Update the VERSION_INFO property below according to the following rules (taken\n# from [1]):\n#\n# VERSION_INFO = current:revision:age\n#\n#   1. Start with a VERSION of `0:0:0` for each shared library.\n#   2. Update VERSION_INFO only immediately before a public release of your\n#      software.  More frequent updates are unnecessary, and only guarantee that\n#      the current interface number gets larger faster.\n#   3. If the library source code has changed at all since the last update, then\n#      increment `revision` (`c:r:a` becomes `c:r+1:a`).\n#   4. If any interfaces have been added, removed, or changed since the last\n#      update, increment `current`, and set `revision` to 0.\n#   5. If any interfaces have been added since the last public release, then\n#      increment `age`.\n#   6. If any interfaces have been removed or changed since the last public\n#      release, then set `age` to 0.\n#\n# Note that changing `current` and setting `age` to 0 means that you are\n# releasing a new backwards-incompatible version of the library.  This has\n# implications on packaging, so once an API has stabilized, this should be a\n# rare occurrence.\n#\n# [1] http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info\n\nadd_c_library(\n    libcork\n    OUTPUT_NAME cork\n    PKGCONFIG_NAME libcork\n    VERSION_INFO 17:0:1\n    SOURCES\n        libcork/cli/commands.c\n        libcork/core/allocator.c\n        libcork/core/error.c\n        libcork/core/gc.c\n        libcork/core/hash.c\n        libcork/core/id.c\n        libcork/core/ip-address.c\n        libcork/core/mempool.c\n        libcork/core/timestamp.c\n        libcork/core/u128.c\n        libcork/core/version.c\n        libcork/ds/array.c\n        libcork/ds/bitset.c\n        libcork/ds/buffer.c\n        libcork/ds/dllist.c\n        libcork/ds/file-stream.c\n        libcork/ds/hash-table.c\n        libcork/ds/managed-buffer.c\n        libcork/ds/ring-buffer.c\n        libcork/ds/slice.c\n        libcork/ds/stream.c\n        libcork/posix/directory-walker.c\n        libcork/posix/env.c\n        libcork/posix/exec.c\n        libcork/posix/files.c\n        libcork/posix/process.c\n        libcork/posix/subprocess.c\n        libcork/pthreads/thread.c\n    LIBRARIES\n        threads\n)\n\nif (ENABLE_SHARED OR ENABLE_SHARED_EXECUTABLES OR ENABLE_SHARED_TESTS)\n    set_target_properties(libcork-shared PROPERTIES\n        COMPILE_DEFINITIONS CORK_API=CORK_EXPORT\n    )\nendif (ENABLE_SHARED OR ENABLE_SHARED_EXECUTABLES OR ENABLE_SHARED_TESTS)\n\nif (ENABLE_STATIC OR NOT ENABLE_SHARED_EXECUTABLES OR NOT ENABLE_SHARED_TESTS)\n    set_target_properties(libcork-static PROPERTIES\n        COMPILE_DEFINITIONS CORK_API=CORK_LOCAL\n    )\nendif (ENABLE_STATIC OR NOT ENABLE_SHARED_EXECUTABLES OR NOT ENABLE_SHARED_TESTS)\n\n\n#-----------------------------------------------------------------------\n# Utility commands\n\nadd_c_executable(\n    cork-hash\n    OUTPUT_NAME cork-hash\n    SOURCES cork-hash/cork-hash.c\n    LOCAL_LIBRARIES\n        libcork\n)\n\nadd_c_executable(\n    cork-initializer\n    SKIP_INSTALL\n    OUTPUT_NAME cork-initializer\n    SOURCES\n        cork-initializer/init1.c\n        cork-initializer/init2.c\n        cork-initializer/main.c\n    LOCAL_LIBRARIES\n        libcork\n)\n\nadd_c_executable(\n    cork-test\n    SKIP_INSTALL\n    OUTPUT_NAME cork-test\n    SOURCES cork-test/cork-test.c\n    LOCAL_LIBRARIES\n        libcork\n)\n"
  },
  {
    "path": "src/cork-hash/cork-hash.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <getopt.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <libcork/core.h>\n\nenum cork_hash_type {\n    CORK_HASH_BIG,\n    CORK_HASH_FASTEST,\n    CORK_HASH_STABLE\n};\n\nstatic enum cork_hash_type  type = CORK_HASH_STABLE;\nstatic const char  *string = NULL;\n\n#define OPT_VERSION 1000\n\nstatic struct option  opts[] = {\n    { \"big\", no_argument, NULL, 'b' },\n    { \"fastest\", no_argument, NULL, 'f' },\n    { \"stable\", no_argument, NULL, 's' },\n    { \"version\", no_argument, NULL, OPT_VERSION },\n    { NULL, 0, NULL, 0 }\n};\n\nstatic void\nusage(void)\n{\n    fprintf(stderr,\n            \"Usage: cork-hash [<options>] <string>\\n\"\n            \"\\n\"\n            \"Options:\\n\"\n            \"  -b, --big\\n\"\n            \"  -f, --fastest\\n\"\n            \"  -s, --stable\\n\");\n}\n\nstatic void\nprint_version(void)\n{\n    const char  *version = cork_version_string();\n    const char  *revision = cork_revision_string();\n\n    printf(\"cork-hash %s\\n\", version);\n    if (strcmp(version, revision) != 0) {\n        printf(\"Revision %s\\n\", revision);\n    }\n}\n\nstatic void\nparse_options(int argc, char **argv)\n{\n    int  ch;\n    while ((ch = getopt_long(argc, argv, \"+bfs\", opts, NULL)) != -1) {\n        switch (ch) {\n            case 'b':\n                type = CORK_HASH_BIG;\n                break;\n            case 'f':\n                type = CORK_HASH_FASTEST;\n                break;\n            case 's':\n                type = CORK_HASH_STABLE;\n                break;\n            case OPT_VERSION:\n                print_version();\n                exit(EXIT_SUCCESS);\n            default:\n                usage();\n                exit(EXIT_FAILURE);\n        }\n    }\n\n    if (optind != argc-1) {\n        usage();\n        exit(EXIT_FAILURE);\n    }\n\n    string = argv[optind];\n}\n\nint\nmain(int argc, char **argv)\n{\n    parse_options(argc, argv);\n\n    if (type == CORK_HASH_BIG) {\n        cork_big_hash  result = CORK_BIG_HASH_INIT();\n        result = cork_big_hash_buffer(result, string, strlen(string));\n        printf(\"%016\" PRIx64 \"%016\" PRIx64 \"\\n\",\n               cork_u128_be64(result.u128, 0),\n               cork_u128_be64(result.u128, 1));\n    }\n\n    if (type == CORK_HASH_FASTEST) {\n        /* don't include NUL terminator in hash */\n        cork_hash  result = 0;\n        result = cork_hash_buffer(result, string, strlen(string));\n        printf(\"0x%08\" PRIx32 \"\\n\", result);\n    }\n\n    if (type == CORK_HASH_STABLE) {\n        /* don't include NUL terminator in hash */\n        cork_hash  result = 0;\n        result = cork_stable_hash_buffer(result, string, strlen(string));\n        printf(\"0x%08\" PRIx32 \"\\n\", result);\n    }\n\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "src/cork-initializer/init1.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdio.h>\n\n#include <libcork/core.h>\n\nCORK_INITIALIZER(init)\n{\n    printf(\"Initializer 1\\n\");\n}\n\nCORK_FINALIZER(done)\n{\n    printf(\"Finalizer 1\\n\");\n}\n"
  },
  {
    "path": "src/cork-initializer/init2.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdio.h>\n\n#include <libcork/core.h>\n\nCORK_INITIALIZER(init)\n{\n    printf(\"Initializer 2\\n\");\n}\n"
  },
  {
    "path": "src/cork-initializer/main.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\nint\nmain(int argc, char **argv)\n{\n    return 0;\n}\n"
  },
  {
    "path": "src/cork-test/cork-test.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"libcork/cli.h\"\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os.h\"\n\n\n#define streq(s1, s2)  (strcmp((s1), (s2)) == 0)\n\n/* Note: We print out error messages to stdout, not stderr, to ensure that our\n * test case output is reproducible.  (It's not defined how stdout and stderr\n * are interleaved together.) */\n\n#define ri_check_exit(call) \\\n    do { \\\n        if ((call) != 0) { \\\n            printf(\"%s\\n\", cork_error_message()); \\\n            exit(EXIT_FAILURE); \\\n        } \\\n    } while (0)\n\n#define rp_check_exit(call) \\\n    do { \\\n        if ((call) == NULL) { \\\n            printf(\"%s\\n\", cork_error_message()); \\\n            exit(EXIT_FAILURE); \\\n        } \\\n    } while (0)\n\n\n/*-----------------------------------------------------------------------\n * Command list\n */\n\nstatic bool  test_option = false;\nstatic const char  *file_option = NULL;\n\n/* cork-test c1 s1 */\n\nstatic int\nc1_s1_options(int argc, char **argv);\n\nstatic void\nc1_s1_run(int argc, char **argv);\n\nstatic struct cork_command  c1_s1 =\n    cork_leaf_command(\"s1\", \"Subcommand 1\", \"[<options>] <filename>\",\n                      \"This is a pretty cool command.\\n\",\n                      c1_s1_options, c1_s1_run);\n\nstatic int\nc1_s1_options(int argc, char **argv)\n{\n    if (argc >= 2 && (streq(argv[1], \"-t\") || streq(argv[1], \"--test\"))) {\n        test_option = true;\n        return 2;\n    } else {\n        return 1;\n    }\n}\n\nstatic void\nc1_s1_run(int argc, char **argv)\n{\n    printf(\"You chose command \\\"c1 s1\\\".  Good for you!\\n\");\n    if (test_option) {\n        printf(\"And you gave the --test option!  Look at that.\\n\");\n    }\n    if (file_option != NULL) {\n        printf(\"And you want the file to be %s.  Sure thing.\\n\", file_option);\n    }\n    exit(EXIT_SUCCESS);\n}\n\n\n/* cork-test c1 s2 */\n\nstatic void\nc1_s2_run(int argc, char **argv)\n{\n    printf(\"You chose command \\\"c1 s2\\\".  Fantastico!\\n\");\n    if (file_option != NULL) {\n        struct cork_stream_consumer  *consumer;\n        printf(\"And you want the file to be %s.  Sure thing.\\n\", file_option);\n\n        /* Print the contents of the file to stdout. */\n        rp_check_exit(consumer = cork_file_consumer_new(stdout));\n        ri_check_exit(cork_consume_file_from_path\n                      (consumer, file_option, O_RDONLY));\n        cork_stream_consumer_free(consumer);\n    }\n\n    exit(EXIT_SUCCESS);\n}\n\nstatic struct cork_command  c1_s2 =\n    cork_leaf_command(\"s2\", \"Subcommand 2\", \"[<options>] <filename>\",\n                      \"This is an excellent command.\\n\",\n                      NULL, c1_s2_run);\n\n\n/* cork-test c1 */\n\nstatic int\nc1_options(int argc, char **argv);\n\nstatic struct cork_command  *c1_subcommands[] = {\n    &c1_s1, &c1_s2, NULL\n};\n\nstatic struct cork_command  c1 =\n    cork_command_set(\"c1\", \"Command 1 (now with subcommands)\",\n                     c1_options, c1_subcommands);\n\nstatic int\nc1_options(int argc, char **argv)\n{\n    if (argc >= 3) {\n        if (streq(argv[1], \"-f\") || streq(argv[1], \"--file\")) {\n            file_option = argv[2];\n            return 3;\n        }\n    }\n\n    if (argc >= 2) {\n        if (memcmp(argv[1], \"--file=\", 7) == 0) {\n            file_option = argv[1] + 7;\n            return 2;\n        }\n    }\n\n    return 1;\n}\n\n\n/* cork-test c2 */\n\nstatic void\nc2_run(int argc, char **argv)\n{\n    printf(\"You chose command \\\"c2\\\".  That's pretty good.\\n\");\n    exit(EXIT_SUCCESS);\n}\n\nstatic struct cork_command  c2 =\n    cork_leaf_command(\"c2\", \"Command 2\", \"[<options>] <filename>\",\n                      \"This command is pretty decent.\\n\",\n                      NULL, c2_run);\n\n\n/*-----------------------------------------------------------------------\n * Forking subprocesses\n */\n\nstatic const char  *sub_cwd = NULL;\nstatic const char  *sub_stdin = NULL;\n\nstatic int\nsub_options(int argc, char **argv);\n\nstatic void\nsub_run(int argc, char **argv);\n\nstatic struct cork_command  sub =\n    cork_leaf_command(\"sub\", \"Run a subcommand\", \"<program> [<options>]\",\n                      \"Runs a subcommand.\\n\",\n                      sub_options, sub_run);\n\nstatic int\nsub_options(int argc, char **argv)\n{\n    int  processed = 1;\n    for (argc--, argv++; argc >= 1; argc--, argv++, processed++) {\n        if ((streq(argv[0], \"-d\") || streq(argv[0], \"--cwd\"))) {\n            if (argc >= 2) {\n                sub_cwd = argv[1];\n                argc--, argv++, processed++;\n            } else {\n                cork_command_show_help(&sub, \"Missing directory for --cwd\");\n                exit(EXIT_FAILURE);\n            }\n        } else if ((streq(argv[0], \"-i\") || streq(argv[0], \"--stdin\"))) {\n            if (argc >= 2) {\n                sub_stdin = argv[1];\n                argc--, argv++, processed++;\n            } else {\n                cork_command_show_help(&sub, \"Missing content for --stdin\");\n                exit(EXIT_FAILURE);\n            }\n        } else {\n            return processed;\n        }\n    }\n    return processed;\n}\n\nstatic void\nsub_run(int argc, char **argv)\n{\n    struct cork_env  *env;\n    struct cork_exec  *exec;\n    struct cork_subprocess_group  *group;\n    struct cork_subprocess  *sp;\n    struct cork_stream_consumer  *stdin_consumer;\n    struct cork_stream_consumer  *stdout_consumer;\n\n    if (argc == 0) {\n        cork_command_show_help(&sub, \"Missing command\");\n        exit(EXIT_FAILURE);\n    }\n\n    /* Note that we explicitly copy the child's stdout to our stdout using a\n     * cork_stream_consumer, instead of letting the child process inherit our\n     * stdout.  This gives us more control over how our output messages\n     * interleave with the child process's output messages, which is needed if\n     * we want the expected test output to be deterministic. */\n\n    rp_check_exit(env = cork_env_clone_current());\n    rp_check_exit(exec = cork_exec_new_with_param_array(argv[0], argv));\n    cork_exec_set_env(exec, env);\n    if (sub_cwd != NULL) {\n        cork_exec_set_cwd(exec, sub_cwd);\n    }\n    printf(\"%s\\n\", cork_exec_description(exec));\n    rp_check_exit(stdout_consumer = cork_file_consumer_new(stdout));\n    rp_check_exit(group = cork_subprocess_group_new());\n    rp_check_exit(sp = cork_subprocess_new_exec(\n                exec, stdout_consumer, stdout_consumer, NULL));\n    cork_subprocess_group_add(group, sp);\n    ri_check_exit(cork_subprocess_group_start(group));\n    stdin_consumer = cork_subprocess_stdin(sp);\n    if (sub_stdin != NULL) {\n        size_t  stdin_length = strlen(sub_stdin);\n        cork_stream_consumer_data\n            (stdin_consumer, sub_stdin, stdin_length, true);\n        cork_stream_consumer_data(stdin_consumer, \"\\n\", 1, false);\n    }\n    cork_stream_consumer_eof(stdin_consumer);\n    ri_check_exit(cork_subprocess_group_wait(group));\n    cork_subprocess_group_free(group);\n    cork_stream_consumer_free(stdout_consumer);\n}\n\n\n/*-----------------------------------------------------------------------\n * pwd\n */\n\n/* cork-test pwd */\n\nstatic void\npwd_run(int argc, char **argv);\n\nstatic struct cork_command  pwd =\n    cork_leaf_command(\"pwd\", \"Print working directory\",\n                      \"\",\n                      \"Prints out the current working directory.\\n\",\n                      NULL, pwd_run);\n\nstatic void\npwd_run(int argc, char **argv)\n{\n    struct cork_path  *path;\n    rp_check_exit(path = cork_path_cwd());\n    printf(\"%s\\n\", cork_path_get(path));\n    cork_path_free(path);\n    exit(EXIT_SUCCESS);\n}\n\n\n/*-----------------------------------------------------------------------\n * mkdir\n */\n\nstatic unsigned int  mkdir_flags = CORK_FILE_PERMISSIVE;\n\n/* cork-test mkdir */\n\nstatic int\nmkdir_options(int argc, char **argv);\n\nstatic void\nmkdir_run(int argc, char **argv);\n\nstatic struct cork_command  mkdir_cmd =\n    cork_leaf_command(\"mkdir\", \"Create a directory\",\n                      \"[<options>] <path>\",\n                      \"Create a new directory.\\n\",\n                      mkdir_options, mkdir_run);\n\nstatic int\nmkdir_options(int argc, char **argv)\n{\n    int  count = 1;\n\n    while (count < argc) {\n        if (streq(argv[count], \"--recursive\")) {\n            mkdir_flags |= CORK_FILE_RECURSIVE;\n            count++;\n        } else if (streq(argv[count], \"--require\")) {\n            mkdir_flags &= ~CORK_FILE_PERMISSIVE;\n            count++;\n        } else {\n            return count;\n        }\n    }\n\n    return count;\n}\n\nstatic void\nmkdir_run(int argc, char **argv)\n{\n    struct cork_file  *file;\n\n    if (argc < 1) {\n        cork_command_show_help(&mkdir_cmd, \"Missing file\");\n        exit(EXIT_FAILURE);\n    } else if (argc > 1) {\n        cork_command_show_help(&mkdir_cmd, \"Too many directories\");\n        exit(EXIT_FAILURE);\n    }\n\n    file = cork_file_new(argv[0]);\n    ri_check_exit(cork_file_mkdir(file, 0755, mkdir_flags));\n    cork_file_free(file);\n    exit(EXIT_SUCCESS);\n}\n\n\n/*-----------------------------------------------------------------------\n * rm\n */\n\nstatic unsigned int  rm_flags = CORK_FILE_PERMISSIVE;\n\n/* cork-test rm */\n\nstatic int\nrm_options(int argc, char **argv);\n\nstatic void\nrm_run(int argc, char **argv);\n\nstatic struct cork_command  rm_cmd =\n    cork_leaf_command(\"rm\", \"Remove a file or directory\",\n                      \"[<options>] <path>\",\n                      \"Remove a file or directory.\\n\",\n                      rm_options, rm_run);\n\nstatic int\nrm_options(int argc, char **argv)\n{\n    int  count = 1;\n\n    while (count < argc) {\n        if (streq(argv[count], \"--recursive\")) {\n            rm_flags |= CORK_FILE_RECURSIVE;\n            count++;\n        } else if (streq(argv[count], \"--require\")) {\n            rm_flags &= ~CORK_FILE_PERMISSIVE;\n            count++;\n        } else {\n            return count;\n        }\n    }\n\n    return count;\n}\n\nstatic void\nrm_run(int argc, char **argv)\n{\n    struct cork_file  *file;\n\n    if (argc < 1) {\n        cork_command_show_help(&rm_cmd, \"Missing file\");\n        exit(EXIT_FAILURE);\n    } else if (argc > 1) {\n        cork_command_show_help(&rm_cmd, \"Too many directories\");\n        exit(EXIT_FAILURE);\n    }\n\n    file = cork_file_new(argv[0]);\n    ri_check_exit(cork_file_remove(file, rm_flags));\n    cork_file_free(file);\n    exit(EXIT_SUCCESS);\n}\n\n\n/*-----------------------------------------------------------------------\n * find\n */\n\nstatic bool  find_all = false;\n\n/* cork-test find */\n\nstatic int\nfind_options(int argc, char **argv);\n\nstatic void\nfind_run(int argc, char **argv);\n\nstatic struct cork_command  find =\n    cork_leaf_command(\"find\", \"Search for a file in a list of directories\",\n                      \"<file> <path list>\",\n                      \"Search for a file in a list of directories.\\n\",\n                      find_options, find_run);\n\nstatic int\nfind_options(int argc, char **argv)\n{\n    if (argc >= 2 && streq(argv[1], \"--all\")) {\n        find_all = true;\n        return 2;\n    }\n    return 1;\n}\n\nstatic void\nfind_run(int argc, char **argv)\n{\n    struct cork_path_list  *list;\n\n    if (argc < 1) {\n        cork_command_show_help(&find, \"Missing file\");\n        exit(EXIT_FAILURE);\n    } else if (argc < 2) {\n        cork_command_show_help(&find, \"Missing path\");\n        exit(EXIT_FAILURE);\n    } else if (argc < 2) {\n        cork_command_show_help(&find, \"Too many parameters\");\n        exit(EXIT_FAILURE);\n    }\n\n    list = cork_path_list_new(argv[1]);\n\n    if (find_all) {\n        struct cork_file_list  *file_list;\n        size_t  i;\n        size_t  count;\n        rp_check_exit(file_list = cork_path_list_find_files(list, argv[0]));\n        count = cork_file_list_size(file_list);\n        for (i = 0; i < count; i++) {\n            struct cork_file  *file = cork_file_list_get(file_list, i);\n            printf(\"%s\\n\", cork_path_get(cork_file_path(file)));\n        }\n        cork_file_list_free(file_list);\n    } else {\n        struct cork_file  *file;\n        rp_check_exit(file = cork_path_list_find_file(list, argv[0]));\n        printf(\"%s\\n\", cork_path_get(cork_file_path(file)));\n        cork_file_free(file);\n    }\n\n    cork_path_list_free(list);\n    exit(EXIT_SUCCESS);\n}\n\n\n/*-----------------------------------------------------------------------\n * paths\n */\n\n/* cork-test paths */\n\nstatic void\npaths_run(int argc, char **argv);\n\nstatic struct cork_command  paths =\n    cork_leaf_command(\"paths\", \"Print out standard paths for the current user\",\n                      \"\",\n                      \"Print out standard paths for the current user.\\n\",\n                      NULL, paths_run);\n\nstatic void\nprint_path(const char *prefix, struct cork_path *path)\n{\n    rp_check_exit(path);\n    printf(\"%s %s\\n\", prefix, cork_path_get(path));\n    cork_path_free(path);\n}\n\nstatic void\nprint_path_list(const char *prefix, struct cork_path_list *list)\n{\n    rp_check_exit(list);\n    printf(\"%s %s\\n\", prefix, cork_path_list_to_string(list));\n    cork_path_list_free(list);\n}\n\nstatic void\npaths_run(int argc, char **argv)\n{\n    print_path     (\"Home:   \", cork_path_home());\n    print_path_list(\"Config: \", cork_path_config_paths());\n    print_path_list(\"Data:   \", cork_path_data_paths());\n    print_path     (\"Cache:  \", cork_path_user_cache_path());\n    print_path     (\"Runtime:\", cork_path_user_runtime_path());\n    exit(EXIT_SUCCESS);\n}\n\n\n/*-----------------------------------------------------------------------\n * Directory walker\n */\n\nstatic bool  only_files = false;\nstatic bool  shallow = false;\nstatic const char  *dir_path = NULL;\n\nstatic int\ndir_options(int argc, char **argv)\n{\n    if (argc == 3) {\n        if (streq(argv[1], \"--shallow\")) {\n            shallow = true;\n            dir_path = argv[2];\n            return 3;\n        } else if (streq(argv[1], \"--only-files\")) {\n            only_files = true;\n            dir_path = argv[2];\n            return 3;\n        }\n    }\n\n    else if (argc == 2) {\n        dir_path = argv[1];\n        return 2;\n    }\n\n    printf(\"Invalid usage.\\n\");\n    exit(EXIT_FAILURE);\n}\n\nstatic size_t  indent = 0;\n\nstatic void\nprint_indent(void)\n{\n    size_t  i;\n    for (i = 0; i < indent; i++) {\n        printf(\"  \");\n    }\n}\n\nstatic int\nenter_directory(struct cork_dir_walker *walker, const char *full_path,\n                const char *rel_path, const char *base_name)\n{\n    print_indent();\n    if (shallow) {\n        printf(\"Skipping %s\\n\", rel_path);\n        return CORK_SKIP_DIRECTORY;\n    } else if (only_files) {\n        return 0;\n    } else {\n        printf(\"Entering %s (%s)\\n\", base_name, rel_path);\n        indent++;\n        return 0;\n    }\n}\n\nstatic int\nprint_file(struct cork_dir_walker *walker, const char *full_path,\n           const char *rel_path, const char *base_name)\n{\n    if (only_files) {\n        printf(\"%s\\n\", rel_path);\n    } else {\n        print_indent();\n        printf(\"%s (%s) (%s)\\n\", base_name, rel_path, full_path);\n    }\n    return 0;\n}\n\nstatic int\nleave_directory(struct cork_dir_walker *walker, const char *full_path,\n                const char *rel_path, const char *base_name)\n{\n    if (!only_files) {\n        indent--;\n        print_indent();\n        printf(\"Leaving %s\\n\", rel_path);\n    }\n    return 0;\n}\n\nstatic struct cork_dir_walker  walker = {\n    enter_directory,\n    print_file,\n    leave_directory\n};\n\nstatic void\ndir_run(int argc, char **argv)\n{\n    ri_check_exit(cork_walk_directory(dir_path, &walker));\n    exit(EXIT_SUCCESS);\n}\n\nstatic struct cork_command  dir =\n    cork_leaf_command(\"dir\", \"Print the contents of a directory\",\n                      \"[--shallow] <path>\",\n                      \"Prints the contents of a directory.\\n\",\n                      dir_options, dir_run);\n\n\n/*-----------------------------------------------------------------------\n * Cleanup functions\n */\n\n#define define_cleanup_function(id) \\\nstatic void \\\ncleanup_##id(void) \\\n{ \\\n    printf(\"Cleanup function \" #id \"\\n\"); \\\n}\n\ndefine_cleanup_function(0);\ndefine_cleanup_function(1);\ndefine_cleanup_function(2);\ndefine_cleanup_function(3);\ndefine_cleanup_function(4);\ndefine_cleanup_function(5);\n\nstatic void\ncleanup_run(int argc, char **argv)\n{\n    cork_cleanup_at_exit(10, cleanup_1);\n    cork_cleanup_at_exit( 0, cleanup_0);\n    cork_cleanup_at_exit(50, cleanup_5);\n    cork_cleanup_at_exit(20, cleanup_2);\n    cork_cleanup_at_exit(40, cleanup_4);\n    cork_cleanup_at_exit(30, cleanup_3);\n}\n\nstatic struct cork_command  cleanup =\n    cork_leaf_command(\"cleanup\", \"Test process cleanup functions\", \"\",\n                      \"Test process cleanup functions.\\n\",\n                      NULL, cleanup_run);\n\n\n/*-----------------------------------------------------------------------\n * Root command\n */\n\n/* [root] cork-test */\n\nstatic struct cork_command  *root_subcommands[] = {\n    &c1, &c2,\n    &pwd,\n    &mkdir_cmd,\n    &rm_cmd,\n    &find,\n    &paths,\n    &dir,\n    &sub,\n    &cleanup,\n    NULL\n};\n\nstatic struct cork_command  root_command =\n    cork_command_set(\"cork-test\", NULL, NULL, root_subcommands);\n\n\n/*-----------------------------------------------------------------------\n * Entry point\n */\n\nint\nmain(int argc, char **argv)\n{\n    return cork_command_main(&root_command, argc, argv);\n}\n"
  },
  {
    "path": "src/libcork/cli/commands.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"libcork/cli.h\"\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n\n\n#define streq(a,b) (strcmp((a), (b)) == 0)\n\nstatic struct cork_buffer  breadcrumbs_buf = CORK_BUFFER_INIT();\n\nstatic void\ncork_command_add_breadcrumb(struct cork_command *command)\n{\n    cork_buffer_append_printf(&breadcrumbs_buf, \" %s\", command->name);\n}\n\n#define cork_command_breadcrumbs() ((char *) breadcrumbs_buf.buf)\n\nstatic void\ncork_command_run(struct cork_command *command, int argc, char **argv);\n\nstatic struct cork_command *\ncork_command_set_get_subcommand(struct cork_command *command,\n                                const char *command_name)\n{\n    struct cork_command  **curr;\n    for (curr = command->set; *curr != NULL; curr++) {\n        if (streq(command_name, (*curr)->name)) {\n            return *curr;\n        }\n    }\n    return NULL;\n}\n\nstatic void\ncork_command_set_show_help(struct cork_command *command)\n{\n    size_t  max_length = 0;\n    struct cork_command  **curr;\n\n    /* Calculate the length of the longest command name. */\n    for (curr = command->set; *curr != NULL; curr++) {\n        size_t  len = strlen((*curr)->name);\n        if (len > max_length) {\n            max_length = len;\n        }\n    }\n\n    /* Then print out the available commands. */\n    printf(\"Usage:%s <command> [<options>]\\n\"\n           \"\\nAvailable commands:\\n\",\n           cork_command_breadcrumbs());\n\n    for (curr = command->set; *curr != NULL; curr++) {\n        printf(\"  %*s\", (int) -max_length, (*curr)->name);\n        if ((*curr)->short_desc != NULL) {\n            printf(\"  %s\\n\", (*curr)->short_desc);\n        } else {\n            printf(\"\\n\");\n        }\n    }\n}\n\nstatic void\ncork_command_leaf_show_help(struct cork_command *command)\n{\n    printf(\"Usage:%s\", cork_command_breadcrumbs());\n    if (command->usage_suffix != NULL) {\n        printf(\" %s\", command->usage_suffix);\n    }\n    if (command->full_help != NULL) {\n        printf(\"\\n\\n%s\", command->full_help);\n    } else {\n        printf(\"\\n\");\n    }\n}\n\nvoid\ncork_command_show_help(struct cork_command *command, const char *message)\n{\n    if (message != NULL) {\n        printf(\"%s\\n\", message);\n    }\n\n    if (command->type == CORK_COMMAND_SET) {\n        cork_command_set_show_help(command);\n    } else if (command->type == CORK_LEAF_COMMAND) {\n        cork_command_leaf_show_help(command);\n    }\n}\n\nstatic void\ncork_command_set_run_help(struct cork_command *command, int argc, char **argv)\n{\n    /* When we see the help command when processing a command set, we use any\n     * remaining arguments to identifity which subcommand the user wants help\n     * with. */\n\n    /* Skip over the name of the command set */\n    argc--;\n    argv++;\n\n    while (argc > 0 && command->type == CORK_COMMAND_SET) {\n        struct cork_command  *subcommand =\n            cork_command_set_get_subcommand(command, argv[0]);\n        if (subcommand == NULL) {\n            printf(\"Unknown command \\\"%s\\\".\\n\"\n                   \"Usage:%s <command> [<options>]\\n\",\n                   argv[0], cork_command_breadcrumbs());\n            exit(EXIT_FAILURE);\n        }\n\n        cork_command_add_breadcrumb(subcommand);\n        command = subcommand;\n        argc--;\n        argv++;\n    }\n\n    cork_command_show_help(command, NULL);\n}\n\nstatic void\ncork_command_set_run(struct cork_command *command, int argc, char **argv)\n{\n    const char  *command_name;\n    struct cork_command  *subcommand;\n\n    if (argc == 0) {\n        printf(\"No command given.\\n\");\n        cork_command_set_show_help(command);\n        exit(EXIT_FAILURE);\n    }\n\n    command_name = argv[0];\n\n    /* The \"help\" command is special. */\n    if (streq(command_name, \"help\")) {\n        cork_command_set_run_help(command, argc, argv);\n        return;\n    }\n\n    /* Otherwise look for a real subcommand with this name. */\n    subcommand = cork_command_set_get_subcommand(command, command_name);\n    if (subcommand == NULL) {\n        printf(\"Unknown command \\\"%s\\\".\\n\"\n               \"Usage:%s <command> [<options>]\\n\",\n               command_name, cork_command_breadcrumbs());\n        exit(EXIT_FAILURE);\n    } else {\n        cork_command_run(subcommand, argc, argv);\n    }\n}\n\nstatic void\ncork_command_leaf_run(struct cork_command *command, int argc, char **argv)\n{\n    command->run(argc, argv);\n}\n\nstatic void\ncork_command_cleanup(void)\n{\n    cork_buffer_done(&breadcrumbs_buf);\n}\n\nstatic void\ncork_command_run(struct cork_command *command, int argc, char **argv)\n{\n    cork_command_add_breadcrumb(command);\n\n    /* If the gives the --help option at this point, describe the current\n     * command. */\n    if (argc >= 2 && (streq(argv[1], \"--help\") || streq(argv[1], \"-h\"))) {\n        cork_command_show_help(command, NULL);\n        return;\n    }\n\n    /* Otherwise let the command parse any options that occur here. */\n    if (command->parse_options != NULL) {\n        int  option_count = command->parse_options(argc, argv);\n        argc -= option_count;\n        argv += option_count;\n    } else {\n        argc--;\n        argv++;\n    }\n\n    switch (command->type) {\n        case CORK_COMMAND_SET:\n            cork_command_set_run(command, argc, argv);\n            return;\n\n        case CORK_LEAF_COMMAND:\n            cork_command_leaf_run(command, argc, argv);\n            return;\n\n        default:\n            cork_unreachable();\n    }\n}\n\n\nint\ncork_command_main(struct cork_command *root, int argc, char **argv)\n{\n    /* Clean up after ourselves when the command finishes. */\n    atexit(cork_command_cleanup);\n\n    /* Run the root command. */\n    cork_command_run(root, argc, argv);\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "src/libcork/core/allocator.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/attributes.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/os/process.h\"\n\n\n/*-----------------------------------------------------------------------\n * Allocator interface\n */\n\nstruct cork_alloc_priv {\n    struct cork_alloc  public;\n    struct cork_alloc_priv  *next;\n};\n\nstatic void *\ncork_alloc__default_calloc(const struct cork_alloc *alloc,\n                           size_t count, size_t size)\n{\n    void  *result = cork_alloc_xcalloc(alloc, count, size);\n    if (CORK_UNLIKELY(result == NULL)) {\n        abort();\n    }\n    return result;\n}\n\nstatic void *\ncork_alloc__default_malloc(const struct cork_alloc *alloc, size_t size)\n{\n    void  *result = cork_alloc_xmalloc(alloc, size);\n    if (CORK_UNLIKELY(result == NULL)) {\n        abort();\n    }\n    return result;\n}\n\nstatic void *\ncork_alloc__default_realloc(const struct cork_alloc *alloc, void *ptr,\n                            size_t old_size, size_t new_size)\n{\n    void  *result = cork_alloc_xrealloc(alloc, ptr, old_size, new_size);\n    if (CORK_UNLIKELY(result == NULL)) {\n        abort();\n    }\n    return result;\n}\n\nstatic void *\ncork_alloc__default_xcalloc(const struct cork_alloc *alloc,\n                            size_t count, size_t size)\n{\n    void  *result;\n    assert(count < (SIZE_MAX / size));\n    result = cork_alloc_xmalloc(alloc, count * size);\n    if (result != NULL) {\n        memset(result, 0, count * size);\n    }\n    return result;\n}\n\nstatic void *\ncork_alloc__default_xmalloc(const struct cork_alloc *alloc, size_t size)\n{\n    cork_abort(\"%s isn't defined\", \"cork_alloc:xmalloc\");\n}\n\nstatic void *\ncork_alloc__default_xrealloc(const struct cork_alloc *alloc, void *ptr,\n                             size_t old_size, size_t new_size)\n{\n    void  *result = cork_alloc_xmalloc(alloc, new_size);\n    if (CORK_LIKELY(result != NULL) && ptr != NULL) {\n        size_t  min_size = (new_size < old_size)? new_size: old_size;\n        memcpy(result, ptr, min_size);\n        cork_alloc_free(alloc, ptr, old_size);\n    }\n    return result;\n}\n\nstatic void\ncork_alloc__default_free(const struct cork_alloc *alloc, void *ptr, size_t size)\n{\n    cork_abort(\"%s isn't defined\", \"cork_alloc:free\");\n}\n\nstatic bool  cleanup_registered = false;\nstatic struct cork_alloc_priv  *all_allocs = NULL;\n\nstatic void\ncork_alloc_free_alloc(struct cork_alloc_priv *alloc)\n{\n    cork_free_user_data(&alloc->public);\n    cork_alloc_delete(alloc->public.parent, struct cork_alloc_priv, alloc);\n}\n\nstatic void\ncork_alloc_free_all(void)\n{\n    struct cork_alloc_priv  *curr;\n    struct cork_alloc_priv  *next;\n    for (curr = all_allocs; curr != NULL; curr = next) {\n        next = curr->next;\n        cork_alloc_free_alloc(curr);\n    }\n}\n\nstatic void\ncork_alloc_register_cleanup(void)\n{\n    if (CORK_UNLIKELY(!cleanup_registered)) {\n        /* We don't use cork_cleanup because that requires the allocators to\n         * have already been set up!  (atexit calls its functions in reverse\n         * order, and this one will be registered before cork_cleanup's, which\n         * makes it safe for cork_cleanup functions to still use the allocator,\n         * since the allocator atexit function will be called last.) */\n        atexit(cork_alloc_free_all);\n        cleanup_registered = true;\n    }\n}\n\nstruct cork_alloc *\ncork_alloc_new_alloc(const struct cork_alloc *parent)\n{\n    struct cork_alloc_priv  *alloc =\n        cork_alloc_new(parent, struct cork_alloc_priv);\n    alloc->public.parent = parent;\n    alloc->public.user_data = NULL;\n    alloc->public.free_user_data = NULL;\n    alloc->public.calloc = cork_alloc__default_calloc;\n    alloc->public.malloc = cork_alloc__default_malloc;\n    alloc->public.realloc = cork_alloc__default_realloc;\n    alloc->public.xcalloc = cork_alloc__default_xcalloc;\n    alloc->public.xmalloc = cork_alloc__default_xmalloc;\n    alloc->public.xrealloc = cork_alloc__default_xrealloc;\n    alloc->public.free = cork_alloc__default_free;\n\n    cork_alloc_register_cleanup();\n    alloc->next = all_allocs;\n    all_allocs = alloc;\n\n    return &alloc->public;\n}\n\n\nvoid\ncork_alloc_set_user_data(struct cork_alloc *alloc,\n                         void *user_data, cork_free_f free_user_data)\n{\n    cork_free_user_data(alloc);\n    alloc->user_data = user_data;\n    alloc->free_user_data = free_user_data;\n}\n\nvoid\ncork_alloc_set_calloc(struct cork_alloc *alloc, cork_alloc_calloc_f calloc)\n{\n    alloc->calloc = calloc;\n}\n\nvoid\ncork_alloc_set_malloc(struct cork_alloc *alloc, cork_alloc_malloc_f malloc)\n{\n    alloc->malloc = malloc;\n}\n\nvoid\ncork_alloc_set_realloc(struct cork_alloc *alloc, cork_alloc_realloc_f realloc)\n{\n    alloc->realloc = realloc;\n}\n\nvoid\ncork_alloc_set_xcalloc(struct cork_alloc *alloc, cork_alloc_calloc_f xcalloc)\n{\n    alloc->xcalloc = xcalloc;\n}\n\nvoid\ncork_alloc_set_xmalloc(struct cork_alloc *alloc, cork_alloc_malloc_f xmalloc)\n{\n    alloc->xmalloc = xmalloc;\n}\n\nvoid\ncork_alloc_set_xrealloc(struct cork_alloc *alloc,\n                        cork_alloc_realloc_f xrealloc)\n{\n    alloc->xrealloc = xrealloc;\n}\n\nvoid\ncork_alloc_set_free(struct cork_alloc *alloc, cork_alloc_free_f free)\n{\n    alloc->free = free;\n}\n\n\n/*-----------------------------------------------------------------------\n * Allocating strings\n */\n\nstatic inline const char *\nstrndup_internal(const struct cork_alloc *alloc,\n                 const char *str, size_t len)\n{\n    char  *dest;\n    size_t  allocated_size = len + sizeof(size_t) + 1;\n    size_t  *new_str = cork_alloc_malloc(alloc, allocated_size);\n    *new_str = len;\n    dest = (char *) (void *) (new_str + 1);\n    memcpy(dest, str, len);\n    dest[len] = '\\0';\n    return dest;\n}\n\nconst char *\ncork_alloc_strdup(const struct cork_alloc *alloc, const char *str)\n{\n    return strndup_internal(alloc, str, strlen(str));\n}\n\nconst char *\ncork_alloc_strndup(const struct cork_alloc *alloc,\n                   const char *str, size_t size)\n{\n    return strndup_internal(alloc, str, size);\n}\n\nstatic inline const char *\nxstrndup_internal(const struct cork_alloc *alloc,\n                  const char *str, size_t len)\n{\n    size_t  allocated_size = len + sizeof(size_t) + 1;\n    size_t  *new_str = cork_alloc_xmalloc(alloc, allocated_size);\n    if (CORK_UNLIKELY(new_str == NULL)) {\n        return NULL;\n    } else {\n        char  *dest;\n        *new_str = len;\n        dest = (char *) (void *) (new_str + 1);\n        memcpy(dest, str, len);\n        dest[len] = '\\0';\n        return dest;\n    }\n}\n\nconst char *\ncork_alloc_xstrdup(const struct cork_alloc *alloc, const char *str)\n{\n    return xstrndup_internal(alloc, str, strlen(str));\n}\n\nconst char *\ncork_alloc_xstrndup(const struct cork_alloc *alloc,\n                    const char *str, size_t size)\n{\n    return xstrndup_internal(alloc, str, size);\n}\n\nvoid\ncork_alloc_strfree(const struct cork_alloc *alloc, const char *str)\n{\n    size_t* base = ((size_t*) str) - 1;\n    size_t len = *base;\n    size_t allocated_size = len + sizeof(size_t) + 1;\n    cork_alloc_free(alloc, base, allocated_size);\n}\n\n\n/*-----------------------------------------------------------------------\n * stdlib allocator\n */\n\nstatic void *\ncork_stdlib_alloc__calloc(const struct cork_alloc *alloc,\n                          size_t count, size_t size)\n{\n    void  *result = calloc(count, size);\n    if (CORK_UNLIKELY(result == NULL)) {\n        abort();\n    }\n    return result;\n}\n\nstatic void *\ncork_stdlib_alloc__malloc(const struct cork_alloc *alloc, size_t size)\n{\n    void  *result = malloc(size);\n    if (CORK_UNLIKELY(result == NULL)) {\n        abort();\n    }\n    return result;\n}\n\nstatic void *\ncork_stdlib_alloc__realloc(const struct cork_alloc *alloc, void *ptr,\n                           size_t old_size, size_t new_size)\n{\n    /* Technically we don't really need to free `ptr` if the reallocation fails,\n     * since we'll abort the process immediately after.  But my sense of\n     * cleanliness makes me do it anyway. */\n\n#if CORK_HAVE_REALLOCF\n    void  *result = reallocf(ptr, new_size);\n    if (result == NULL) {\n        abort();\n    }\n    return result;\n#else\n    void  *result = realloc(ptr, new_size);\n    if (result == NULL) {\n        free(ptr);\n        abort();\n    }\n    return result;\n#endif\n}\n\nstatic void *\ncork_stdlib_alloc__xcalloc(const struct cork_alloc *alloc,\n                           size_t count, size_t size)\n{\n    return calloc(count, size);\n}\n\nstatic void *\ncork_stdlib_alloc__xmalloc(const struct cork_alloc *alloc, size_t size)\n{\n    return malloc(size);\n}\n\nstatic void *\ncork_stdlib_alloc__xrealloc(const struct cork_alloc *alloc, void *ptr,\n                            size_t old_size, size_t new_size)\n{\n    return realloc(ptr, new_size);\n}\n\nstatic void\ncork_stdlib_alloc__free(const struct cork_alloc *alloc, void *ptr, size_t size)\n{\n    free(ptr);\n}\n\n\nstatic const struct cork_alloc  default_allocator = {\n    NULL,\n    NULL,\n    NULL,\n    cork_stdlib_alloc__calloc,\n    cork_stdlib_alloc__malloc,\n    cork_stdlib_alloc__realloc,\n    cork_stdlib_alloc__xcalloc,\n    cork_stdlib_alloc__xmalloc,\n    cork_stdlib_alloc__xrealloc,\n    cork_stdlib_alloc__free\n};\n\n\n/*-----------------------------------------------------------------------\n * Customizing libcork's allocator\n */\n\nconst struct cork_alloc  *cork_allocator = &default_allocator;\n\nvoid\ncork_set_allocator(const struct cork_alloc *alloc)\n{\n    cork_allocator = alloc;\n}\n\n\n/*-----------------------------------------------------------------------\n * Debugging allocator\n */\n\nstatic void *\ncork_debug_alloc__xmalloc(const struct cork_alloc *alloc, size_t size)\n{\n    size_t  real_size = size + sizeof(size_t);\n    size_t  *base = cork_alloc_xmalloc(alloc->parent, real_size);\n    *base = size;\n    return base + 1;\n}\n\nstatic void\ncork_debug_alloc__free(const struct cork_alloc *alloc, void *ptr,\n                       size_t expected_size)\n{\n    size_t  *base = ((size_t *) ptr) - 1;\n    size_t  actual_size = *base;\n    size_t  real_size = actual_size + sizeof(size_t);\n    if (CORK_UNLIKELY(actual_size != expected_size)) {\n        cork_abort\n            (\"Incorrect size when freeing pointer (got %zu, expected %zu)\",\n             expected_size, actual_size);\n    }\n    cork_alloc_free(alloc->parent, base, real_size);\n}\n\nstruct cork_alloc *\ncork_debug_alloc_new(const struct cork_alloc *parent)\n{\n    struct cork_alloc  *debug = cork_alloc_new_alloc(parent);\n    cork_alloc_set_xmalloc(debug, cork_debug_alloc__xmalloc);\n    cork_alloc_set_free(debug, cork_debug_alloc__free);\n    return debug;\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nvoid *\ncork_alloc_calloc(const struct cork_alloc *alloc, size_t count, size_t size);\n\nvoid *\ncork_alloc_malloc(const struct cork_alloc *alloc, size_t size);\n\nvoid *\ncork_alloc_realloc(const struct cork_alloc *alloc, void *ptr,\n                   size_t old_size, size_t new_size);\n\nvoid *\ncork_alloc_xcalloc(const struct cork_alloc *alloc, size_t count, size_t size);\n\nvoid *\ncork_alloc_xmalloc(const struct cork_alloc *alloc, size_t size);\n\nvoid *\ncork_alloc_xrealloc(const struct cork_alloc *alloc, void *ptr,\n                    size_t old_size, size_t new_size);\n\nvoid *\ncork_alloc_xreallocf(const struct cork_alloc *alloc, void *ptr,\n                     size_t old_size, size_t new_size);\n\nvoid\ncork_alloc_free(const struct cork_alloc *alloc, void *ptr, size_t size);\n\nvoid\ncork_alloc_cfree(const struct cork_alloc *alloc, void *ptr,\n                 size_t count, size_t size);\n\nvoid *\ncork_calloc(size_t count, size_t size);\n\nvoid *\ncork_malloc(size_t size);\n\nvoid *\ncork_realloc(void *ptr, size_t old_size, size_t new_size);\n\nvoid *\ncork_xcalloc(size_t count, size_t size);\n\nvoid *\ncork_xmalloc(size_t size);\n\nvoid *\ncork_xrealloc(void *ptr, size_t old_size, size_t new_size);\n\nvoid *\ncork_xreallocf(void *ptr, size_t old_size, size_t new_size);\n\nvoid\ncork_free(void *ptr, size_t size);\n\nvoid\ncork_cfree(void *ptr, size_t count, size_t size);\n\nconst char *\ncork_strdup(const char *str);\n\nconst char *\ncork_strndup(const char *str, size_t size);\n\nconst char *\ncork_xstrdup(const char *str);\n\nconst char *\ncork_xstrndup(const char *str, size_t size);\n\nvoid\ncork_strfree(const char *str);\n\nsize_t\ncork_strlen(const char *str);\n"
  },
  {
    "path": "src/libcork/core/error.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <errno.h>\n#include <stdarg.h>\n#include <string.h>\n\n#include \"libcork/config.h\"\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/os/process.h\"\n#include \"libcork/threads/basics.h\"\n\n\n/*-----------------------------------------------------------------------\n * Life cycle\n */\n\nstruct cork_error {\n    cork_error  code;\n    struct cork_buffer  *message;\n    struct cork_buffer  *other;\n    struct cork_buffer  buf1;\n    struct cork_buffer  buf2;\n    struct cork_error  *next;\n};\n\nstatic struct cork_error *\ncork_error_new(void)\n{\n    struct cork_error  *error = cork_new(struct cork_error);\n    error->code = CORK_ERROR_NONE;\n    cork_buffer_init(&error->buf1);\n    cork_buffer_init(&error->buf2);\n    error->message = &error->buf1;\n    error->other = &error->buf2;\n    return error;\n}\n\nstatic void\ncork_error_free(struct cork_error *error)\n{\n    cork_buffer_done(&error->buf1);\n    cork_buffer_done(&error->buf2);\n    cork_delete(struct cork_error, error);\n}\n\n\nstatic struct cork_error * volatile  errors;\n\ncork_once_barrier(cork_error_list);\n\nstatic void\ncork_error_list_done(void)\n{\n    struct cork_error  *curr;\n    struct cork_error  *next;\n    for (curr = errors; curr != NULL; curr = next) {\n        next = curr->next;\n        cork_error_free(curr);\n    }\n}\n\nstatic void\ncork_error_list_init(void)\n{\n    cork_cleanup_at_exit(0, cork_error_list_done);\n}\n\n\ncork_tls(struct cork_error *, cork_error_);\n\nstatic struct cork_error *\ncork_error_get(void)\n{\n    struct cork_error  **error_ptr = cork_error__get();\n    if (CORK_UNLIKELY(*error_ptr == NULL)) {\n        struct cork_error  *old_head;\n        struct cork_error  *error = cork_error_new();\n        cork_once(cork_error_list, cork_error_list_init());\n        do {\n            old_head = errors;\n            error->next = old_head;\n        } while (cork_ptr_cas(&errors, old_head, error) != old_head);\n        *error_ptr = error;\n        return error;\n    } else {\n        return *error_ptr;\n    }\n}\n\n\n/*-----------------------------------------------------------------------\n * Public error API\n */\n\nbool\ncork_error_occurred(void)\n{\n    struct cork_error  *error = cork_error_get();\n    return error->code != CORK_ERROR_NONE;\n}\n\ncork_error\ncork_error_code(void)\n{\n    struct cork_error  *error = cork_error_get();\n    return error->code;\n}\n\nconst char *\ncork_error_message(void)\n{\n    struct cork_error  *error = cork_error_get();\n    return error->message->buf;\n}\n\nvoid\ncork_error_clear(void)\n{\n    struct cork_error  *error = cork_error_get();\n    error->code = CORK_ERROR_NONE;\n    cork_buffer_clear(error->message);\n}\n\nvoid\ncork_error_set_printf(cork_error code, const char *format, ...)\n{\n    va_list  args;\n    struct cork_error  *error = cork_error_get();\n    error->code = code;\n    va_start(args, format);\n    cork_buffer_vprintf(error->message, format, args);\n    va_end(args);\n}\n\nvoid\ncork_error_set_string(cork_error code, const char *str)\n{\n    struct cork_error  *error = cork_error_get();\n    error->code = code;\n    cork_buffer_set_string(error->message, str);\n}\n\nvoid\ncork_error_set_vprintf(cork_error code, const char *format, va_list args)\n{\n    struct cork_error  *error = cork_error_get();\n    error->code = code;\n    cork_buffer_vprintf(error->message, format, args);\n}\n\nvoid\ncork_error_prefix_printf(const char *format, ...)\n{\n    va_list  args;\n    struct cork_error  *error = cork_error_get();\n    struct cork_buffer  *temp;\n    va_start(args, format);\n    cork_buffer_vprintf(error->other, format, args);\n    va_end(args);\n    cork_buffer_append_copy(error->other, error->message);\n    temp = error->other;\n    error->other = error->message;\n    error->message = temp;\n}\n\nvoid\ncork_error_prefix_string(const char *str)\n{\n    struct cork_error  *error = cork_error_get();\n    struct cork_buffer  *temp;\n    cork_buffer_set_string(error->other, str);\n    cork_buffer_append_copy(error->other, error->message);\n    temp = error->other;\n    error->other = error->message;\n    error->message = temp;\n}\n\nvoid\ncork_error_prefix_vprintf(const char *format, va_list args)\n{\n    struct cork_error  *error = cork_error_get();\n    struct cork_buffer  *temp;\n    cork_buffer_vprintf(error->other, format, args);\n    cork_buffer_append_copy(error->other, error->message);\n    temp = error->other;\n    error->other = error->message;\n    error->message = temp;\n}\n\n\n/*-----------------------------------------------------------------------\n * Deprecated\n */\n\nvoid\ncork_error_set(uint32_t error_class, unsigned int error_code,\n               const char *format, ...)\n{\n    /* Create a fallback error code that's most likely not very useful. */\n    va_list  args;\n    va_start(args, format);\n    cork_error_set_vprintf(error_class + error_code, format, args);\n    va_end(args);\n}\n\nvoid\ncork_error_prefix(const char *format, ...)\n{\n    va_list  args;\n    va_start(args, format);\n    cork_error_prefix_vprintf(format, args);\n    va_end(args);\n}\n\n\n/*-----------------------------------------------------------------------\n * Built-in errors\n */\n\nvoid\ncork_system_error_set_explicit(int err)\n{\n    cork_error_set_string(err, strerror(err));\n}\n\nvoid\ncork_system_error_set(void)\n{\n    cork_error_set_string(errno, strerror(errno));\n}\n\nvoid\ncork_unknown_error_set_(const char *location)\n{\n    cork_error_set_printf(CORK_UNKNOWN_ERROR, \"Unknown error in %s\", location);\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nvoid *\ncork_abort_if_null_(void *ptr, const char *msg, const char *func,\n                    const char *file, unsigned int line);\n"
  },
  {
    "path": "src/libcork/core/gc.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n\n#include \"libcork/config/config.h\"\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/gc.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/dllist.h\"\n#include \"libcork/threads/basics.h\"\n\n\n#if !defined(CORK_DEBUG_GC)\n#define CORK_DEBUG_GC  0\n#endif\n\n#if CORK_DEBUG_GC\n#include <stdio.h>\n#define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define DEBUG(...) /* no debug messages */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * GC context life cycle\n */\n\n#define ROOTS_SIZE  1024\n\n/* An internal structure allocated with every garbage-collected object. */\nstruct cork_gc_header;\n\n/* A garbage collector context. */\nstruct cork_gc {\n    /* The number of used entries in roots. */\n    size_t  root_count;\n    /* The possible roots of garbage cycles */\n    struct cork_gc_header  *roots[ROOTS_SIZE];\n};\n\ncork_tls(struct cork_gc, cork_gc);\n\nstatic void\ncork_gc_collect_cycles(struct cork_gc *gc);\n\n\n/*-----------------------------------------------------------------------\n * Garbage collection functions\n */\n\nstruct cork_gc_header {\n    /* The current reference count for this object, along with its color\n     * during the mark/sweep process. */\n    volatile int  ref_count_color;\n\n    /* The allocated size of this garbage-collected object (including\n     * the header). */\n    size_t  allocated_size;\n\n    /* The garbage collection interface for this object. */\n    struct cork_gc_obj_iface  *iface;\n};\n\n/*\n * Structure of ref_count_color:\n *\n *   +-----+---+---+---+---+---+\n *   | ... | 4 | 3 | 2 | 1 | 0 |\n *   +-----+---+---+---+---+---+\n *      ref_count    |   color\n *                   |\n *        buffered --/\n */\n\n#define cork_gc_ref_count_color(count, buffered, color) \\\n    (((count) << 3) | ((buffered) << 2) | (color))\n\n#define cork_gc_get_ref_count(hdr) \\\n    ((hdr)->ref_count_color >> 3)\n\n#define cork_gc_inc_ref_count(hdr) \\\n    do { \\\n        (hdr)->ref_count_color += (1 << 3); \\\n    } while (0)\n\n#define cork_gc_dec_ref_count(hdr) \\\n    do { \\\n        (hdr)->ref_count_color -= (1 << 3); \\\n    } while (0)\n\n#define cork_gc_get_color(hdr) \\\n    ((hdr)->ref_count_color & 0x3)\n\n#define cork_gc_set_color(hdr, color) \\\n    do { \\\n        (hdr)->ref_count_color = \\\n            ((hdr)->ref_count_color & ~0x3) | (color & 0x3); \\\n    } while (0)\n\n#define cork_gc_get_buffered(hdr) \\\n    (((hdr)->ref_count_color & 0x4) != 0)\n\n#define cork_gc_set_buffered(hdr, buffered) \\\n    do { \\\n        (hdr)->ref_count_color = \\\n            ((hdr)->ref_count_color & ~0x4) | (((buffered) & 1) << 2); \\\n    } while (0)\n\n#define cork_gc_free(hdr) \\\n    do { \\\n        if ((hdr)->iface->free != NULL) { \\\n            (hdr)->iface->free(cork_gc_get_object((hdr))); \\\n        } \\\n        cork_free((hdr), (hdr)->allocated_size); \\\n    } while (0)\n\n#define cork_gc_recurse(gc, hdr, recurser) \\\n    do { \\\n        if ((hdr)->iface->recurse != NULL) { \\\n            (hdr)->iface->recurse \\\n                ((gc), cork_gc_get_object((hdr)), (recurser), NULL); \\\n        } \\\n    } while (0)\n\nenum cork_gc_color {\n    /* In use or free */\n    GC_BLACK = 0,\n    /* Possible member of garbage cycle */\n    GC_GRAY = 1,\n    /* Member of garbage cycle */\n    GC_WHITE = 2,\n    /* Possible root of garbage cycle */\n    GC_PURPLE = 3\n};\n\n#define cork_gc_get_header(obj) \\\n    (((struct cork_gc_header *) (obj)) - 1)\n\n#define cork_gc_get_object(hdr) \\\n    ((void *) (((struct cork_gc_header *) (hdr)) + 1))\n\n\nvoid\ncork_gc_init(void)\n{\n    cork_gc_get();\n}\n\nvoid\ncork_gc_done(void)\n{\n    cork_gc_collect_cycles(cork_gc_get());\n}\n\nvoid *\ncork_gc_alloc(size_t instance_size, struct cork_gc_obj_iface *iface)\n{\n    size_t  full_size = instance_size + sizeof(struct cork_gc_header);\n    DEBUG(\"Allocating %zu (%zu) bytes\\n\", instance_size, full_size);\n    struct cork_gc_header  *header = cork_malloc(full_size);\n    DEBUG(\"  Result is %p[%p]\\n\", cork_gc_get_object(header), header);\n    header->ref_count_color = cork_gc_ref_count_color(1, false, GC_BLACK);\n    header->allocated_size = full_size;\n    header->iface = iface;\n    return cork_gc_get_object(header);\n}\n\nvoid *\ncork_gc_incref(void *obj)\n{\n    if (obj != NULL) {\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        cork_gc_inc_ref_count(header);\n        DEBUG(\"Incrementing %p -> %d\\n\",\n              obj, cork_gc_get_ref_count(header));\n        cork_gc_set_color(header, GC_BLACK);\n    }\n    return obj;\n}\n\nstatic void\ncork_gc_decref_step(struct cork_gc *gc, void *obj, void *ud);\n\nstatic void\ncork_gc_release(struct cork_gc *gc, struct cork_gc_header *header)\n{\n    cork_gc_recurse(gc, header, cork_gc_decref_step);\n    cork_gc_set_color(header, GC_BLACK);\n    if (!cork_gc_get_buffered(header)) {\n        cork_gc_free(header);\n    }\n}\n\nstatic void\ncork_gc_possible_root(struct cork_gc *gc, struct cork_gc_header *header)\n{\n    if (cork_gc_get_color(header) != GC_PURPLE) {\n        DEBUG(\"  Possible garbage cycle root\\n\");\n        cork_gc_set_color(header, GC_PURPLE);\n        if (!cork_gc_get_buffered(header)) {\n            cork_gc_set_buffered(header, true);\n            if (gc->root_count >= ROOTS_SIZE) {\n                cork_gc_collect_cycles(gc);\n            }\n            gc->roots[gc->root_count++] = header;\n        }\n    } else {\n        DEBUG(\"  Already marked as possible garbage cycle root\\n\");\n    }\n}\n\nstatic void\ncork_gc_decref_step(struct cork_gc *gc, void *obj, void *ud)\n{\n    if (obj != NULL) {\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        cork_gc_dec_ref_count(header);\n        DEBUG(\"Decrementing %p -> %d\\n\",\n              obj, cork_gc_get_ref_count(header));\n        if (cork_gc_get_ref_count(header) == 0) {\n            DEBUG(\"  Releasing %p\\n\", header);\n            cork_gc_release(gc, header);\n        } else {\n            cork_gc_possible_root(gc, header);\n        }\n    }\n}\n\nvoid\ncork_gc_decref(void *obj)\n{\n    if (obj != NULL) {\n        struct cork_gc  *gc = cork_gc_get();\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        cork_gc_dec_ref_count(header);\n        DEBUG(\"Decrementing %p -> %d\\n\",\n              obj, cork_gc_get_ref_count(header));\n        if (cork_gc_get_ref_count(header) == 0) {\n            DEBUG(\"  Releasing %p\\n\", header);\n            cork_gc_release(gc, header);\n        } else {\n            cork_gc_possible_root(gc, header);\n        }\n    }\n}\n\n\nstatic void\ncork_gc_mark_gray_step(struct cork_gc *gc, void *obj, void *ud);\n\nstatic void\ncork_gc_mark_gray(struct cork_gc *gc, struct cork_gc_header *header)\n{\n    if (cork_gc_get_color(header) != GC_GRAY) {\n        DEBUG(\"      Setting color to gray\\n\");\n        cork_gc_set_color(header, GC_GRAY);\n        cork_gc_recurse(gc, header, cork_gc_mark_gray_step);\n    }\n}\n\nstatic void\ncork_gc_mark_gray_step(struct cork_gc *gc, void *obj, void *ud)\n{\n    if (obj != NULL) {\n        DEBUG(\"    cork_gc_mark_gray(%p)\\n\", obj);\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        cork_gc_dec_ref_count(header);\n        DEBUG(\"      Reference count now %d\\n\", cork_gc_get_ref_count(header));\n        cork_gc_mark_gray(gc, header);\n    }\n}\n\nstatic void\ncork_gc_mark_roots(struct cork_gc *gc)\n{\n    size_t  i;\n    for (i = 0; i < gc->root_count; i++) {\n        struct cork_gc_header  *header = gc->roots[i];\n        if (cork_gc_get_color(header) == GC_PURPLE) {\n            DEBUG(\"  Checking possible garbage cycle root %p\\n\",\n                  cork_gc_get_object(header));\n            DEBUG(\"    cork_gc_mark_gray(%p)\\n\",\n                  cork_gc_get_object(header));\n            cork_gc_mark_gray(gc, header);\n        } else {\n            DEBUG(\"  Possible garbage cycle root %p already checked\\n\",\n                  cork_gc_get_object(header));\n            cork_gc_set_buffered(header, false);\n            gc->roots[i] = NULL;\n            if (cork_gc_get_color(header) == GC_BLACK &&\n                cork_gc_get_ref_count(header) == 0) {\n                DEBUG(\"  Freeing %p\\n\", header);\n                cork_gc_free(header);\n            }\n        }\n    }\n}\n\nstatic void\ncork_gc_scan_black_step(struct cork_gc *gc, void *obj, void *ud);\n\nstatic void\ncork_gc_scan_black(struct cork_gc *gc, struct cork_gc_header *header)\n{\n    DEBUG(\"      Setting color of %p to BLACK\\n\",\n          cork_gc_get_object(header));\n    cork_gc_set_color(header, GC_BLACK);\n    cork_gc_recurse(gc, header, cork_gc_scan_black_step);\n}\n\nstatic void\ncork_gc_scan_black_step(struct cork_gc *gc, void *obj, void *ud)\n{\n    if (obj != NULL) {\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        cork_gc_inc_ref_count(header);\n        DEBUG(\"      Increasing reference count %p -> %d\\n\",\n              obj, cork_gc_get_ref_count(header));\n        if (cork_gc_get_color(header) != GC_BLACK) {\n            cork_gc_scan_black(gc, header);\n        }\n    }\n}\n\nstatic void\ncork_gc_scan(struct cork_gc *gc, void *obj, void *ud)\n{\n    if (obj != NULL) {\n        DEBUG(\"  Scanning possible garbage cycle entry %p\\n\", obj);\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        if (cork_gc_get_color(header) == GC_GRAY) {\n            if (cork_gc_get_ref_count(header) > 0) {\n                DEBUG(\"    Remaining references; can't be a cycle\\n\");\n                cork_gc_scan_black(gc, header);\n            } else {\n                DEBUG(\"    Definitely a garbage cycle\\n\");\n                cork_gc_set_color(header, GC_WHITE);\n                cork_gc_recurse(gc, header, cork_gc_scan);\n            }\n        } else {\n            DEBUG(\"    Already checked\\n\");\n        }\n    }\n}\n\nstatic void\ncork_gc_scan_roots(struct cork_gc *gc)\n{\n    size_t  i;\n    for (i = 0; i < gc->root_count; i++) {\n        if (gc->roots[i] != NULL) {\n            void  *obj = cork_gc_get_object(gc->roots[i]);\n            cork_gc_scan(gc, obj, NULL);\n        }\n    }\n}\n\nstatic void\ncork_gc_collect_white(struct cork_gc *gc, void *obj, void *ud)\n{\n    if (obj != NULL) {\n        struct cork_gc_header  *header = cork_gc_get_header(obj);\n        if (cork_gc_get_color(header) == GC_WHITE &&\n            !cork_gc_get_buffered(header)) {\n            DEBUG(\"  Releasing %p\\n\", obj);\n            cork_gc_set_color(header, GC_BLACK);\n            cork_gc_recurse(gc, header, cork_gc_collect_white);\n            DEBUG(\"  Freeing %p\\n\", header);\n            cork_gc_free(header);\n        }\n    }\n}\n\nstatic void\ncork_gc_collect_roots(struct cork_gc *gc)\n{\n    size_t  i;\n    for (i = 0; i < gc->root_count; i++) {\n        if (gc->roots[i] != NULL) {\n            struct cork_gc_header  *header = gc->roots[i];\n            void  *obj = cork_gc_get_object(header);\n            cork_gc_set_buffered(header, false);\n            DEBUG(\"Collecting cycles from garbage root %p\\n\", obj);\n            cork_gc_collect_white(gc, obj, NULL);\n            gc->roots[i] = NULL;\n        }\n    }\n    gc->root_count = 0;\n}\n\nstatic void\ncork_gc_collect_cycles(struct cork_gc *gc)\n{\n    DEBUG(\"Collecting garbage cycles\\n\");\n    cork_gc_mark_roots(gc);\n    cork_gc_scan_roots(gc);\n    cork_gc_collect_roots(gc);\n}\n"
  },
  {
    "path": "src/libcork/core/hash.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include \"libcork/core/hash.h\"\n#include \"libcork/core/types.h\"\n\nbool\ncork_big_hash_equal(const cork_big_hash h1, const cork_big_hash h2);\n\ncork_hash\ncork_stable_hash_buffer(cork_hash seed, const void *src, size_t len);\n\ncork_hash\ncork_hash_buffer(cork_hash seed, const void *src, size_t len);\n\ncork_big_hash\ncork_big_hash_buffer(cork_big_hash seed, const void *src, size_t len);\n"
  },
  {
    "path": "src/libcork/core/id.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2020, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include \"libcork/core/id.h\"\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nbool\ncork_uid_equal(const cork_uid id1, const cork_uid id2);\n\ncork_hash\ncork_uid_hash(const cork_uid id);\n\nconst char*\ncork_uid_name(const cork_uid id);\n"
  },
  {
    "path": "src/libcork/core/ip-address.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"libcork/core/byte-order.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/net-addresses.h\"\n#include \"libcork/core/types.h\"\n\n#ifndef CORK_IP_ADDRESS_DEBUG\n#define CORK_IP_ADDRESS_DEBUG 0\n#endif\n\n#if CORK_IP_ADDRESS_DEBUG\n#include <stdio.h>\n#define DEBUG(...) \\\n    do { \\\n        fprintf(stderr, __VA_ARGS__); \\\n    } while (0)\n#else\n#define DEBUG(...) /* nothing */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * IP addresses\n */\n\n/*** IPv4 ***/\n\nstatic inline const char *\ncork_ipv4_parse(struct cork_ipv4 *addr, const char *str)\n{\n    const char  *ch;\n    bool  seen_digit_in_octet = false;\n    unsigned int  octets = 0;\n    unsigned int  digit = 0;\n    uint8_t  result[4];\n\n    for (ch = str; *ch != '\\0'; ch++) {\n        DEBUG(\"%2u: %c\\t\", (unsigned int) (ch-str), *ch);\n        switch (*ch) {\n            case '0': case '1': case '2': case '3': case '4':\n            case '5': case '6': case '7': case '8': case '9':\n                seen_digit_in_octet = true;\n                digit *= 10;\n                digit += (*ch - '0');\n                DEBUG(\"digit = %u\\n\", digit);\n                if (CORK_UNLIKELY(digit > 255)) {\n                    DEBUG(\"\\t\");\n                    goto parse_error;\n                }\n                break;\n\n            case '.':\n                /* If this would be the fourth octet, it can't have a trailing\n                 * period. */\n                if (CORK_UNLIKELY(octets == 3)) {\n                    goto parse_error;\n                }\n                DEBUG(\"octet %u = %u\\n\", octets, digit);\n                result[octets] = digit;\n                digit = 0;\n                octets++;\n                seen_digit_in_octet = false;\n                break;\n\n            default:\n                /* Any other character is a parse error. */\n                goto parse_error;\n        }\n    }\n\n    /* If we have a valid octet at the end, and that would be the fourth octet,\n     * then we've got a valid final parse. */\n    DEBUG(\"%2u:\\t\", (unsigned int) (ch-str));\n    if (CORK_LIKELY(seen_digit_in_octet && octets == 3)) {\n#if CORK_IP_ADDRESS_DEBUG\n        char  parsed_ipv4[CORK_IPV4_STRING_LENGTH];\n#endif\n        DEBUG(\"octet %u = %u\\n\", octets, digit);\n        result[octets] = digit;\n        cork_ipv4_copy(addr, result);\n#if CORK_IP_ADDRESS_DEBUG\n        cork_ipv4_to_raw_string(addr, parsed_ipv4);\n        DEBUG(\"\\tParsed address: %s\\n\", parsed_ipv4);\n#endif\n        return ch;\n    }\n\nparse_error:\n    DEBUG(\"parse error\\n\");\n    cork_parse_error(\"Invalid IPv4 address: \\\"%s\\\"\", str);\n    return NULL;\n}\n\nint\ncork_ipv4_init(struct cork_ipv4 *addr, const char *str)\n{\n    return cork_ipv4_parse(addr, str) == NULL? -1: 0;\n}\n\nbool\ncork_ipv4_equal_(const struct cork_ipv4 *addr1, const struct cork_ipv4 *addr2)\n{\n    return cork_ipv4_equal(addr1, addr2);\n}\n\nvoid\ncork_ipv4_to_raw_string(const struct cork_ipv4 *addr, char *dest)\n{\n    snprintf(dest, CORK_IPV4_STRING_LENGTH, \"%u.%u.%u.%u\",\n             addr->_.u8[0], addr->_.u8[1], addr->_.u8[2], addr->_.u8[3]);\n}\n\nbool\ncork_ipv4_is_valid_network(const struct cork_ipv4 *addr,\n                           unsigned int cidr_prefix)\n{\n    uint32_t  cidr_mask;\n\n    if (cidr_prefix > 32) {\n        return false;\n    } else if (cidr_prefix == 32) {\n        /* This handles undefined behavior for overflow bit shifts. */\n        cidr_mask = 0;\n    } else {\n        cidr_mask = 0xffffffff >> cidr_prefix;\n    }\n\n    return (CORK_UINT32_BIG_TO_HOST(addr->_.u32) & cidr_mask) == 0;\n}\n\n/*** IPv6 ***/\n\nint\ncork_ipv6_init(struct cork_ipv6 *addr, const char *str)\n{\n    const char  *ch;\n\n    uint16_t  digit = 0;\n    unsigned int  before_count = 0;\n    uint16_t  before_double_colon[8];\n    uint16_t  after_double_colon[8];\n    uint16_t  *dest = before_double_colon;\n\n    unsigned int  digits_seen = 0;\n    unsigned int  hextets_seen = 0;\n    bool  another_required = true;\n    bool  digit_allowed = true;\n    bool  colon_allowed = true;\n    bool  double_colon_allowed = true;\n    bool  just_saw_colon = false;\n\n    for (ch = str; *ch != '\\0'; ch++) {\n        DEBUG(\"%2u: %c\\t\", (unsigned int) (ch-str), *ch);\n        switch (*ch) {\n#define process_digit(base) \\\n                /* Make sure a digit is allowed here. */ \\\n                if (CORK_UNLIKELY(!digit_allowed)) { \\\n                    goto parse_error; \\\n                } \\\n                /* If we've already seen 4 digits, it's a parse error. */ \\\n                if (CORK_UNLIKELY(digits_seen == 4)) { \\\n                    goto parse_error; \\\n                } \\\n                \\\n                digits_seen++; \\\n                colon_allowed = true; \\\n                just_saw_colon = false; \\\n                digit <<= 4; \\\n                digit |= (*ch - (base)); \\\n                DEBUG(\"digit = %04x\\n\", digit);\n\n            case '0': case '1': case '2': case '3': case '4':\n            case '5': case '6': case '7': case '8': case '9':\n                process_digit('0');\n                break;\n\n            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':\n                process_digit('a'-10);\n                break;\n\n            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':\n                process_digit('A'-10);\n                break;\n\n#undef process_digit\n\n            case ':':\n                /* We can only see a colon immediately after a hextet or as part\n                 * of a double-colon. */\n                if (CORK_UNLIKELY(!colon_allowed)) {\n                    goto parse_error;\n                }\n\n                /* If this is a double-colon, start parsing hextets into our\n                 * second array. */\n                if (just_saw_colon) {\n                    DEBUG(\"double-colon\\n\");\n                    colon_allowed = false;\n                    digit_allowed = true;\n                    another_required = false;\n                    double_colon_allowed = false;\n                    before_count = hextets_seen;\n                    dest = after_double_colon;\n                    continue;\n                }\n\n                /* If this would end the eighth hextet (regardless of the\n                 * placement of a double-colon), then there can't be a trailing\n                 * colon. */\n                if (CORK_UNLIKELY(hextets_seen == 8)) {\n                    goto parse_error;\n                }\n\n                /* If this is the very beginning of the string, then we can only\n                 * have a double-colon, not a single colon. */\n                if (digits_seen == 0 && hextets_seen == 0) {\n                    DEBUG(\"initial colon\\n\");\n                    colon_allowed = true;\n                    digit_allowed = false;\n                    just_saw_colon = true;\n                    another_required = true;\n                    continue;\n                }\n\n                /* Otherwise this ends the current hextet. */\n                DEBUG(\"hextet %u = %04x\\n\", hextets_seen, digit);\n                *(dest++) = CORK_UINT16_HOST_TO_BIG(digit);\n                digit = 0;\n                hextets_seen++;\n                digits_seen = 0;\n                colon_allowed = double_colon_allowed;\n                just_saw_colon = true;\n                another_required = true;\n                break;\n\n            case '.':\n            {\n                /* If we see a period, then we must be in the middle of an IPv4\n                 * address at the end of the IPv6 address. */\n                struct cork_ipv4  *ipv4 = (struct cork_ipv4 *) dest;\n                DEBUG(\"Detected IPv4 address %s\\n\", ch-digits_seen);\n\n                /* Ensure that we have space for the two hextets that the IPv4\n                 * address will take up. */\n                if (CORK_UNLIKELY(hextets_seen >= 7)) {\n                    goto parse_error;\n                }\n\n                /* Parse the IPv4 address directly into our current hextet\n                 * buffer. */\n                ch = cork_ipv4_parse(ipv4, ch - digits_seen);\n                if (CORK_LIKELY(ch != NULL)) {\n                    hextets_seen += 2;\n                    digits_seen = 0;\n                    another_required = false;\n\n                    /* ch now points at the NUL terminator, but we're about to\n                     * increment ch. */\n                    ch--;\n                    break;\n                }\n\n                /* The IPv4 parse failed, so we have an IPv6 parse error. */\n                goto parse_error;\n            }\n\n            default:\n                /* Any other character is a parse error. */\n                goto parse_error;\n        }\n    }\n\n    /* If we have a valid hextet at the end, and we've either seen a\n     * double-colon, or we have eight hextets in total, then we've got a valid\n     * final parse. */\n    DEBUG(\"%2u:\\t\", (unsigned int) (ch-str));\n    if (CORK_LIKELY(digits_seen > 0)) {\n        /* If there are trailing digits that would form a ninth hextet\n         * (regardless of the placement of a double-colon), then we have a parse\n         * error. */\n        if (CORK_UNLIKELY(hextets_seen == 8)) {\n            goto parse_error;\n        }\n\n        DEBUG(\"hextet %u = %04x\\n\\t\", hextets_seen, digit);\n        *(dest++) = CORK_UINT16_HOST_TO_BIG(digit);\n        hextets_seen++;\n    } else if (CORK_UNLIKELY(another_required)) {\n        goto parse_error;\n    }\n\n    if (!double_colon_allowed) {\n        /* We've seen a double-colon, so use 0000 for any hextets that weren't\n         * present. */\n#if CORK_IP_ADDRESS_DEBUG\n        char  parsed_result[CORK_IPV6_STRING_LENGTH];\n#endif\n        unsigned int  after_count = hextets_seen - before_count;\n        DEBUG(\"Saw double-colon; %u hextets before, %u after\\n\",\n              before_count, after_count);\n        memset(addr, 0, sizeof(struct cork_ipv6));\n        memcpy(addr, before_double_colon,\n               sizeof(uint16_t) * before_count);\n        memcpy(&addr->_.u16[8-after_count], after_double_colon,\n               sizeof(uint16_t) * after_count);\n#if CORK_IP_ADDRESS_DEBUG\n        cork_ipv6_to_raw_string(addr, parsed_result);\n        DEBUG(\"\\tParsed address: %s\\n\", parsed_result);\n#endif\n        return 0;\n    } else if (hextets_seen == 8) {\n        /* No double-colon, so we must have exactly eight hextets. */\n#if CORK_IP_ADDRESS_DEBUG\n        char  parsed_result[CORK_IPV6_STRING_LENGTH];\n#endif\n        DEBUG(\"No double-colon\\n\");\n        cork_ipv6_copy(addr, before_double_colon);\n#if CORK_IP_ADDRESS_DEBUG\n        cork_ipv6_to_raw_string(addr, parsed_result);\n        DEBUG(\"\\tParsed address: %s\\n\", parsed_result);\n#endif\n        return 0;\n    }\n\nparse_error:\n    DEBUG(\"parse error\\n\");\n    cork_parse_error(\"Invalid IPv6 address: \\\"%s\\\"\", str);\n    return -1;\n}\n\nbool\ncork_ipv6_equal_(const struct cork_ipv6 *addr1, const struct cork_ipv6 *addr2)\n{\n    return cork_ipv6_equal(addr1, addr2);\n}\n\n#define NS_IN6ADDRSZ 16\n#define NS_INT16SZ 2\n\nvoid\ncork_ipv6_to_raw_string(const struct cork_ipv6 *addr, char *dest)\n{\n    const uint8_t  *src = addr->_.u8;\n\n    /*\n     * Note that int32_t and int16_t need only be \"at least\" large enough\n     * to contain a value of the specified size.  On some systems, like\n     * Crays, there is no such thing as an integer variable with 16 bits.\n     * Keep this in mind if you think this function should have been coded\n     * to use pointer overlays.  All the world's not a VAX.\n     */\n    char *tp;\n    struct { int base, len; } best, cur;\n    unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];\n    int i;\n\n    /*\n     * Preprocess:\n     *      Copy the input (bytewise) array into a wordwise array.\n     *      Find the longest run of 0x00's in src[] for :: shorthanding.\n     */\n    memset(words, '\\0', sizeof words);\n    for (i = 0; i < NS_IN6ADDRSZ; i++)\n        words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));\n    best.base = -1;\n    best.len = 0;\n    cur.base = -1;\n    cur.len = 0;\n    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {\n        if (words[i] == 0) {\n            if (cur.base == -1)\n                cur.base = i, cur.len = 1;\n            else\n                cur.len++;\n        } else {\n            if (cur.base != -1) {\n                if (best.base == -1 || cur.len > best.len)\n                    best = cur;\n                cur.base = -1;\n            }\n        }\n    }\n    if (cur.base != -1) {\n        if (best.base == -1 || cur.len > best.len)\n            best = cur;\n    }\n    if (best.base != -1 && best.len < 2)\n        best.base = -1;\n\n    /*\n     * Format the result.\n     */\n    tp = dest;\n    for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {\n        /* Are we inside the best run of 0x00's? */\n        if (best.base != -1 && i >= best.base &&\n            i < (best.base + best.len)) {\n            if (i == best.base)\n                *tp++ = ':';\n            continue;\n        }\n        /* Are we following an initial run of 0x00s or any real hex? */\n        if (i != 0)\n            *tp++ = ':';\n        /* Is this address an encapsulated IPv4? */\n        if (i == 6 && best.base == 0 &&\n            (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {\n            tp += sprintf(tp, \"%u.%u.%u.%u\",\n                          src[12], src[13], src[14], src[15]);\n            break;\n        }\n        tp += sprintf(tp, \"%x\", words[i]);\n    }\n    /* Was it a trailing run of 0x00's? */\n    if (best.base != -1 && (best.base + best.len) ==\n        (NS_IN6ADDRSZ / NS_INT16SZ))\n        *tp++ = ':';\n    *tp++ = '\\0';\n}\n\nbool\ncork_ipv6_is_valid_network(const struct cork_ipv6 *addr,\n                           unsigned int cidr_prefix)\n{\n    uint64_t  cidr_mask[2];\n\n    if (cidr_prefix > 128) {\n        return false;\n    } else if (cidr_prefix == 128) {\n        /* This handles undefined behavior for overflow bit shifts. */\n        cidr_mask[0] = cidr_mask[1] = 0;\n    } else if (cidr_prefix == 64) {\n        /* This handles undefined behavior for overflow bit shifts. */\n        cidr_mask[0] = 0;\n        cidr_mask[1] = UINT64_C(0xffffffffffffffff);\n    } else if (cidr_prefix > 64) {\n        cidr_mask[0] = 0;\n        cidr_mask[1] = UINT64_C(0xffffffffffffffff) >> (cidr_prefix-64);\n    } else {\n        cidr_mask[0] = UINT64_C(0xffffffffffffffff) >> cidr_prefix;\n        cidr_mask[1] = UINT64_C(0xffffffffffffffff);\n    }\n\n    return (CORK_UINT64_BIG_TO_HOST(addr->_.u64[0] & cidr_mask[0]) == 0) &&\n           (CORK_UINT64_BIG_TO_HOST(addr->_.u64[1] & cidr_mask[1]) == 0);\n}\n\n\n/*** IP ***/\n\nvoid\ncork_ip_from_ipv4_(struct cork_ip *addr, const void *src)\n{\n    cork_ip_from_ipv4(addr, src);\n}\n\nvoid\ncork_ip_from_ipv6_(struct cork_ip *addr, const void *src)\n{\n    cork_ip_from_ipv6(addr, src);\n}\n\nint\ncork_ip_init(struct cork_ip *addr, const char *str)\n{\n    int  rc;\n\n    /* Try IPv4 first */\n    rc = cork_ipv4_init(&addr->ip.v4, str);\n    if (rc == 0) {\n        /* successful parse */\n        addr->version = 4;\n        return 0;\n    }\n\n    /* Then try IPv6 */\n    cork_error_clear();\n    rc = cork_ipv6_init(&addr->ip.v6, str);\n    if (rc == 0) {\n        /* successful parse */\n        addr->version = 6;\n        return 0;\n    }\n\n    /* Parse error for both address types */\n    cork_parse_error(\"Invalid IP address: \\\"%s\\\"\", str);\n    return -1;\n}\n\nbool\ncork_ip_equal_(const struct cork_ip *addr1, const struct cork_ip *addr2)\n{\n    return cork_ip_equal(addr1, addr2);\n}\n\nvoid\ncork_ip_to_raw_string(const struct cork_ip *addr, char *dest)\n{\n    switch (addr->version) {\n        case 4:\n            cork_ipv4_to_raw_string(&addr->ip.v4, dest);\n            return;\n\n        case 6:\n            cork_ipv6_to_raw_string(&addr->ip.v6, dest);\n            return;\n\n        default:\n            strncpy(dest, \"<INVALID>\", CORK_IP_STRING_LENGTH);\n            return;\n    }\n}\n\nbool\ncork_ip_is_valid_network(const struct cork_ip *addr, unsigned int cidr_prefix)\n{\n    switch (addr->version) {\n        case 4:\n            return cork_ipv4_is_valid_network(&addr->ip.v4, cidr_prefix);\n        case 6:\n            return cork_ipv6_is_valid_network(&addr->ip.v6, cidr_prefix);\n        default:\n            return false;\n    }\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nvoid\ncork_ipv4_copy(struct cork_ipv4* addr, const void* src);\n\nbool\ncork_ipv4_equal(const struct cork_ipv4* addr1, const struct cork_ipv4* addr2);\n\nvoid\ncork_ipv6_copy(struct cork_ipv6* addr, const void* src);\n\nbool\ncork_ipv6_equal(const struct cork_ipv6* addr1, const struct cork_ipv6* addr2);\n\nbool\ncork_ip_equal(const struct cork_ip* addr1, const struct cork_ip* addr2);\n\nvoid\ncork_ip_from_ipv4(struct cork_ip* addr, const void* src);\n\nvoid\ncork_ip_from_ipv6(struct cork_ip* addr, const void* src);\n"
  },
  {
    "path": "src/libcork/core/mempool.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <stdlib.h>\n\n#include \"libcork/core/callbacks.h\"\n#include \"libcork/core/mempool.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/helpers/errors.h\"\n\n\n#if !defined(CORK_DEBUG_MEMPOOL)\n#define CORK_DEBUG_MEMPOOL  0\n#endif\n\n#if CORK_DEBUG_MEMPOOL\n#include <stdio.h>\n#define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define DEBUG(...) /* no debug messages */\n#endif\n\n\n\nstruct cork_mempool {\n    size_t  element_size;\n    size_t  block_size;\n    struct cork_mempool_object  *free_list;\n    /* The number of objects that have been given out by\n     * cork_mempool_new but not returned via cork_mempool_free. */\n    size_t  allocated_count;\n    struct cork_mempool_block  *blocks;\n\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_init_f  init_object;\n    cork_done_f  done_object;\n};\n\nstruct cork_mempool_object {\n    /* When this object is unclaimed, it will be in the cork_mempool\n     * object's free_list using this pointer. */\n    struct cork_mempool_object  *next_free;\n};\n\nstruct cork_mempool_block {\n    struct cork_mempool_block  *next_block;\n};\n\n#define cork_mempool_object_size(mp) \\\n    (sizeof(struct cork_mempool_object) + (mp)->element_size)\n\n#define cork_mempool_get_header(obj) \\\n    (((struct cork_mempool_object *) (obj)) - 1)\n\n#define cork_mempool_get_object(hdr) \\\n    ((void *) (((struct cork_mempool_object *) (hdr)) + 1))\n\n\nstruct cork_mempool *\ncork_mempool_new_size_ex(size_t element_size, size_t block_size)\n{\n    struct cork_mempool  *mp = cork_new(struct cork_mempool);\n    mp->element_size = element_size;\n    mp->block_size = block_size;\n    mp->free_list = NULL;\n    mp->allocated_count = 0;\n    mp->blocks = NULL;\n    mp->user_data = NULL;\n    mp->free_user_data = NULL;\n    mp->init_object = NULL;\n    mp->done_object = NULL;\n    return mp;\n}\n\nvoid\ncork_mempool_free(struct cork_mempool *mp)\n{\n    struct cork_mempool_block  *curr;\n    assert(mp->allocated_count == 0);\n\n    if (mp->done_object != NULL) {\n        struct cork_mempool_object  *obj;\n        for (obj = mp->free_list; obj != NULL; obj = obj->next_free) {\n            mp->done_object\n                (mp->user_data, cork_mempool_get_object(obj));\n        }\n    }\n\n    for (curr = mp->blocks; curr != NULL; ) {\n        struct cork_mempool_block  *next = curr->next_block;\n        cork_free(curr, mp->block_size);\n        /* Do this here instead of in the for statement to avoid\n         * accessing the just-freed block. */\n        curr = next;\n    }\n\n    cork_free_user_data(mp);\n    cork_delete(struct cork_mempool, mp);\n}\n\n\nvoid\ncork_mempool_set_user_data(struct cork_mempool *mp,\n                           void *user_data, cork_free_f free_user_data)\n{\n    cork_free_user_data(mp);\n    mp->user_data = user_data;\n    mp->free_user_data = free_user_data;\n}\n\nvoid\ncork_mempool_set_init_object(struct cork_mempool *mp, cork_init_f init_object)\n{\n    mp->init_object = init_object;\n}\n\nvoid\ncork_mempool_set_done_object(struct cork_mempool *mp, cork_done_f done_object)\n{\n    mp->done_object = done_object;\n}\n\nvoid\ncork_mempool_set_callbacks(struct cork_mempool *mp,\n                           void *user_data, cork_free_f free_user_data,\n                           cork_init_f init_object,\n                           cork_done_f done_object)\n{\n    cork_mempool_set_user_data(mp, user_data, free_user_data);\n    cork_mempool_set_init_object(mp, init_object);\n    cork_mempool_set_done_object(mp, done_object);\n}\n\n\n/* If this function succeeds, then we guarantee that there will be at\n * least one object in mp->free_list. */\nstatic void\ncork_mempool_new_block(struct cork_mempool *mp)\n{\n    /* Allocate the new block and add it to mp's block list. */\n    struct cork_mempool_block  *block;\n    void  *vblock;\n    DEBUG(\"Allocating new %zu-byte block\\n\", mp->block_size);\n    block = cork_malloc(mp->block_size);\n    block->next_block = mp->blocks;\n    mp->blocks = block;\n    vblock = block;\n\n    /* Divide the block's memory region into a bunch of objects. */\n    size_t  index = sizeof(struct cork_mempool_block);\n    for (index = sizeof(struct cork_mempool_block);\n         (index + cork_mempool_object_size(mp)) <= mp->block_size;\n         index += cork_mempool_object_size(mp)) {\n        struct cork_mempool_object  *obj = vblock + index;\n        DEBUG(\"  New object at %p[%p]\\n\", cork_mempool_get_object(obj), obj);\n        if (mp->init_object != NULL) {\n            mp->init_object\n                (mp->user_data, cork_mempool_get_object(obj));\n        }\n        obj->next_free = mp->free_list;\n        mp->free_list = obj;\n    }\n}\n\nvoid *\ncork_mempool_new_object(struct cork_mempool *mp)\n{\n    struct cork_mempool_object  *obj;\n    void  *ptr;\n\n    if (CORK_UNLIKELY(mp->free_list == NULL)) {\n        cork_mempool_new_block(mp);\n    }\n\n    obj = mp->free_list;\n    mp->free_list = obj ? obj->next_free : NULL;\n    mp->allocated_count++;\n    ptr = cork_mempool_get_object(obj);\n    return ptr;\n}\n\nvoid\ncork_mempool_free_object(struct cork_mempool *mp, void *ptr)\n{\n    struct cork_mempool_object  *obj = cork_mempool_get_header(ptr);\n    DEBUG(\"Returning %p[%p] to memory pool\\n\", ptr, obj);\n    obj->next_free = mp->free_list;\n    mp->free_list = obj;\n    mp->allocated_count--;\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nstruct cork_mempool*\ncork_mempool_new_size(size_t element_size);\n"
  },
  {
    "path": "src/libcork/core/timestamp.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <string.h>\n#include <time.h>\n#include <sys/time.h>\n\n#include \"libcork/core/timestamp.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/helpers/errors.h\"\n\nvoid\ncork_timestamp_init_now(cork_timestamp *ts)\n{\n    struct timeval  tp;\n    gettimeofday(&tp, NULL);\n    cork_timestamp_init_usec(ts, tp.tv_sec, tp.tv_usec);\n}\n\n\n#define is_digit(ch)  ((ch) >= '0' && (ch) <= '9')\n\nstatic uint64_t\npower_of_10(unsigned int width)\n{\n    uint64_t  accumulator = 10;\n    uint64_t  result = 1;\n    while (width != 0) {\n        if ((width % 2) == 1) {\n            result *= accumulator;\n            width--;\n        }\n        accumulator *= accumulator;\n        width /= 2;\n    }\n    return result;\n}\n\nstatic int\nappend_fractional(const cork_timestamp ts, unsigned int width,\n                  struct cork_buffer *dest)\n{\n    if (CORK_UNLIKELY(width == 0 || width > 9)) {\n        cork_error_set_printf\n            (EINVAL,\n             \"Invalid width %u for fractional cork_timestamp\", width);\n        return -1;\n    } else {\n        uint64_t  denom = power_of_10(width);\n        uint64_t  frac = cork_timestamp_gsec_to_units(ts, denom);\n        cork_buffer_append_printf(dest, \"%0*\" PRIu64, width, frac);\n        return 0;\n    }\n}\n\nstatic int\ncork_timestamp_format_parts(const cork_timestamp ts, struct tm *tm,\n                            const char *format, struct cork_buffer *dest)\n{\n    const char  *next_percent;\n\n    while ((next_percent = strchr(format, '%')) != NULL) {\n        const char  *spec = next_percent + 1;\n        unsigned int  width = 0;\n\n        /* First append any text in between the previous format specifier and\n         * this one. */\n        cork_buffer_append(dest, format, next_percent - format);\n\n        /* Then parse the format specifier */\n        while (is_digit(*spec)) {\n            width *= 10;\n            width += (*spec++ - '0');\n        }\n\n        switch (*spec) {\n            case '\\0':\n                cork_error_set_string\n                    (EINVAL,\n                     \"Trailing %% at end of cork_timestamp format string\");\n                return -1;\n\n            case '%':\n                cork_buffer_append(dest, \"%\", 1);\n                break;\n\n            case 'Y':\n                cork_buffer_append_printf(dest, \"%04d\", tm->tm_year + 1900);\n                break;\n\n            case 'm':\n                cork_buffer_append_printf(dest, \"%02d\", tm->tm_mon + 1);\n                break;\n\n            case 'd':\n                cork_buffer_append_printf(dest, \"%02d\", tm->tm_mday);\n                break;\n\n            case 'H':\n                cork_buffer_append_printf(dest, \"%02d\", tm->tm_hour);\n                break;\n\n            case 'M':\n                cork_buffer_append_printf(dest, \"%02d\", tm->tm_min);\n                break;\n\n            case 'S':\n                cork_buffer_append_printf(dest, \"%02d\", tm->tm_sec);\n                break;\n\n            case 's':\n                cork_buffer_append_printf\n                    (dest, \"%\" PRIu32, cork_timestamp_sec(ts));\n                break;\n\n            case 'f':\n                rii_check(append_fractional(ts, width, dest));\n                break;\n\n            default:\n                cork_error_set_printf\n                    (EINVAL,\n                     \"Unknown cork_timestamp format specifier %%%c\", *spec);\n                return -1;\n        }\n\n        format = spec + 1;\n    }\n\n    /* When we fall through, there is some additional content after the final\n     * format specifier. */\n    cork_buffer_append_string(dest, format);\n    return 0;\n}\n\nint\ncork_timestamp_format_utc(const cork_timestamp ts, const char *format,\n                          struct cork_buffer *dest)\n{\n    time_t  clock;\n    struct tm  tm;\n    clock = cork_timestamp_sec(ts);\n    gmtime_r(&clock, &tm);\n    return cork_timestamp_format_parts(ts, &tm, format, dest);\n}\n\nint\ncork_timestamp_format_local(const cork_timestamp ts, const char *format,\n                            struct cork_buffer *dest)\n{\n    time_t  clock;\n    struct tm  tm;\n    clock = cork_timestamp_sec(ts);\n    localtime_r(&clock, &tm);\n    return cork_timestamp_format_parts(ts, &tm, format, dest);\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nvoid\ncork_timestamp_init_sec(cork_timestamp* ts, uint64_t sec);\n\nvoid\ncork_timestamp_init_gsec(cork_timestamp* ts, uint64_t sec, uint64_t gsec);\n\nvoid\ncork_timestamp_init_msec(cork_timestamp* ts, uint64_t sec, uint64_t msec);\n\nvoid\ncork_timestamp_init_usec(cork_timestamp* ts, uint64_t sec, uint64_t usec);\n\nvoid\ncork_timestamp_init_nsec(cork_timestamp* ts, uint64_t sec, uint64_t nsec);\n\nuint32_t\ncork_timestamp_sec(const cork_timestamp ts);\n\nuint32_t\ncork_timestamp_gsec(const cork_timestamp ts);\n\nuint64_t\ncork_timestamp_gsec_to_units(const cork_timestamp ts, uint64_t denom);\n\nuint64_t\ncork_timestamp_msec(const cork_timestamp ts);\n\nuint64_t\ncork_timestamp_usec(const cork_timestamp ts);\n\nuint64_t\ncork_timestamp_nsec(const cork_timestamp ts);\n"
  },
  {
    "path": "src/libcork/core/u128.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <string.h>\n#include <stdio.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/core/u128.h\"\n\n\n/* From http://stackoverflow.com/questions/8023414/how-to-convert-a-128-bit-integer-to-a-decimal-ascii-string-in-c */\n\nconst char *\ncork_u128_to_decimal(char *dest, cork_u128 val)\n{\n    uint32_t  n[4];\n    char  *s = dest;\n    char  *p = dest;\n    unsigned int  i;\n\n    /* This algorithm assumes that n[3] is the MSW. */\n    n[3] = cork_u128_be32(val, 0);\n    n[2] = cork_u128_be32(val, 1);\n    n[1] = cork_u128_be32(val, 2);\n    n[0] = cork_u128_be32(val, 3);\n\n    memset(s, '0', CORK_U128_DECIMAL_LENGTH - 1);\n    s[CORK_U128_DECIMAL_LENGTH - 1] = '\\0';\n\n    for (i = 0; i < 128; i++) {\n        unsigned int  j;\n        unsigned int carry;\n\n        carry = (n[3] >= 0x80000000);\n        /* Shift n[] left, doubling it */\n        n[3] = ((n[3] << 1) & 0xFFFFFFFF) + (n[2] >= 0x80000000);\n        n[2] = ((n[2] << 1) & 0xFFFFFFFF) + (n[1] >= 0x80000000);\n        n[1] = ((n[1] << 1) & 0xFFFFFFFF) + (n[0] >= 0x80000000);\n        n[0] = ((n[0] << 1) & 0xFFFFFFFF);\n\n        /* Add s[] to itself in decimal, doubling it */\n        for (j = CORK_U128_DECIMAL_LENGTH - 1; j-- > 0; ) {\n            s[j] += s[j] - '0' + carry;\n            carry = (s[j] > '9');\n            if (carry) {\n                s[j] -= 10;\n            }\n        }\n    }\n\n    while ((p[0] == '0') && (p < &s[CORK_U128_DECIMAL_LENGTH - 2])) {\n        p++;\n    }\n\n    return p;\n}\n\n\nconst char *\ncork_u128_to_hex(char *buf, cork_u128 val)\n{\n    uint64_t  hi = val._.be64.hi;\n    uint64_t  lo = val._.be64.lo;\n    if (hi == 0) {\n        snprintf(buf, CORK_U128_HEX_LENGTH, \"%\" PRIx64, lo);\n    } else {\n        snprintf(buf, CORK_U128_HEX_LENGTH, \"%\" PRIx64 \"%016\" PRIx64, hi, lo);\n    }\n    return buf;\n}\n\nconst char *\ncork_u128_to_padded_hex(char *buf, cork_u128 val)\n{\n    uint64_t  hi = val._.be64.hi;\n    uint64_t  lo = val._.be64.lo;\n    snprintf(buf, CORK_U128_HEX_LENGTH, \"%016\" PRIx64 \"%016\" PRIx64, hi, lo);\n    return buf;\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\ncork_u128\ncork_u128_from_32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3);\n\ncork_u128\ncork_u128_from_64(uint64_t i0, uint64_t i1);\n\ncork_u128\ncork_u128_zero(void);\n\nbool\ncork_u128_eq(cork_u128 a, cork_u128 b);\n\nbool\ncork_u128_ne(cork_u128 a, cork_u128 b);\n\nbool\ncork_u128_lt(cork_u128 a, cork_u128 b);\n\nbool\ncork_u128_le(cork_u128 a, cork_u128 b);\n\nbool\ncork_u128_gt(cork_u128 a, cork_u128 b);\n\nbool\ncork_u128_ge(cork_u128 a, cork_u128 b);\n\ncork_u128\ncork_u128_shl(cork_u128 a, unsigned int b);\n\ncork_u128\ncork_u128_shr(cork_u128 a, unsigned int b);\n\ncork_u128\ncork_u128_add(cork_u128 a, cork_u128 b);\n\ncork_u128\ncork_u128_sub(cork_u128 a, cork_u128 b);\n"
  },
  {
    "path": "src/libcork/core/version.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2015, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include \"libcork/config.h\"\n#include \"libcork/core/api.h\"\n\n\n/*-----------------------------------------------------------------------\n * Library version\n */\n\nconst char *\ncork_version_string(void)\n{\n    return CORK_CONFIG_VERSION_STRING;\n}\n\nconst char *\ncork_revision_string(void)\n{\n    return CORK_CONFIG_REVISION;\n}\n"
  },
  {
    "path": "src/libcork/ds/array.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/array.h\"\n#include \"libcork/helpers/errors.h\"\n\n#ifndef CORK_ARRAY_DEBUG\n#define CORK_ARRAY_DEBUG 0\n#endif\n\n#if CORK_ARRAY_DEBUG\n#include <stdio.h>\n#define DEBUG(...) \\\n    do { \\\n        fprintf(stderr, __VA_ARGS__); \\\n        fprintf(stderr, \"\\n\"); \\\n    } while (0)\n#else\n#define DEBUG(...) /* nothing */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Resizable arrays\n */\n\nstruct cork_array_priv {\n    size_t  allocated_count;\n    size_t  allocated_size;\n    size_t  element_size;\n    size_t  initialized_count;\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_init_f  init;\n    cork_done_f  done;\n    cork_init_f  reuse;\n    cork_done_f  remove;\n};\n\nvoid\ncork_raw_array_init(struct cork_raw_array *array, size_t element_size)\n{\n    array->items = NULL;\n    array->size = 0;\n    array->priv = cork_new(struct cork_array_priv);\n    array->priv->allocated_count = 0;\n    array->priv->allocated_size = 0;\n    array->priv->element_size = element_size;\n    array->priv->initialized_count = 0;\n    array->priv->user_data = NULL;\n    array->priv->free_user_data = NULL;\n    array->priv->init = NULL;\n    array->priv->done = NULL;\n    array->priv->reuse = NULL;\n    array->priv->remove = NULL;\n}\n\nvoid\ncork_raw_array_done(struct cork_raw_array *array)\n{\n    if (array->priv->done != NULL) {\n        size_t  i;\n        char  *element = array->items;\n        for (i = 0; i < array->priv->initialized_count; i++) {\n            array->priv->done(array->priv->user_data, element);\n            element += array->priv->element_size;\n        }\n    }\n    if (array->items != NULL) {\n        cork_free(array->items, array->priv->allocated_size);\n    }\n    cork_free_user_data(array->priv);\n    cork_delete(struct cork_array_priv, array->priv);\n}\n\nvoid\ncork_raw_array_set_callback_data(struct cork_raw_array *array,\n                                 void *user_data, cork_free_f free_user_data)\n{\n    array->priv->user_data = user_data;\n    array->priv->free_user_data = free_user_data;\n}\n\nvoid\ncork_raw_array_set_init(struct cork_raw_array *array, cork_init_f init)\n{\n    array->priv->init = init;\n}\n\nvoid\ncork_raw_array_set_done(struct cork_raw_array *array, cork_done_f done)\n{\n    array->priv->done = done;\n}\n\nvoid\ncork_raw_array_set_reuse(struct cork_raw_array *array, cork_init_f reuse)\n{\n    array->priv->reuse = reuse;\n}\n\nvoid\ncork_raw_array_set_remove(struct cork_raw_array *array, cork_done_f remove)\n{\n    array->priv->remove = remove;\n}\n\nsize_t\ncork_raw_array_element_size(const struct cork_raw_array *array)\n{\n    return array->priv->element_size;\n}\n\nvoid\ncork_raw_array_clear(struct cork_raw_array *array)\n{\n    if (array->priv->remove != NULL) {\n        size_t  i;\n        char  *element = array->items;\n        for (i = 0; i < array->priv->initialized_count; i++) {\n            array->priv->remove(array->priv->user_data, element);\n            element += array->priv->element_size;\n        }\n    }\n    array->size = 0;\n}\n\nvoid *\ncork_raw_array_elements(const struct cork_raw_array *array)\n{\n    return array->items;\n}\n\nvoid *\ncork_raw_array_at(const struct cork_raw_array *array, size_t index)\n{\n    return ((char *) array->items) + (array->priv->element_size * index);\n}\n\nsize_t\ncork_raw_array_size(const struct cork_raw_array *array)\n{\n    return array->size;\n}\n\nbool\ncork_raw_array_is_empty(const struct cork_raw_array *array)\n{\n    return (array->size == 0);\n}\n\nvoid\ncork_raw_array_ensure_size(struct cork_raw_array *array, size_t desired_count)\n{\n    size_t  desired_size;\n\n    DEBUG(\"--- Array %p: Ensure %zu %zu-byte elements\",\n          array, desired_count, array->priv->element_size);\n    desired_size = desired_count * array->priv->element_size;\n\n    if (desired_size > array->priv->allocated_size) {\n        size_t  new_count = array->priv->allocated_count * 2;\n        size_t  new_size = array->priv->allocated_size * 2;\n        if (desired_size > new_size) {\n            new_count = desired_count;\n            new_size = desired_size;\n        }\n\n        DEBUG(\"--- Array %p: Reallocating %zu->%zu bytes\",\n              array, array->priv->allocated_size, new_size);\n        array->items =\n            cork_realloc(array->items, array->priv->allocated_size, new_size);\n\n        array->priv->allocated_count = new_count;\n        array->priv->allocated_size = new_size;\n    }\n}\n\nvoid *\ncork_raw_array_append(struct cork_raw_array *array)\n{\n    size_t  index;\n    void  *element;\n    index = array->size++;\n    cork_raw_array_ensure_size(array, array->size);\n    element = cork_raw_array_at(array, index);\n\n    /* Call the init or reset callback, depending on whether this entry has been\n     * initialized before. */\n\n    /* Since we can currently only add elements by appending them one at a time,\n     * then this entry is either already initialized, or is the first\n     * uninitialized entry. */\n    assert(index <= array->priv->initialized_count);\n\n    if (index == array->priv->initialized_count) {\n        /* This element has not been initialized yet. */\n        array->priv->initialized_count++;\n        if (array->priv->init != NULL) {\n            array->priv->init(array->priv->user_data, element);\n        }\n    } else {\n        /* This element has already been initialized. */\n        if (array->priv->reuse != NULL) {\n            array->priv->reuse(array->priv->user_data, element);\n        }\n    }\n\n    return element;\n}\n\nvoid\ncork_raw_array_remove(struct cork_raw_array *array, size_t index);\n\nvoid\ncork_raw_array_remove_range(struct cork_raw_array* array, size_t index,\n                            size_t count)\n{\n    size_t element_size = array->priv->element_size;\n    size_t remaining = array->size - index - count;\n    char* start_of_removed = array->items + (index * element_size);\n    char* end_of_removed = start_of_removed + (count * element_size);\n    char* end_of_array = array->items + (array->size * element_size);\n\n    array->size -= count;\n    if (array->priv->remove == NULL) {\n        /* If there isn't a cleanup callback, just move the array contents\n         * directly. */\n        if (end_of_removed < end_of_array) {\n            memmove(start_of_removed, end_of_removed, remaining * element_size);\n        }\n    } else {\n        /* If there are any elements _after_ the elements to be removed, we\n         * first swap them into the beginning of the elements to be removed. */\n        char temp[element_size];\n        while (end_of_removed < end_of_array) {\n            memcpy(temp, start_of_removed, element_size);\n            memcpy(start_of_removed, end_of_removed, element_size);\n            memcpy(end_of_removed, temp, element_size);\n            start_of_removed += element_size;\n            end_of_removed += element_size;\n        }\n\n        /* Then call the cleanup callback on all of the elements to be removed,\n         * which are now guaranteed to be at the end of the array. */\n        while (start_of_removed < end_of_removed) {\n            array->priv->remove(array->priv->user_data, start_of_removed);\n            start_of_removed += element_size;\n        }\n    }\n}\n\nint\ncork_raw_array_copy(struct cork_raw_array *dest,\n                    const struct cork_raw_array *src,\n                    cork_copy_f copy, void *user_data)\n{\n    size_t  i;\n    size_t  reuse_count;\n    char  *dest_element;\n\n    DEBUG(\"--- Copying %zu elements (%zu bytes) from %p to %p\",\n          src->size, src->size * dest->priv->element_size, src, dest);\n    assert(dest->priv->element_size == src->priv->element_size);\n    cork_array_clear(dest);\n    cork_array_ensure_size(dest, src->size);\n\n    /* Initialize enough elements to hold the contents of src */\n    reuse_count = dest->priv->initialized_count;\n    if (src->size < reuse_count) {\n        reuse_count = src->size;\n    }\n\n    dest_element = dest->items;\n    if (dest->priv->reuse != NULL) {\n        DEBUG(\"    Calling reuse on elements 0-%zu\", reuse_count);\n        for (i = 0; i < reuse_count; i++) {\n            dest->priv->reuse(dest->priv->user_data, dest_element);\n            dest_element += dest->priv->element_size;\n        }\n    } else {\n        dest_element += reuse_count * dest->priv->element_size;\n    }\n\n    if (dest->priv->init != NULL) {\n        DEBUG(\"    Calling init on elements %zu-%zu\", reuse_count, src->size);\n        for (i = reuse_count; i < src->size; i++) {\n            dest->priv->init(dest->priv->user_data, dest_element);\n            dest_element += dest->priv->element_size;\n        }\n    }\n\n    if (src->size > dest->priv->initialized_count) {\n        dest->priv->initialized_count = src->size;\n    }\n\n    /* If the caller provided a copy function, let it copy each element in turn.\n     * Otherwise, bulk copy everything using memcpy. */\n    if (copy == NULL) {\n        memcpy(dest->items, src->items, src->size * dest->priv->element_size);\n    } else {\n        const char  *src_element = src->items;\n        dest_element = dest->items;\n        for (i = 0; i < src->size; i++) {\n            rii_check(copy(user_data, dest_element, src_element));\n            dest_element += dest->priv->element_size;\n            src_element += dest->priv->element_size;\n        }\n    }\n\n    dest->size = src->size;\n    return 0;\n}\n\n\n/*-----------------------------------------------------------------------\n * Pointer arrays\n */\n\nstruct cork_pointer_array {\n    cork_free_f  free;\n};\n\nstatic void\npointer__init(void *user_data, void *vvalue)\n{\n    void **value = vvalue;\n    *value = NULL;\n}\n\nstatic void\npointer__done(void *user_data, void *vvalue)\n{\n    struct cork_pointer_array  *ptr_array = user_data;\n    void **value = vvalue;\n    if (*value != NULL) {\n        ptr_array->free(*value);\n    }\n}\n\nstatic void\npointer__remove(void *user_data, void *vvalue)\n{\n    struct cork_pointer_array  *ptr_array = user_data;\n    void **value = vvalue;\n    if (*value != NULL) {\n        ptr_array->free(*value);\n    }\n    *value = NULL;\n}\n\nstatic void\npointer__free(void *user_data)\n{\n    struct cork_pointer_array  *ptr_array = user_data;\n    cork_delete(struct cork_pointer_array, ptr_array);\n}\n\nvoid\ncork_raw_pointer_array_init(struct cork_raw_array *array, cork_free_f free_ptr)\n{\n    struct cork_pointer_array  *ptr_array = cork_new(struct cork_pointer_array);\n    ptr_array->free = free_ptr;\n    cork_raw_array_init(array, sizeof(void *));\n    cork_array_set_callback_data(array, ptr_array, pointer__free);\n    cork_array_set_init(array, pointer__init);\n    cork_array_set_done(array, pointer__done);\n    cork_array_set_remove(array, pointer__remove);\n}\n\n\n/*-----------------------------------------------------------------------\n * String arrays\n */\n\nvoid\ncork_string_array_init(struct cork_string_array *array)\n{\n    cork_raw_pointer_array_init\n        ((struct cork_raw_array *) array, (cork_free_f) cork_strfree);\n}\n\nvoid\ncork_string_array_append(struct cork_string_array *array, const char *str)\n{\n    const char  *copy = cork_strdup(str);\n    cork_array_append(array, copy);\n}\n\nstatic int\nstring__copy(void *user_data, void *vdest, const void *vsrc)\n{\n    const char  **dest = vdest;\n    const char  **src = (const char **) vsrc;\n    *dest = cork_strdup(*src);\n    return 0;\n}\n\nvoid\ncork_string_array_copy(struct cork_string_array *dest,\n                       const struct cork_string_array *src)\n{\n    CORK_ATTR_UNUSED int  rc;\n    rc = cork_array_copy(dest, src, string__copy, NULL);\n    /* cork_array_copy can only fail if the copy callback fails, and ours\n     * doesn't! */\n    assert(rc == 0);\n}\n"
  },
  {
    "path": "src/libcork/ds/bitset.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <string.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/api.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/bitset.h\"\n\n\nstatic size_t\nbytes_needed(size_t bit_count)\n{\n    /* We need one byte for every bit... */\n    size_t  bytes_needed = bit_count / 8;\n    /* Plus one extra for the leftovers that don't fit into a whole byte. */\n    bytes_needed += ((bit_count % 8) > 0);\n    return bytes_needed;\n}\n\nvoid\ncork_bitset_init(struct cork_bitset *set, size_t bit_count)\n{\n    set->bit_count = bit_count;\n    set->byte_count = bytes_needed(bit_count);\n    set->bits = cork_malloc(set->byte_count);\n    memset(set->bits, 0, set->byte_count);\n}\n\nstruct cork_bitset *\ncork_bitset_new(size_t bit_count)\n{\n    struct cork_bitset  *set = cork_new(struct cork_bitset);\n    cork_bitset_init(set, bit_count);\n    return set;\n}\n\nvoid\ncork_bitset_done(struct cork_bitset *set)\n{\n    cork_free(set->bits, set->byte_count);\n}\n\nvoid\ncork_bitset_free(struct cork_bitset *set)\n{\n    cork_bitset_done(set);\n    cork_delete(struct cork_bitset, set);\n}\n\nvoid\ncork_bitset_clear(struct cork_bitset *set)\n{\n    memset(set->bits, 0, set->byte_count);\n}\n"
  },
  {
    "path": "src/libcork/ds/buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/ds/managed-buffer.h\"\n#include \"libcork/ds/stream.h\"\n#include \"libcork/helpers/errors.h\"\n\n\nvoid\ncork_buffer_init(struct cork_buffer* buffer);\n\n\nstruct cork_buffer *\ncork_buffer_new(void)\n{\n    struct cork_buffer  *buffer = cork_new(struct cork_buffer);\n    cork_buffer_init(buffer);\n    return buffer;\n}\n\n\nvoid\ncork_buffer_done(struct cork_buffer *buffer)\n{\n    if (buffer->buf != NULL) {\n        cork_free(buffer->buf, buffer->allocated_size);\n        buffer->buf = NULL;\n    }\n    buffer->size = 0;\n    buffer->allocated_size = 0;\n}\n\n\nvoid\ncork_buffer_free(struct cork_buffer *buffer)\n{\n    cork_buffer_done(buffer);\n    cork_delete(struct cork_buffer, buffer);\n}\n\n\nbool\ncork_buffer_equal(const struct cork_buffer *buffer1,\n                  const struct cork_buffer *buffer2)\n{\n    if (buffer1 == buffer2) {\n        return true;\n    }\n\n    if (buffer1->size != buffer2->size) {\n        return false;\n    }\n\n    return (memcmp(buffer1->buf, buffer2->buf, buffer1->size) == 0);\n}\n\n\nvoid\ncork_buffer_ensure_size_(struct cork_buffer* buffer, size_t desired_size)\n{\n    size_t new_size;\n\n    /* Make sure we at least double the old size when reallocating. */\n    new_size = buffer->allocated_size * 2;\n    if (desired_size > new_size) {\n        new_size = desired_size;\n    }\n\n    buffer->buf = cork_realloc(buffer->buf, buffer->allocated_size, new_size);\n    buffer->allocated_size = new_size;\n}\n\nvoid\ncork_buffer_ensure_size(struct cork_buffer* buffer, size_t desired_size);\n\n\nvoid\ncork_buffer_clear(struct cork_buffer* buffer);\n\nvoid\ncork_buffer_truncate(struct cork_buffer* buffer, size_t length);\n\nvoid\ncork_buffer_set(struct cork_buffer* buffer, const void* src, size_t length);\n\nvoid\ncork_buffer_append(struct cork_buffer* buffer, const void* src, size_t length);\n\nvoid\ncork_buffer_set_string(struct cork_buffer* buffer, const char* str);\n\nvoid\ncork_buffer_append_string(struct cork_buffer* buffer, const char* str);\n\n\nvoid\ncork_buffer_append_vprintf(struct cork_buffer *buffer, const char *format,\n                           va_list args)\n{\n    size_t  format_size;\n    va_list  args1;\n\n    va_copy(args1, args);\n    format_size = vsnprintf(buffer->buf + buffer->size,\n                            buffer->allocated_size - buffer->size,\n                            format, args1);\n    va_end(args1);\n\n    /* If the first call works, then set buffer->size and return. */\n    if (format_size < (buffer->allocated_size - buffer->size)) {\n        buffer->size += format_size;\n        return;\n    }\n\n    /* If the first call fails, resize buffer and try again. */\n    cork_buffer_ensure_size(buffer, buffer->allocated_size + format_size + 1);\n    format_size = vsnprintf(buffer->buf + buffer->size,\n                            buffer->allocated_size - buffer->size,\n                            format, args);\n    buffer->size += format_size;\n}\n\n\nvoid\ncork_buffer_vprintf(struct cork_buffer *buffer, const char *format,\n                    va_list args)\n{\n    cork_buffer_clear(buffer);\n    cork_buffer_append_vprintf(buffer, format, args);\n}\n\n\nvoid\ncork_buffer_append_printf(struct cork_buffer *buffer, const char *format, ...)\n{\n    va_list  args;\n    va_start(args, format);\n    cork_buffer_append_vprintf(buffer, format, args);\n    va_end(args);\n}\n\n\nvoid\ncork_buffer_printf(struct cork_buffer *buffer, const char *format, ...)\n{\n    va_list  args;\n    va_start(args, format);\n    cork_buffer_vprintf(buffer, format, args);\n    va_end(args);\n}\n\n\nvoid\ncork_buffer_append_indent(struct cork_buffer *buffer, size_t indent)\n{\n    cork_buffer_ensure_size(buffer, buffer->size + indent + 1);\n    memset(buffer->buf + buffer->size, ' ', indent);\n    buffer->size += indent;\n    ((char *) buffer->buf)[buffer->size] = '\\0';\n}\n\n/* including space */\n#define is_sprint(ch)  ((ch) >= 0x20 && (ch) <= 0x7e)\n\n/* not including space */\n#define is_print(ch)  ((ch) > 0x20 && (ch) <= 0x7e)\n\n#define is_space(ch) \\\n    ((ch) == ' ' || \\\n     (ch) == '\\f' || \\\n     (ch) == '\\n' || \\\n     (ch) == '\\r' || \\\n     (ch) == '\\t' || \\\n     (ch) == '\\v')\n\n#define to_hex(nybble) \\\n    ((nybble) < 10? '0' + (nybble): 'a' - 10 + (nybble))\n\nvoid\ncork_buffer_append_c_string(struct cork_buffer *dest,\n                            const char *chars, size_t length)\n{\n    size_t  i;\n    cork_buffer_append(dest, \"\\\"\", 1);\n    for (i = 0; i < length; i++) {\n        char  ch = chars[i];\n        switch (ch) {\n            case '\\\"':\n                cork_buffer_append_literal(dest, \"\\\\\\\"\");\n                break;\n            case '\\\\':\n                cork_buffer_append_literal(dest, \"\\\\\\\\\");\n                break;\n            case '\\f':\n                cork_buffer_append_literal(dest, \"\\\\f\");\n                break;\n            case '\\n':\n                cork_buffer_append_literal(dest, \"\\\\n\");\n                break;\n            case '\\r':\n                cork_buffer_append_literal(dest, \"\\\\r\");\n                break;\n            case '\\t':\n                cork_buffer_append_literal(dest, \"\\\\t\");\n                break;\n            case '\\v':\n                cork_buffer_append_literal(dest, \"\\\\v\");\n                break;\n            default:\n                if (is_sprint(ch)) {\n                    cork_buffer_append(dest, &chars[i], 1);\n                } else {\n                    uint8_t  byte = ch;\n                    cork_buffer_append_printf(dest, \"\\\\x%02\" PRIx8, byte);\n                }\n                break;\n        }\n    }\n    cork_buffer_append(dest, \"\\\"\", 1);\n}\n\nvoid\ncork_buffer_append_hex_dump(struct cork_buffer *dest, size_t indent,\n                            const char *chars, size_t length)\n{\n    char  hex[3 * 16];\n    char  print[16];\n    char  *curr_hex = hex;\n    char  *curr_print = print;\n    size_t  i;\n    size_t  column = 0;\n    for (i = 0; i < length; i++) {\n        char  ch = chars[i];\n        uint8_t  u8 = ch;\n        *curr_hex++ = to_hex(u8 >> 4);\n        *curr_hex++ = to_hex(u8 & 0x0f);\n        *curr_hex++ = ' ';\n        *curr_print++ = is_sprint(ch)? ch: '.';\n        if (column == 0 && i != 0) {\n            cork_buffer_append_literal(dest, \"\\n\");\n            cork_buffer_append_indent(dest, indent);\n            column++;\n        } else if (column == 15) {\n            cork_buffer_append_printf\n                (dest, \"%-48.*s\", (int) (curr_hex - hex), hex);\n            cork_buffer_append_literal(dest, \" |\");\n            cork_buffer_append(dest, print, curr_print - print);\n            cork_buffer_append_literal(dest, \"|\");\n            curr_hex = hex;\n            curr_print = print;\n            column = 0;\n        } else {\n            column++;\n        }\n    }\n\n    if (column > 0) {\n        cork_buffer_append_printf(dest, \"%-48.*s\", (int) (curr_hex - hex), hex);\n        cork_buffer_append_literal(dest, \" |\");\n        cork_buffer_append(dest, print, curr_print - print);\n        cork_buffer_append_literal(dest, \"|\");\n    }\n}\n\nvoid\ncork_buffer_append_multiline(struct cork_buffer *dest, size_t indent,\n                             const char *chars, size_t length)\n{\n    size_t  i;\n    for (i = 0; i < length; i++) {\n        char  ch = chars[i];\n        if (ch == '\\n') {\n            cork_buffer_append_literal(dest, \"\\n\");\n            cork_buffer_append_indent(dest, indent);\n        } else {\n            cork_buffer_append(dest, &chars[i], 1);\n        }\n    }\n}\n\nvoid\ncork_buffer_append_binary(struct cork_buffer *dest, size_t indent,\n                          const char *chars, size_t length)\n{\n    size_t  i;\n    bool  newline = false;\n\n    /* If there are any non-printable characters, print out a hex dump */\n    for (i = 0; i < length; i++) {\n        if (!is_print(chars[i]) && !is_space(chars[i])) {\n            cork_buffer_append_literal(dest, \"(hex)\\n\");\n            cork_buffer_append_indent(dest, indent);\n            cork_buffer_append_hex_dump(dest, indent, chars, length);\n            return;\n        } else if (chars[i] == '\\n') {\n            newline = true;\n            /* Don't immediately use the multiline format, since there might be\n             * a non-printable character later on that kicks us over to the hex\n             * dump format. */\n        }\n    }\n\n    if (newline) {\n        cork_buffer_append_literal(dest, \"(multiline)\\n\");\n        cork_buffer_append_indent(dest, indent);\n        cork_buffer_append_multiline(dest, indent, chars, length);\n    } else {\n        cork_buffer_append(dest, chars, length);\n    }\n}\n\n\nstruct cork_buffer__managed_buffer {\n    struct cork_managed_buffer  parent;\n    struct cork_buffer  *buffer;\n};\n\nstatic void\ncork_buffer__managed_free(struct cork_managed_buffer *vself)\n{\n    struct cork_buffer__managed_buffer  *self =\n        cork_container_of(vself, struct cork_buffer__managed_buffer, parent);\n    cork_buffer_free(self->buffer);\n    cork_delete(struct cork_buffer__managed_buffer, self);\n}\n\nstatic struct cork_managed_buffer_iface  CORK_BUFFER__MANAGED_BUFFER = {\n    cork_buffer__managed_free\n};\n\nstruct cork_managed_buffer *\ncork_buffer_to_managed_buffer(struct cork_buffer *buffer)\n{\n    struct cork_buffer__managed_buffer  *self =\n        cork_new(struct cork_buffer__managed_buffer);\n    self->parent.buf = buffer->buf;\n    self->parent.size = buffer->size;\n    self->parent.ref_count = 1;\n    self->parent.iface = &CORK_BUFFER__MANAGED_BUFFER;\n    self->buffer = buffer;\n    return &self->parent;\n}\n\n\nint\ncork_buffer_to_slice(struct cork_buffer *buffer, struct cork_slice *slice)\n{\n    struct cork_managed_buffer  *managed =\n        cork_buffer_to_managed_buffer(buffer);\n\n    /* We don't have to check for NULL; cork_managed_buffer_slice_offset\n     * will do that for us. */\n    int  rc = cork_managed_buffer_slice_offset(slice, managed, 0);\n\n    /* Before returning, drop our reference to the managed buffer.  If\n     * the slicing succeeded, then there will be one remaining reference\n     * in the slice.  If it didn't succeed, this will free the managed\n     * buffer for us. */\n    cork_managed_buffer_unref(managed);\n    return rc;\n}\n\n\nstruct cork_buffer__stream_consumer {\n    struct cork_stream_consumer  consumer;\n    struct cork_buffer  *buffer;\n};\n\nstatic int\ncork_buffer_stream_consumer_data(struct cork_stream_consumer *consumer,\n                                 const void *buf, size_t size,\n                                 bool is_first_chunk)\n{\n    struct cork_buffer__stream_consumer  *bconsumer = cork_container_of\n        (consumer, struct cork_buffer__stream_consumer, consumer);\n    cork_buffer_append(bconsumer->buffer, buf, size);\n    return 0;\n}\n\nstatic int\ncork_buffer_stream_consumer_eof(struct cork_stream_consumer *consumer)\n{\n    return 0;\n}\n\nstatic void\ncork_buffer_stream_consumer_free(struct cork_stream_consumer *consumer)\n{\n    struct cork_buffer__stream_consumer  *bconsumer =\n        cork_container_of\n        (consumer, struct cork_buffer__stream_consumer, consumer);\n    cork_delete(struct cork_buffer__stream_consumer, bconsumer);\n}\n\nstruct cork_stream_consumer *\ncork_buffer_to_stream_consumer(struct cork_buffer *buffer)\n{\n    struct cork_buffer__stream_consumer  *bconsumer =\n        cork_new(struct cork_buffer__stream_consumer);\n    bconsumer->consumer.data = cork_buffer_stream_consumer_data;\n    bconsumer->consumer.eof = cork_buffer_stream_consumer_eof;\n    bconsumer->consumer.free = cork_buffer_stream_consumer_free;\n    bconsumer->buffer = buffer;\n    return &bconsumer->consumer;\n}\n"
  },
  {
    "path": "src/libcork/ds/dllist.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include \"libcork/core/api.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/dllist.h\"\n\n\n/* Include a linkable (but deprecated) version of this to maintain ABI\n * compatibility. */\n#undef cork_dllist_init\nCORK_API void\ncork_dllist_init(struct cork_dllist *list)\n{\n    list->head.next = &list->head;\n    list->head.prev = &list->head;\n}\n\n\nvoid\ncork_dllist_map(struct cork_dllist *list,\n                cork_dllist_map_func func, void *user_data)\n{\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n    cork_dllist_foreach_void(list, curr, next) {\n        func(curr, user_data);\n    }\n}\n\nint\ncork_dllist_visit(struct cork_dllist *list, void *ud,\n                  cork_dllist_visit_f *visit)\n{\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n    cork_dllist_foreach_void(list, curr, next) {\n        int  rc = visit(ud, curr);\n        if (rc != 0) {\n            return rc;\n        }\n    }\n    return 0;\n}\n\n\nsize_t\ncork_dllist_size(const struct cork_dllist *list)\n{\n    size_t  size = 0;\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n    cork_dllist_foreach_void(list, curr, next) {\n        size++;\n    }\n    return size;\n}\n"
  },
  {
    "path": "src/libcork/ds/file-stream.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/types.h>\n\n#include \"libcork/ds/stream.h\"\n#include \"libcork/helpers/errors.h\"\n#include \"libcork/helpers/posix.h\"\n\n#define BUFFER_SIZE  4096\n\n\n/*-----------------------------------------------------------------------\n * Producers\n */\n\nint\ncork_consume_fd(struct cork_stream_consumer *consumer, int fd)\n{\n    char  buf[BUFFER_SIZE];\n    ssize_t  bytes_read;\n    bool  first = true;\n\n    while (true) {\n        while ((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0) {\n            rii_check(cork_stream_consumer_data\n                      (consumer, buf, bytes_read, first));\n            first = false;\n        }\n\n        if (bytes_read == 0) {\n            return cork_stream_consumer_eof(consumer);\n        } else if (errno != EINTR) {\n            cork_system_error_set();\n            return -1;\n        }\n    }\n}\n\nint\ncork_consume_file(struct cork_stream_consumer *consumer, FILE *fp)\n{\n    char  buf[BUFFER_SIZE];\n    size_t  bytes_read;\n    bool  first = true;\n\n    while (true) {\n        while ((bytes_read = fread(buf, 1, BUFFER_SIZE, fp)) > 0) {\n            rii_check(cork_stream_consumer_data\n                      (consumer, buf, bytes_read, first));\n            first = false;\n        }\n\n        if (feof(fp)) {\n            return cork_stream_consumer_eof(consumer);\n        } else if (errno != EINTR) {\n            cork_system_error_set();\n            return -1;\n        }\n    }\n}\n\nint\ncork_consume_file_from_path(struct cork_stream_consumer *consumer,\n                            const char *path, int flags)\n{\n    int  fd;\n    rii_check_posix(fd = open(path, flags));\n    ei_check(cork_consume_fd(consumer, fd));\n    rii_check_posix(close(fd));\n    return 0;\n\nerror:\n    rii_check_posix(close(fd));\n    return -1;\n}\n\n\n/*-----------------------------------------------------------------------\n * Consumers\n */\n\nstruct cork_file_consumer {\n    struct cork_stream_consumer  parent;\n    FILE  *fp;\n};\n\nstatic int\ncork_file_consumer__data(struct cork_stream_consumer *vself,\n                         const void *buf, size_t size, bool is_first)\n{\n    struct cork_file_consumer  *self =\n        cork_container_of(vself, struct cork_file_consumer, parent);\n    size_t  bytes_written = fwrite(buf, 1, size, self->fp);\n    /* If there was an error writing to the file, then signal this to\n     * the producer */\n    if (bytes_written == size) {\n        return 0;\n    } else {\n        cork_system_error_set();\n        return -1;\n    }\n}\n\nstatic int\ncork_file_consumer__eof(struct cork_stream_consumer *vself)\n{\n    /* We never close the file with this version of the consumer, so there's\n     * nothing special to do at end-of-stream. */\n    return 0;\n}\n\nstatic void\ncork_file_consumer__free(struct cork_stream_consumer *vself)\n{\n    struct cork_file_consumer  *self =\n        cork_container_of(vself, struct cork_file_consumer, parent);\n    cork_delete(struct cork_file_consumer, self);\n}\n\nstruct cork_stream_consumer *\ncork_file_consumer_new(FILE *fp)\n{\n    struct cork_file_consumer  *self = cork_new(struct cork_file_consumer);\n    self->parent.data = cork_file_consumer__data;\n    self->parent.eof = cork_file_consumer__eof;\n    self->parent.free = cork_file_consumer__free;\n    self->fp = fp;\n    return &self->parent;\n}\n\n\nstruct cork_fd_consumer {\n    struct cork_stream_consumer  parent;\n    int  fd;\n};\n\nstatic int\ncork_fd_consumer__data(struct cork_stream_consumer *vself,\n                       const void *buf, size_t size, bool is_first)\n{\n    struct cork_fd_consumer  *self =\n        cork_container_of(vself, struct cork_fd_consumer, parent);\n    size_t  bytes_left = size;\n\n    while (bytes_left > 0) {\n        ssize_t  rc = write(self->fd, buf, bytes_left);\n        if (rc == -1 && errno != EINTR) {\n            cork_system_error_set();\n            return -1;\n        } else {\n            bytes_left -= rc;\n            buf += rc;\n        }\n    }\n\n    return 0;\n}\n\nstatic int\ncork_fd_consumer__eof_close(struct cork_stream_consumer *vself)\n{\n    int  rc;\n    struct cork_fd_consumer  *self =\n        cork_container_of(vself, struct cork_fd_consumer, parent);\n    rii_check_posix(rc = close(self->fd));\n    return 0;\n}\n\nstatic void\ncork_fd_consumer__free(struct cork_stream_consumer *vself)\n{\n    struct cork_fd_consumer  *self =\n        cork_container_of(vself, struct cork_fd_consumer, parent);\n    cork_delete(struct cork_fd_consumer, self);\n}\n\nstruct cork_stream_consumer *\ncork_fd_consumer_new(int fd)\n{\n    struct cork_fd_consumer  *self = cork_new(struct cork_fd_consumer);\n    self->parent.data = cork_fd_consumer__data;\n    /* We don't want to close fd, so we reuse file_consumer's eof method */\n    self->parent.eof = cork_file_consumer__eof;\n    self->parent.free = cork_fd_consumer__free;\n    self->fd = fd;\n    return &self->parent;\n}\n\nstruct cork_stream_consumer *\ncork_file_from_path_consumer_new(const char *path, int flags)\n{\n\n    int  fd;\n    struct cork_fd_consumer  *self;\n\n    rpi_check_posix(fd = open(path, flags));\n    self = cork_new(struct cork_fd_consumer);\n    self->parent.data = cork_fd_consumer__data;\n    self->parent.eof = cork_fd_consumer__eof_close;\n    self->parent.free = cork_fd_consumer__free;\n    self->fd = fd;\n    return &self->parent;\n}\n"
  },
  {
    "path": "src/libcork/ds/hash-table.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"libcork/core/callbacks.h\"\n#include \"libcork/core/hash.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/dllist.h\"\n#include \"libcork/ds/hash-table.h\"\n#include \"libcork/helpers/errors.h\"\n\n#ifndef CORK_HASH_TABLE_DEBUG\n#define CORK_HASH_TABLE_DEBUG 0\n#endif\n\n#if CORK_HASH_TABLE_DEBUG\n#include <stdio.h>\n#define DEBUG(...) \\\n    do { \\\n        fprintf(stderr, __VA_ARGS__); \\\n        fprintf(stderr, \"\\n\"); \\\n    } while (0)\n#else\n#define DEBUG(...) /* nothing */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Hash tables\n */\n\nstruct cork_hash_table_entry_priv {\n    struct cork_hash_table_entry  public;\n    struct cork_dllist_item  in_bucket;\n    struct cork_dllist_item  insertion_order;\n};\n\nstruct cork_hash_table {\n    struct cork_dllist  *bins;\n    struct cork_dllist  insertion_order;\n    size_t  bin_count;\n    size_t  bin_mask;\n    size_t  entry_count;\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_hash_f  hash;\n    cork_equals_f  equals;\n    cork_free_f  free_key;\n    cork_free_f  free_value;\n};\n\nstatic cork_hash\ncork_hash_table__default_hash(void *user_data, const void *key)\n{\n    return (cork_hash) (uintptr_t) key;\n}\n\nstatic bool\ncork_hash_table__default_equals(void *user_data,\n                                const void *key1, const void *key2)\n{\n    return key1 == key2;\n}\n\n\n/* The default initial number of bins to allocate in a new table. */\n#define CORK_HASH_TABLE_DEFAULT_INITIAL_SIZE  8\n\n/* The default number of entries per bin to allow before increasing the\n * number of bins. */\n#define CORK_HASH_TABLE_MAX_DENSITY  5\n\n/* Return a power-of-2 bin count that's at least as big as the given requested\n * size. */\nstatic inline size_t\ncork_hash_table_new_size(size_t desired_count)\n{\n    size_t  v = desired_count;\n    size_t  r = 1;\n    while (v >>= 1) {\n        r <<= 1;\n    }\n    if (r != desired_count) {\n        r <<= 1;\n    }\n    return r;\n}\n\n#define bin_index(table, hash)  ((hash) & (table)->bin_mask)\n\n/* Allocates a new bins array in a hash table.  We overwrite the old\n * array, so make sure to stash it away somewhere safe first. */\nstatic void\ncork_hash_table_allocate_bins(struct cork_hash_table *table,\n                              size_t desired_count)\n{\n    size_t  i;\n\n    table->bin_count = cork_hash_table_new_size(desired_count);\n    table->bin_mask = table->bin_count - 1;\n    DEBUG(\"Allocate %zu bins\", table->bin_count);\n    table->bins = cork_calloc(table->bin_count, sizeof(struct cork_dllist));\n    for (i = 0; i < table->bin_count; i++) {\n        cork_dllist_init(&table->bins[i]);\n    }\n}\n\n\nstatic struct cork_hash_table_entry_priv *\ncork_hash_table_new_entry(struct cork_hash_table *table,\n                          cork_hash hash, void *key, void *value)\n{\n    struct cork_hash_table_entry_priv  *entry =\n        cork_new(struct cork_hash_table_entry_priv);\n    cork_dllist_add(&table->insertion_order, &entry->insertion_order);\n    entry->public.hash = hash;\n    entry->public.key = key;\n    entry->public.value = value;\n    return entry;\n}\n\nstatic void\ncork_hash_table_free_entry(struct cork_hash_table *table,\n                           struct cork_hash_table_entry_priv *entry)\n{\n    if (table->free_key != NULL) {\n        table->free_key(entry->public.key);\n    }\n    if (table->free_value != NULL) {\n        table->free_value(entry->public.value);\n    }\n    cork_dllist_remove(&entry->insertion_order);\n    cork_delete(struct cork_hash_table_entry_priv, entry);\n}\n\n\nstruct cork_hash_table *\ncork_hash_table_new(size_t initial_size, unsigned int flags)\n{\n    struct cork_hash_table  *table = cork_new(struct cork_hash_table);\n    table->entry_count = 0;\n    table->user_data = NULL;\n    table->free_user_data = NULL;\n    table->hash = cork_hash_table__default_hash;\n    table->equals = cork_hash_table__default_equals;\n    table->free_key = NULL;\n    table->free_value = NULL;\n    cork_dllist_init(&table->insertion_order);\n    if (initial_size < CORK_HASH_TABLE_DEFAULT_INITIAL_SIZE) {\n        initial_size = CORK_HASH_TABLE_DEFAULT_INITIAL_SIZE;\n    }\n    cork_hash_table_allocate_bins(table, initial_size);\n    return table;\n}\n\nvoid\ncork_hash_table_clear(struct cork_hash_table *table)\n{\n    size_t  i;\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n\n    DEBUG(\"(clear) Remove all entries\");\n    for (curr = cork_dllist_start(&table->insertion_order);\n         !cork_dllist_is_end(&table->insertion_order, curr);\n         curr = next) {\n        struct cork_hash_table_entry_priv  *entry =\n            cork_container_of\n            (curr, struct cork_hash_table_entry_priv, insertion_order);\n        next = curr->next;\n        cork_hash_table_free_entry(table, entry);\n    }\n    cork_dllist_init(&table->insertion_order);\n\n    DEBUG(\"(clear) Clear bins\");\n    for (i = 0; i < table->bin_count; i++) {\n        DEBUG(\"  Bin %zu\", i);\n        cork_dllist_init(&table->bins[i]);\n    }\n\n    table->entry_count = 0;\n}\n\nvoid\ncork_hash_table_free(struct cork_hash_table *table)\n{\n    cork_hash_table_clear(table);\n    cork_cfree(table->bins, table->bin_count, sizeof(struct cork_dllist));\n    cork_delete(struct cork_hash_table, table);\n}\n\nsize_t\ncork_hash_table_size(const struct cork_hash_table *table)\n{\n    return table->entry_count;\n}\n\nvoid\ncork_hash_table_set_user_data(struct cork_hash_table *table,\n                              void *user_data, cork_free_f free_user_data)\n{\n    table->user_data = user_data;\n    table->free_user_data = free_user_data;\n}\n\nvoid\ncork_hash_table_set_hash(struct cork_hash_table *table, cork_hash_f hash)\n{\n    table->hash = hash;\n}\n\nvoid\ncork_hash_table_set_equals(struct cork_hash_table *table, cork_equals_f equals)\n{\n    table->equals = equals;\n}\n\nvoid\ncork_hash_table_set_free_key(struct cork_hash_table *table, cork_free_f free)\n{\n    table->free_key = free;\n}\n\nvoid\ncork_hash_table_set_free_value(struct cork_hash_table *table, cork_free_f free)\n{\n    table->free_value = free;\n}\n\n\nvoid\ncork_hash_table_ensure_size(struct cork_hash_table *table, size_t desired_count)\n{\n    if (desired_count > table->bin_count) {\n        struct cork_dllist  *old_bins = table->bins;\n        size_t  old_bin_count = table->bin_count;\n\n        cork_hash_table_allocate_bins(table, desired_count);\n\n        if (old_bins != NULL) {\n            size_t  i;\n            for (i = 0; i < old_bin_count; i++) {\n                struct cork_dllist  *bin = &old_bins[i];\n                struct cork_dllist_item  *curr = cork_dllist_start(bin);\n                while (!cork_dllist_is_end(bin, curr)) {\n                    struct cork_hash_table_entry_priv  *entry =\n                        cork_container_of\n                        (curr, struct cork_hash_table_entry_priv, in_bucket);\n                    struct cork_dllist_item  *next = curr->next;\n\n                    size_t  bin_index = bin_index(table, entry->public.hash);\n                    DEBUG(\"      Rehash %p from bin %zu to bin %zu\",\n                          entry, i, bin_index);\n                    cork_dllist_add(&table->bins[bin_index], curr);\n\n                    curr = next;\n                }\n            }\n\n            cork_cfree(old_bins, old_bin_count, sizeof(struct cork_dllist));\n        }\n    }\n}\n\n\nstatic void\ncork_hash_table_rehash(struct cork_hash_table *table)\n{\n    DEBUG(\"    Reached maximum density; rehash\");\n    cork_hash_table_ensure_size(table, table->bin_count + 1);\n}\n\n\nstruct cork_hash_table_entry *\ncork_hash_table_get_entry_hash(const struct cork_hash_table *table,\n                               cork_hash hash, const void *key)\n{\n    size_t  bin_index;\n    struct cork_dllist  *bin;\n    struct cork_dllist_item  *curr;\n\n    if (table->bin_count == 0) {\n        DEBUG(\"(get) Empty table when searching for key %p \"\n              \"(hash 0x%08\" PRIx32 \")\",\n              key, hash);\n        return NULL;\n    }\n\n    bin_index = bin_index(table, hash);\n    DEBUG(\"(get) Search for key %p (hash 0x%08\" PRIx32 \", bin %zu)\",\n          key, hash, bin_index);\n\n    bin = &table->bins[bin_index];\n    curr = cork_dllist_start(bin);\n    while (!cork_dllist_is_end(bin, curr)) {\n        struct cork_hash_table_entry_priv  *entry =\n            cork_container_of\n            (curr, struct cork_hash_table_entry_priv, in_bucket);\n\n        DEBUG(\"  Check entry %p\", entry);\n        if (table->equals(table->user_data, key, entry->public.key)) {\n            DEBUG(\"  Match\");\n            return &entry->public;\n        }\n\n        curr = curr->next;\n    }\n\n    DEBUG(\"  Entry not found\");\n    return NULL;\n}\n\nstruct cork_hash_table_entry *\ncork_hash_table_get_entry(const struct cork_hash_table *table, const void *key)\n{\n    cork_hash  hash = table->hash(table->user_data, key);\n    return cork_hash_table_get_entry_hash(table, hash, key);\n}\n\nvoid *\ncork_hash_table_get_hash(const struct cork_hash_table *table,\n                         cork_hash hash, const void *key)\n{\n    struct cork_hash_table_entry  *entry =\n        cork_hash_table_get_entry_hash(table, hash, key);\n    if (entry == NULL) {\n        return NULL;\n    } else {\n        DEBUG(\"  Extract value pointer %p\", entry->value);\n        return entry->value;\n    }\n}\n\nvoid *\ncork_hash_table_get(const struct cork_hash_table *table, const void *key)\n{\n    struct cork_hash_table_entry  *entry =\n        cork_hash_table_get_entry(table, key);\n    if (entry == NULL) {\n        return NULL;\n    } else {\n        DEBUG(\"  Extract value pointer %p\", entry->value);\n        return entry->value;\n    }\n}\n\n\nstruct cork_hash_table_entry *\ncork_hash_table_get_or_create_hash(struct cork_hash_table *table,\n                                   cork_hash hash, void *key, bool *is_new)\n{\n    struct cork_hash_table_entry_priv  *entry;\n    size_t  bin_index;\n\n    if (table->bin_count > 0) {\n        struct cork_dllist  *bin;\n        struct cork_dllist_item  *curr;\n\n        bin_index = bin_index(table, hash);\n        DEBUG(\"(get_or_create) Search for key %p \"\n              \"(hash 0x%08\" PRIx32 \", bin %zu)\",\n              key, hash, bin_index);\n\n        bin = &table->bins[bin_index];\n        curr = cork_dllist_start(bin);\n        while (!cork_dllist_is_end(bin, curr)) {\n            struct cork_hash_table_entry_priv  *entry =\n                cork_container_of\n                (curr, struct cork_hash_table_entry_priv, in_bucket);\n\n            DEBUG(\"  Check entry %p\", entry);\n            if (table->equals(table->user_data, key, entry->public.key)) {\n                DEBUG(\"    Match\");\n                DEBUG(\"    Return value pointer %p\", entry->public.value);\n                *is_new = false;\n                return &entry->public;\n            }\n\n            curr = curr->next;\n        }\n\n        /* create a new entry */\n        DEBUG(\"  Entry not found\");\n\n        if ((table->entry_count / table->bin_count) >\n            CORK_HASH_TABLE_MAX_DENSITY) {\n            cork_hash_table_rehash(table);\n            bin_index = bin_index(table, hash);\n        }\n    } else {\n        DEBUG(\"(get_or_create) Search for key %p (hash 0x%08\" PRIx32 \")\",\n              key, hash);\n        DEBUG(\"  Empty table\");\n        cork_hash_table_rehash(table);\n        bin_index = bin_index(table, hash);\n    }\n\n    DEBUG(\"    Allocate new entry\");\n    entry = cork_hash_table_new_entry(table, hash, key, NULL);\n    DEBUG(\"    Created new entry %p\", entry);\n\n    DEBUG(\"    Add entry into bin %zu\", bin_index);\n    cork_dllist_add(&table->bins[bin_index], &entry->in_bucket);\n\n    table->entry_count++;\n    *is_new = true;\n    return &entry->public;\n}\n\nstruct cork_hash_table_entry *\ncork_hash_table_get_or_create(struct cork_hash_table *table,\n                              void *key, bool *is_new)\n{\n    cork_hash  hash = table->hash(table->user_data, key);\n    return cork_hash_table_get_or_create_hash(table, hash, key, is_new);\n}\n\n\nvoid\ncork_hash_table_put_hash(struct cork_hash_table *table,\n                         cork_hash hash, void *key, void *value,\n                         bool *is_new, void **old_key, void **old_value)\n{\n    struct cork_hash_table_entry_priv  *entry;\n    size_t  bin_index;\n\n    if (table->bin_count > 0) {\n        struct cork_dllist  *bin;\n        struct cork_dllist_item  *curr;\n\n        bin_index = bin_index(table, hash);\n        DEBUG(\"(put) Search for key %p (hash 0x%08\" PRIx32 \", bin %zu)\",\n              key, hash, bin_index);\n\n        bin = &table->bins[bin_index];\n        curr = cork_dllist_start(bin);\n        while (!cork_dllist_is_end(bin, curr)) {\n            struct cork_hash_table_entry_priv  *entry =\n                cork_container_of\n                (curr, struct cork_hash_table_entry_priv, in_bucket);\n\n            DEBUG(\"  Check entry %p\", entry);\n            if (table->equals(table->user_data, key, entry->public.key)) {\n                DEBUG(\"    Found existing entry; overwriting\");\n                DEBUG(\"    Return old key %p\", entry->public.key);\n                if (old_key != NULL) {\n                    *old_key = entry->public.key;\n                }\n                DEBUG(\"    Return old value %p\", entry->public.value);\n                if (old_value != NULL) {\n                    *old_value = entry->public.value;\n                }\n                DEBUG(\"    Copy key %p into entry\", key);\n                entry->public.key = key;\n                DEBUG(\"    Copy value %p into entry\", value);\n                entry->public.value = value;\n                if (is_new != NULL) {\n                    *is_new = false;\n                }\n                return;\n            }\n\n            curr = curr->next;\n        }\n\n        /* create a new entry */\n        DEBUG(\"  Entry not found\");\n        if ((table->entry_count / table->bin_count) >\n            CORK_HASH_TABLE_MAX_DENSITY) {\n            cork_hash_table_rehash(table);\n            bin_index = bin_index(table, hash);\n        }\n    } else {\n        DEBUG(\"(put) Search for key %p (hash 0x%08\" PRIx32 \")\",\n              key, hash);\n        DEBUG(\"  Empty table\");\n        cork_hash_table_rehash(table);\n        bin_index = bin_index(table, hash);\n    }\n\n    DEBUG(\"    Allocate new entry\");\n    entry = cork_hash_table_new_entry(table, hash, key, value);\n    DEBUG(\"    Created new entry %p\", entry);\n\n    DEBUG(\"    Add entry into bin %zu\", bin_index);\n    cork_dllist_add(&table->bins[bin_index], &entry->in_bucket);\n\n    table->entry_count++;\n    if (old_key != NULL) {\n        *old_key = NULL;\n    }\n    if (old_value != NULL) {\n        *old_value = NULL;\n    }\n    if (is_new != NULL) {\n        *is_new = true;\n    }\n}\n\nvoid\ncork_hash_table_put(struct cork_hash_table *table,\n                    void *key, void *value,\n                    bool *is_new, void **old_key, void **old_value)\n{\n    cork_hash  hash = table->hash(table->user_data, key);\n    cork_hash_table_put_hash\n        (table, hash, key, value, is_new, old_key, old_value);\n}\n\n\nvoid\ncork_hash_table_delete_entry(struct cork_hash_table *table,\n                             struct cork_hash_table_entry *ventry)\n{\n    struct cork_hash_table_entry_priv  *entry =\n        cork_container_of(ventry, struct cork_hash_table_entry_priv, public);\n    cork_dllist_remove(&entry->in_bucket);\n    table->entry_count--;\n    cork_hash_table_free_entry(table, entry);\n}\n\n\nbool\ncork_hash_table_delete_hash(struct cork_hash_table *table,\n                            cork_hash hash, const void *key,\n                            void **deleted_key, void **deleted_value)\n{\n    size_t  bin_index;\n    struct cork_dllist  *bin;\n    struct cork_dllist_item  *curr;\n\n    if (table->bin_count == 0) {\n        DEBUG(\"(delete) Empty table when searching for key %p \"\n              \"(hash 0x%08\" PRIx32 \")\",\n              key, hash);\n        return false;\n    }\n\n    bin_index = bin_index(table, hash);\n    DEBUG(\"(delete) Search for key %p (hash 0x%08\" PRIx32 \", bin %zu)\",\n          key, hash, bin_index);\n\n    bin = &table->bins[bin_index];\n    curr = cork_dllist_start(bin);\n    while (!cork_dllist_is_end(bin, curr)) {\n        struct cork_hash_table_entry_priv  *entry =\n            cork_container_of\n            (curr, struct cork_hash_table_entry_priv, in_bucket);\n\n        DEBUG(\"  Check entry %p\", entry);\n        if (table->equals(table->user_data, key, entry->public.key)) {\n            DEBUG(\"    Match\");\n            if (deleted_key != NULL) {\n                *deleted_key = entry->public.key;\n            }\n            if (deleted_value != NULL) {\n                *deleted_value = entry->public.value;\n            }\n\n            DEBUG(\"    Remove entry from hash bin %zu\", bin_index);\n            cork_dllist_remove(curr);\n            table->entry_count--;\n\n            DEBUG(\"    Free entry %p\", entry);\n            cork_hash_table_free_entry(table, entry);\n            return true;\n        }\n\n        curr = curr->next;\n    }\n\n    DEBUG(\"  Entry not found\");\n    return false;\n}\n\nbool\ncork_hash_table_delete(struct cork_hash_table *table, const void *key,\n                       void **deleted_key, void **deleted_value)\n{\n    cork_hash  hash = table->hash(table->user_data, key);\n    return cork_hash_table_delete_hash\n        (table, hash, key, deleted_key, deleted_value);\n}\n\n\nvoid\ncork_hash_table_map(struct cork_hash_table *table, void *user_data,\n                    cork_hash_table_map_f map)\n{\n    struct cork_dllist_item  *curr;\n    DEBUG(\"Map across hash table\");\n\n    curr = cork_dllist_start(&table->insertion_order);\n    while (!cork_dllist_is_end(&table->insertion_order, curr)) {\n        struct cork_hash_table_entry_priv  *entry =\n            cork_container_of\n            (curr, struct cork_hash_table_entry_priv, insertion_order);\n        struct cork_dllist_item  *next = curr->next;\n        enum cork_hash_table_map_result  result;\n\n        DEBUG(\"    Apply function to entry %p\", entry);\n        result = map(user_data, &entry->public);\n\n        if (result == CORK_HASH_TABLE_MAP_ABORT) {\n            return;\n        } else if (result == CORK_HASH_TABLE_MAP_DELETE) {\n            DEBUG(\"      Delete requested\");\n            cork_dllist_remove(curr);\n            cork_dllist_remove(&entry->in_bucket);\n            table->entry_count--;\n            cork_hash_table_free_entry(table, entry);\n        }\n\n        curr = next;\n    }\n}\n\n\nvoid\ncork_hash_table_iterator_init(struct cork_hash_table *table,\n                              struct cork_hash_table_iterator *iterator)\n{\n    DEBUG(\"Iterate through hash table\");\n    iterator->table = table;\n    iterator->priv = cork_dllist_start(&table->insertion_order);\n}\n\n\nstruct cork_hash_table_entry *\ncork_hash_table_iterator_next(struct cork_hash_table_iterator *iterator)\n{\n    struct cork_hash_table  *table = iterator->table;\n    struct cork_dllist_item  *curr = iterator->priv;\n    struct cork_hash_table_entry_priv  *entry;\n\n    if (cork_dllist_is_end(&table->insertion_order, curr)) {\n        return NULL;\n    }\n\n    entry = cork_container_of\n        (curr, struct cork_hash_table_entry_priv, insertion_order);\n    DEBUG(\"    Return entry %p\", entry);\n    iterator->priv = curr->next;\n    return &entry->public;\n}\n\n\n/*-----------------------------------------------------------------------\n * Built-in key types\n */\n\nstatic cork_hash\nstring_hash(void *user_data, const void *vk)\n{\n    const char  *k = vk;\n    size_t  len = strlen(k);\n    return cork_hash_buffer(0, k, len);\n}\n\nstatic bool\nstring_equals(void *user_data, const void *vk1, const void *vk2)\n{\n    const char  *k1 = vk1;\n    const char  *k2 = vk2;\n    return strcmp(k1, k2) == 0;\n}\n\nstruct cork_hash_table *\ncork_string_hash_table_new(size_t initial_size, unsigned int flags)\n{\n    struct cork_hash_table  *table = cork_hash_table_new(initial_size, flags);\n    cork_hash_table_set_hash(table, string_hash);\n    cork_hash_table_set_equals(table, string_equals);\n    return table;\n}\n\nstruct cork_hash_table *\ncork_pointer_hash_table_new(size_t initial_size, unsigned int flags)\n{\n    return cork_hash_table_new(initial_size, flags);\n}\n"
  },
  {
    "path": "src/libcork/ds/managed-buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/managed-buffer.h\"\n#include \"libcork/ds/slice.h\"\n#include \"libcork/helpers/errors.h\"\n\n\n/*-----------------------------------------------------------------------\n * Error handling\n */\n\nstatic void\ncork_slice_invalid_slice_set(size_t buf_size, size_t requested_offset,\n                             size_t requested_length)\n{\n    cork_error_set\n        (CORK_SLICE_ERROR, CORK_SLICE_INVALID_SLICE,\n         \"Cannot slice %zu-byte buffer at %zu:%zu\",\n         buf_size, requested_offset, requested_length);\n}\n\n\n/*-----------------------------------------------------------------------\n * Managed buffers\n */\n\nstruct cork_managed_buffer_wrapped {\n    struct cork_managed_buffer  parent;\n    void  *buf;\n    size_t  size;\n    cork_managed_buffer_freer  free;\n};\n\nstatic void\ncork_managed_buffer_wrapped__free(struct cork_managed_buffer *vself)\n{\n    struct cork_managed_buffer_wrapped  *self =\n        cork_container_of(vself, struct cork_managed_buffer_wrapped, parent);\n    self->free(self->buf, self->size);\n    cork_delete(struct cork_managed_buffer_wrapped, self);\n}\n\nstatic struct cork_managed_buffer_iface  CORK_MANAGED_BUFFER_WRAPPED = {\n    cork_managed_buffer_wrapped__free\n};\n\nstruct cork_managed_buffer *\ncork_managed_buffer_new(const void *buf, size_t size,\n                        cork_managed_buffer_freer free)\n{\n    /*\n    DEBUG(\"Creating new struct cork_managed_buffer [%p:%zu], refcount now 1\",\n          buf, size);\n    */\n\n    struct cork_managed_buffer_wrapped  *self =\n        cork_new(struct cork_managed_buffer_wrapped);\n    self->parent.buf = buf;\n    self->parent.size = size;\n    self->parent.ref_count = 1;\n    self->parent.iface = &CORK_MANAGED_BUFFER_WRAPPED;\n    self->buf = (void *) buf;\n    self->size = size;\n    self->free = free;\n    return &self->parent;\n}\n\n\nstruct cork_managed_buffer_copied {\n    struct cork_managed_buffer  parent;\n};\n\n#define cork_managed_buffer_copied_data(self) \\\n    (((void *) (self)) + sizeof(struct cork_managed_buffer_copied))\n\n#define cork_managed_buffer_copied_sizeof(sz) \\\n    ((sz) + sizeof(struct cork_managed_buffer_copied))\n\nstatic void\ncork_managed_buffer_copied__free(struct cork_managed_buffer *vself)\n{\n    struct cork_managed_buffer_copied  *self =\n        cork_container_of(vself, struct cork_managed_buffer_copied, parent);\n    size_t  allocated_size =\n        cork_managed_buffer_copied_sizeof(self->parent.size);\n    cork_free(self, allocated_size);\n}\n\nstatic struct cork_managed_buffer_iface  CORK_MANAGED_BUFFER_COPIED = {\n    cork_managed_buffer_copied__free\n};\n\nstruct cork_managed_buffer *\ncork_managed_buffer_new_copy(const void *buf, size_t size)\n{\n    size_t  allocated_size = cork_managed_buffer_copied_sizeof(size);\n    struct cork_managed_buffer_copied  *self = cork_malloc(allocated_size);\n    if (self == NULL) {\n        return NULL;\n    }\n\n    self->parent.buf = cork_managed_buffer_copied_data(self);\n    self->parent.size = size;\n    self->parent.ref_count = 1;\n    self->parent.iface = &CORK_MANAGED_BUFFER_COPIED;\n    memcpy((void *) self->parent.buf, buf, size);\n    return &self->parent;\n}\n\n\nstatic void\ncork_managed_buffer_free(struct cork_managed_buffer *self)\n{\n    /*\n    DEBUG(\"Freeing struct cork_managed_buffer [%p:%zu]\", self->buf, self->size);\n    */\n\n    self->iface->free(self);\n}\n\n\nstruct cork_managed_buffer *\ncork_managed_buffer_ref(struct cork_managed_buffer *self)\n{\n    /*\n    int  old_count = self->ref_count++;\n    DEBUG(\"Referencing struct cork_managed_buffer [%p:%zu], refcount now %d\",\n          self->buf, self->size, old_count + 1);\n    */\n\n    self->ref_count++;\n    return self;\n}\n\n\nvoid\ncork_managed_buffer_unref(struct cork_managed_buffer *self)\n{\n    /*\n    int  old_count = self->ref_count--;\n    DEBUG(\"Dereferencing struct cork_managed_buffer [%p:%zu], refcount now %d\",\n          self->buf, self->size, old_count - 1);\n    */\n\n    if (--self->ref_count == 0) {\n        cork_managed_buffer_free(self);\n    }\n}\n\n\nstatic struct cork_slice_iface  CORK_MANAGED_BUFFER__SLICE;\n\nstatic void\ncork_managed_buffer__slice_free(struct cork_slice *self)\n{\n    struct cork_managed_buffer  *mbuf = self->user_data;\n    cork_managed_buffer_unref(mbuf);\n}\n\nstatic int\ncork_managed_buffer__slice_copy(struct cork_slice *dest,\n                                const struct cork_slice *src,\n                                size_t offset, size_t length)\n{\n    struct cork_managed_buffer  *mbuf = src->user_data;\n    dest->buf = src->buf + offset;\n    dest->size = length;\n    dest->iface = &CORK_MANAGED_BUFFER__SLICE;\n    dest->user_data = cork_managed_buffer_ref(mbuf);\n    return 0;\n}\n\nstatic struct cork_slice_iface  CORK_MANAGED_BUFFER__SLICE = {\n    cork_managed_buffer__slice_free,\n    cork_managed_buffer__slice_copy,\n    cork_managed_buffer__slice_copy,\n    NULL\n};\n\n\nint\ncork_managed_buffer_slice(struct cork_slice *dest,\n                          struct cork_managed_buffer *buffer,\n                          size_t offset, size_t length)\n{\n    if ((buffer != NULL) &&\n        (offset <= buffer->size) &&\n        ((offset + length) <= buffer->size)) {\n        /*\n        DEBUG(\"Slicing [%p:%zu] at %zu:%zu, gives <%p:%zu>\",\n              buffer->buf, buffer->size,\n              offset, length,\n              buffer->buf + offset, length);\n        */\n        dest->buf = buffer->buf + offset;\n        dest->size = length;\n        dest->iface = &CORK_MANAGED_BUFFER__SLICE;\n        dest->user_data = cork_managed_buffer_ref(buffer);\n        return 0;\n    }\n\n    else {\n        /*\n        DEBUG(\"Cannot slice [%p:%zu] at %zu:%zu\",\n              buffer->buf, buffer->size,\n              offset, length);\n        */\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return -1;\n    }\n}\n\n\nint\ncork_managed_buffer_slice_offset(struct cork_slice *dest,\n                                 struct cork_managed_buffer *buffer,\n                                 size_t offset)\n{\n    if (buffer == NULL) {\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return -1;\n    } else {\n        return cork_managed_buffer_slice\n            (dest, buffer, offset, buffer->size - offset);\n    }\n}\n"
  },
  {
    "path": "src/libcork/ds/ring-buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/ring-buffer.h\"\n\n\nint\ncork_ring_buffer_init(struct cork_ring_buffer *self, size_t size)\n{\n    self->elements = cork_calloc(size, sizeof(void *));\n    self->allocated_size = size;\n    self->size = 0;\n    self->read_index = 0;\n    self->write_index = 0;\n    return 0;\n}\n\nstruct cork_ring_buffer *\ncork_ring_buffer_new(size_t size)\n{\n    struct cork_ring_buffer  *buf = cork_new(struct cork_ring_buffer);\n    cork_ring_buffer_init(buf, size);\n    return buf;\n}\n\nvoid\ncork_ring_buffer_done(struct cork_ring_buffer *self)\n{\n    cork_cfree(self->elements, self->allocated_size, sizeof(void *));\n}\n\nvoid\ncork_ring_buffer_free(struct cork_ring_buffer *buf)\n{\n    cork_ring_buffer_done(buf);\n    cork_delete(struct cork_ring_buffer, buf);\n}\n\nint\ncork_ring_buffer_add(struct cork_ring_buffer *self, void *element)\n{\n    if (cork_ring_buffer_is_full(self)) {\n        return -1;\n    }\n\n    self->elements[self->write_index++] = element;\n    self->size++;\n    if (self->write_index == self->allocated_size) {\n        self->write_index = 0;\n    }\n    return 0;\n}\n\nvoid *\ncork_ring_buffer_pop(struct cork_ring_buffer *self)\n{\n    if (cork_ring_buffer_is_empty(self)) {\n        return NULL;\n    } else {\n        void  *result = self->elements[self->read_index++];\n        self->size--;\n        if (self->read_index == self->allocated_size) {\n            self->read_index = 0;\n        }\n        return result;\n    }\n}\n\nvoid *\ncork_ring_buffer_peek(struct cork_ring_buffer *self)\n{\n    if (cork_ring_buffer_is_empty(self)) {\n        return NULL;\n    } else {\n        return self->elements[self->read_index];\n    }\n}\n"
  },
  {
    "path": "src/libcork/ds/slice.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <string.h>\n\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/managed-buffer.h\"\n#include \"libcork/ds/slice.h\"\n#include \"libcork/helpers/errors.h\"\n\n\n/*-----------------------------------------------------------------------\n * Error handling\n */\n\nstatic void\ncork_slice_invalid_slice_set(size_t buf_size, size_t requested_offset,\n                             size_t requested_length)\n{\n    cork_error_set\n        (CORK_SLICE_ERROR, CORK_SLICE_INVALID_SLICE,\n         \"Cannot slice %zu-byte buffer at %zu:%zu\",\n         buf_size, requested_offset, requested_length);\n}\n\n\n/*-----------------------------------------------------------------------\n * Slices\n */\n\nvoid\ncork_slice_clear(struct cork_slice *slice)\n{\n    slice->buf = NULL;\n    slice->size = 0;\n    slice->iface = NULL;\n    slice->user_data = NULL;\n}\n\n\nint\ncork_slice_copy(struct cork_slice *dest, const struct cork_slice *slice,\n                size_t offset, size_t length)\n{\n    if ((slice != NULL) &&\n        (offset <= slice->size) &&\n        ((offset + length) <= slice->size)) {\n        /*\n        DEBUG(\"Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>\",\n              slice->buf, slice->size,\n              offset, length,\n              slice->buf + offset, length);\n        */\n        return slice->iface->copy(dest, slice, offset, length);\n    }\n\n    else {\n        /*\n        DEBUG(\"Cannot slice <%p:%zu> at %zu:%zu\",\n              slice->buf, slice->size,\n              offset, length);\n        */\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set\n            ((slice == NULL)? 0: slice->size, offset, length);\n        return -1;\n    }\n}\n\n\nint\ncork_slice_copy_offset(struct cork_slice *dest, const struct cork_slice *slice,\n                       size_t offset)\n{\n    if (slice == NULL) {\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return -1;\n    } else {\n        return cork_slice_copy\n            (dest, slice, offset, slice->size - offset);\n    }\n}\n\n\nint\ncork_slice_light_copy(struct cork_slice *dest, const struct cork_slice *slice,\n                      size_t offset, size_t length)\n{\n    if ((slice != NULL) &&\n        (offset <= slice->size) &&\n        ((offset + length) <= slice->size)) {\n        /*\n        DEBUG(\"Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>\",\n              slice->buf, slice->size,\n              offset, length,\n              slice->buf + offset, length);\n        */\n        return slice->iface->light_copy(dest, slice, offset, length);\n    }\n\n    else {\n        /*\n        DEBUG(\"Cannot slice <%p:%zu> at %zu:%zu\",\n              slice->buf, slice->size,\n              offset, length);\n        */\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set\n            ((slice == NULL)? 0: slice->size, offset, length);\n        return -1;\n    }\n}\n\n\nint\ncork_slice_light_copy_offset(struct cork_slice *dest,\n                             const struct cork_slice *slice, size_t offset)\n{\n    if (slice == NULL) {\n        cork_slice_clear(dest);\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return -1;\n    } else {\n        return cork_slice_light_copy\n            (dest, slice, offset, slice->size - offset);\n    }\n}\n\n\nint\ncork_slice_slice(struct cork_slice *slice, size_t offset, size_t length)\n{\n    if ((slice != NULL) &&\n        (offset <= slice->size) &&\n        ((offset + length) <= slice->size)) {\n        /*\n        DEBUG(\"Slicing <%p:%zu> at %zu:%zu, gives <%p:%zu>\",\n              slice->buf, slice->size,\n              offset, length,\n              slice->buf + offset, length);\n        */\n        if (slice->iface->slice == NULL) {\n            slice->buf += offset;\n            slice->size = length;\n            return 0;\n        } else {\n            return slice->iface->slice(slice, offset, length);\n        }\n    }\n\n    else {\n        /*\n        DEBUG(\"Cannot slice <%p:%zu> at %zu:%zu\",\n              slice->buf, slice->size,\n              offset, length);\n        */\n        if (slice != NULL)\n            cork_slice_invalid_slice_set(slice->size, offset, length);\n        return -1;\n    }\n}\n\n\nint\ncork_slice_slice_offset(struct cork_slice *slice, size_t offset)\n{\n    if (slice == NULL) {\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return -1;\n    } else {\n        return cork_slice_slice\n            (slice, offset, slice->size - offset);\n    }\n}\n\n\nconst void*\ncork_slice_advance_checked(struct cork_slice* slice, size_t offset)\n{\n    if (slice == NULL) {\n        cork_slice_invalid_slice_set(0, offset, 0);\n        return NULL;\n    } else {\n        const void* buf = slice->buf;\n        rpi_check(cork_slice_slice(slice, offset, slice->size - offset));\n        return buf;\n    }\n}\n\n\nvoid\ncork_slice_finish(struct cork_slice *slice)\n{\n    /*\n    DEBUG(\"Finalizing <%p:%zu>\", dest->buf, dest->size);\n    */\n\n    if (slice->iface != NULL && slice->iface->free != NULL) {\n        slice->iface->free(slice);\n    }\n\n    cork_slice_clear(slice);\n}\n\n\nbool\ncork_slice_equal(const struct cork_slice *slice1,\n                 const struct cork_slice *slice2)\n{\n    if (slice1 == slice2) {\n        return true;\n    }\n\n    if (slice1->size != slice2->size) {\n        return false;\n    }\n\n    return (memcmp(slice1->buf, slice2->buf, slice1->size) == 0);\n}\n\n\n/*-----------------------------------------------------------------------\n * Slices of static content\n */\n\nstatic struct cork_slice_iface  cork_static_slice;\n\nstatic int\ncork_static_slice_copy(struct cork_slice *dest, const struct cork_slice *src,\n                       size_t offset, size_t length)\n{\n    dest->buf = src->buf + offset;\n    dest->size = length;\n    dest->iface = &cork_static_slice;\n    dest->user_data = NULL;\n    return 0;\n}\n\nstatic struct cork_slice_iface  cork_static_slice = {\n    NULL,\n    cork_static_slice_copy,\n    cork_static_slice_copy,\n    NULL\n};\n\nvoid\ncork_slice_init_static(struct cork_slice *dest, const void *buf, size_t size)\n{\n    dest->buf = buf;\n    dest->size = size;\n    dest->iface = &cork_static_slice;\n    dest->user_data = NULL;\n}\n\n\n/*-----------------------------------------------------------------------\n * Copy-once slices\n */\n\nstatic struct cork_slice_iface  cork_copy_once_slice;\n\nstatic int\ncork_copy_once_slice__copy(struct cork_slice *dest,\n                           const struct cork_slice *src,\n                           size_t offset, size_t length)\n{\n    struct cork_managed_buffer  *mbuf =\n        cork_managed_buffer_new_copy(src->buf, src->size);\n    rii_check(cork_managed_buffer_slice(dest, mbuf, offset, length));\n    rii_check(cork_managed_buffer_slice\n              ((struct cork_slice *) src, mbuf, 0, src->size));\n    cork_managed_buffer_unref(mbuf);\n    return 0;\n}\n\nstatic int\ncork_copy_once_slice__light_copy(struct cork_slice *dest,\n                                 const struct cork_slice *src,\n                                 size_t offset, size_t length)\n{\n    dest->buf = src->buf + offset;\n    dest->size = length;\n    dest->iface = &cork_copy_once_slice;\n    dest->user_data = NULL;\n    return 0;\n}\n\nstatic struct cork_slice_iface  cork_copy_once_slice = {\n    NULL,\n    cork_copy_once_slice__copy,\n    cork_copy_once_slice__light_copy,\n    NULL\n};\n\nvoid\ncork_slice_init_copy_once(struct cork_slice *dest, const void *buf, size_t size)\n{\n    dest->buf = buf;\n    dest->size = size;\n    dest->iface = &cork_copy_once_slice;\n    dest->user_data = NULL;\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nbool\ncork_slice_is_empty(const struct cork_slice* slice);\n\nint\ncork_slice_copy_fast(struct cork_slice* dest, const struct cork_slice* slice,\n                     size_t offset, size_t length);\n\nint\ncork_slice_copy_offset_fast(struct cork_slice *dest,\n                            const struct cork_slice *slice, size_t offset);\n\nint\ncork_slice_light_copy_fast(struct cork_slice *dest,\n                           const struct cork_slice *slice, size_t offset,\n                           size_t length);\n\nint\ncork_slice_light_copy_offset_fast(struct cork_slice *dest,\n                                  const struct cork_slice *slice,\n                                  size_t offset);\n\nint\ncork_slice_slice_fast(struct cork_slice *slice, size_t offset, size_t length);\n\nint\ncork_slice_slice_offset_fast(struct cork_slice *slice, size_t offset);\n\nconst void*\ncork_slice_advance(struct cork_slice *slice, size_t offset);\n"
  },
  {
    "path": "src/libcork/ds/stream.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2020, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include \"libcork/ds/stream.h\"\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nint\ncork_stream_consumer_data(struct cork_stream_consumer* consumer,\n                          const void *buf, size_t size, bool is_first_chunk);\n\nint\ncork_stream_consumer_eof(struct cork_stream_consumer *consumer);\n\nvoid\ncork_stream_consumer_free(struct cork_stream_consumer *consumer);\n"
  },
  {
    "path": "src/libcork/posix/directory-walker.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <dirent.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"libcork/core/attributes.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/helpers/errors.h\"\n#include \"libcork/helpers/posix.h\"\n#include \"libcork/os/files.h\"\n\n\nstatic int\ncork_walk_one_directory(struct cork_dir_walker *w, struct cork_buffer *path,\n                        size_t root_path_size)\n{\n    DIR  *dir = NULL;\n    struct dirent  *entry;\n    size_t  dir_path_size;\n\n    rip_check_posix(dir = opendir(path->buf));\n\n    cork_buffer_append(path, \"/\", 1);\n    dir_path_size = path->size;\n    errno = 0;\n    while ((entry = readdir(dir)) != NULL) {\n        struct stat  info;\n\n        /* Skip the \".\" and \"..\" entries */\n        if (strcmp(entry->d_name, \".\") == 0 ||\n            strcmp(entry->d_name, \"..\") == 0) {\n            continue;\n        }\n\n        /* Stat the directory entry */\n        cork_buffer_append_string(path, entry->d_name);\n        ei_check_posix(stat(path->buf, &info));\n\n        /* If the entry is a subdirectory, recurse into it. */\n        if (S_ISDIR(info.st_mode)) {\n            int  rc = cork_dir_walker_enter_directory\n                (w, path->buf, path->buf + root_path_size,\n                 path->buf + dir_path_size);\n            if (rc != CORK_SKIP_DIRECTORY) {\n                ei_check(cork_walk_one_directory(w, path, root_path_size));\n                ei_check(cork_dir_walker_leave_directory\n                         (w, path->buf, path->buf + root_path_size,\n                          path->buf + dir_path_size));\n            }\n        } else if (S_ISREG(info.st_mode)) {\n            ei_check(cork_dir_walker_file\n                     (w, path->buf, path->buf + root_path_size,\n                      path->buf + dir_path_size));\n        }\n\n        /* Remove this entry name from the path buffer. */\n        cork_buffer_truncate(path, dir_path_size);\n\n        /* We have to reset errno to 0 because of the ambiguous way\n         * readdir uses a return value of NULL.  Other functions may\n         * return normally yet set errno to a non-zero value.  dlopen\n         * on Mac OS X is an ogreish example.  Since an error readdir\n         * is indicated by returning NULL and setting errno to indicate\n         * the error, then we need to reset it to zero before each call.\n         * We shall assume, perhaps to our great misery, that functions\n         * within this loop do proper error checking and act accordingly.\n         */\n        errno = 0;\n    }\n\n    /* Check errno immediately after the while loop terminates */\n    if (CORK_UNLIKELY(errno != 0)) {\n        cork_system_error_set();\n        goto error;\n    }\n\n    /* Remove the trailing '/' from the path buffer. */\n    cork_buffer_truncate(path, dir_path_size - 1);\n    rii_check_posix(closedir(dir));\n    return 0;\n\nerror:\n    if (dir != NULL) {\n        rii_check_posix(closedir(dir));\n    }\n    return -1;\n}\n\nint\ncork_walk_directory(const char *path, struct cork_dir_walker *w)\n{\n    int  rc;\n    char  *p;\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n\n    /* Seed the buffer with the directory's path, ensuring that there's no\n     * trailing '/' */\n    cork_buffer_append_string(&buf, path);\n    p = buf.buf;\n    while (p[buf.size-1] == '/') {\n        buf.size--;\n        p[buf.size] = '\\0';\n    }\n    rc = cork_walk_one_directory(w, &buf, buf.size + 1);\n    cork_buffer_done(&buf);\n    return rc;\n}\n"
  },
  {
    "path": "src/libcork/posix/env.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os/subprocess.h\"\n#include \"libcork/helpers/errors.h\"\n\n#ifdef __CYGWIN__\n#include <cygwin/version.h>\n#endif\n\n#if defined(__APPLE__)\n/* Apple doesn't provide access to the \"environ\" variable from a shared library.\n * There's a workaround function to grab the environ pointer described at [1].\n *\n * [1] http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man7/environ.7.html\n */\n#include <crt_externs.h>\n#define environ  (*_NSGetEnviron())\n\n#else\n/* On all other POSIX platforms, we assume that environ is available in shared\n * libraries. */\nextern char  **environ;\n\n#endif\n\n\nstruct cork_env_var {\n    const char  *name;\n    const char  *value;\n};\n\nstatic struct cork_env_var *\ncork_env_var_new(const char *name, const char *value)\n{\n    struct cork_env_var  *var = cork_new(struct cork_env_var);\n    var->name = cork_strdup(name);\n    var->value = cork_strdup(value);\n    return var;\n}\n\nstatic void\ncork_env_var_free(void *vvar)\n{\n    struct cork_env_var  *var = vvar;\n    cork_strfree(var->name);\n    cork_strfree(var->value);\n    cork_delete(struct cork_env_var, var);\n}\n\n\nstruct cork_env {\n    struct cork_hash_table  *variables;\n    struct cork_buffer  buffer;\n};\n\nstruct cork_env *\ncork_env_new(void)\n{\n    struct cork_env  *env = cork_new(struct cork_env);\n    env->variables = cork_string_hash_table_new(0, 0);\n    cork_hash_table_set_free_value(env->variables, cork_env_var_free);\n    cork_buffer_init(&env->buffer);\n    return env;\n}\n\nstatic void\ncork_env_add_internal(struct cork_env *env, const char *name, const char *value)\n{\n    if (env == NULL) {\n        setenv(name, value, true);\n    } else {\n        struct cork_env_var  *var = cork_env_var_new(name, value);\n        void  *old_var;\n\n        cork_hash_table_put\n            (env->variables, (void *) var->name, var, NULL, NULL, &old_var);\n\n        if (old_var != NULL) {\n            cork_env_var_free(old_var);\n        }\n    }\n}\n\nstruct cork_env *\ncork_env_clone_current(void)\n{\n    char  **curr;\n    struct cork_env  *env = cork_env_new();\n\n    for (curr = environ; *curr != NULL; curr++) {\n        const char  *entry = *curr;\n        const char  *equal;\n\n        equal = strchr(entry, '=');\n        if (CORK_UNLIKELY(equal == NULL)) {\n            /* This environment entry is malformed; skip it. */\n            continue;\n        }\n\n        /* Make a copy of the name so that it's NUL-terminated rather than\n         * equal-terminated. */\n        cork_buffer_set(&env->buffer, entry, equal - entry);\n        cork_env_add_internal(env, env->buffer.buf, equal + 1);\n    }\n\n    return env;\n}\n\n\nvoid\ncork_env_free(struct cork_env *env)\n{\n    cork_hash_table_free(env->variables);\n    cork_buffer_done(&env->buffer);\n    cork_delete(struct cork_env, env);\n}\n\nconst char *\ncork_env_get(struct cork_env *env, const char *name)\n{\n    if (env == NULL) {\n        return getenv(name);\n    } else {\n        struct cork_env_var  *var =\n            cork_hash_table_get(env->variables, (void *) name);\n        return (var == NULL)? NULL: var->value;\n    }\n}\n\nvoid\ncork_env_add(struct cork_env *env, const char *name, const char *value)\n{\n    cork_env_add_internal(env, name, value);\n}\n\nvoid\ncork_env_add_vprintf(struct cork_env *env, const char *name,\n                     const char *format, va_list args)\n{\n    cork_buffer_vprintf(&env->buffer, format, args);\n    cork_env_add_internal(env, name, env->buffer.buf);\n}\n\nvoid\ncork_env_add_printf(struct cork_env *env, const char *name,\n                    const char *format, ...)\n{\n    va_list  args;\n    va_start(args, format);\n    cork_env_add_vprintf(env, name, format, args);\n    va_end(args);\n}\n\nvoid\ncork_env_remove(struct cork_env *env, const char *name)\n{\n    if (env == NULL) {\n        unsetenv(name);\n    } else {\n        void  *old_var;\n        cork_hash_table_delete(env->variables, (void *) name, NULL, &old_var);\n        if (old_var != NULL) {\n            cork_env_var_free(old_var);\n        }\n    }\n}\n\n\nstatic enum cork_hash_table_map_result\ncork_env_set_vars(void *user_data, struct cork_hash_table_entry *entry)\n{\n    struct cork_env_var  *var = entry->value;\n    setenv(var->name, var->value, false);\n    return CORK_HASH_TABLE_MAP_CONTINUE;\n}\n\n#if (defined(__APPLE__) || (defined(BSD) && (BSD >= 199103)) || (defined(__CYGWIN__) && CYGWIN_VERSION_API_MINOR < 326)) && !defined(__GNU__)\n/* A handful of platforms [1] don't provide clearenv(), so we must implement our\n * own version that clears the environ array directly.\n *\n * [1] http://www.gnu.org/software/gnulib/manual/html_node/clearenv.html\n */\nstatic void\nclearenv(void)\n{\n    *environ = NULL;\n}\n\n#else\n/* Otherwise assume that we have clearenv available. */\n#endif\n\nvoid\ncork_env_replace_current(struct cork_env *env)\n{\n    clearenv();\n    cork_hash_table_map(env->variables, NULL, cork_env_set_vars);\n}\n"
  },
  {
    "path": "src/libcork/posix/exec.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <errno.h>\n#include <unistd.h>\n\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os/subprocess.h\"\n#include \"libcork/helpers/errors.h\"\n\n#define ri_check_posix(call) \\\n    do { \\\n        while (true) { \\\n            if ((call) == -1) { \\\n                if (errno == EINTR) { \\\n                    continue; \\\n                } else { \\\n                    cork_system_error_set(); \\\n                    CORK_PRINT_ERROR(); \\\n                    return -1; \\\n                } \\\n            } else { \\\n                break; \\\n            } \\\n        } \\\n    } while (0)\n\n\nstruct cork_exec {\n    const char  *program;\n    struct cork_string_array  params;\n    struct cork_env  *env;\n    const char  *cwd;\n    struct cork_buffer  description;\n};\n\nstruct cork_exec *\ncork_exec_new(const char *program)\n{\n    struct cork_exec  *exec = cork_new(struct cork_exec);\n    exec->program = cork_strdup(program);\n    cork_string_array_init(&exec->params);\n    exec->env = NULL;\n    exec->cwd = NULL;\n    cork_buffer_init(&exec->description);\n    cork_buffer_set_string(&exec->description, program);\n    return exec;\n}\n\nstruct cork_exec *\ncork_exec_new_with_params(const char *program, ...)\n{\n    struct cork_exec  *exec;\n    va_list  args;\n    const char  *param;\n\n    exec = cork_exec_new(program);\n    cork_exec_add_param(exec, program);\n    va_start(args, program);\n    while ((param = va_arg(args, const char *)) != NULL) {\n        cork_exec_add_param(exec, param);\n    }\n    return exec;\n}\n\nstruct cork_exec *\ncork_exec_new_with_param_array(const char *program, char * const *params)\n{\n    char * const  *curr;\n    struct cork_exec  *exec = cork_exec_new(program);\n    for (curr = params; *curr != NULL; curr++) {\n        cork_exec_add_param(exec, *curr);\n    }\n    return exec;\n}\n\nvoid\ncork_exec_free(struct cork_exec *exec)\n{\n    cork_strfree(exec->program);\n    cork_array_done(&exec->params);\n    if (exec->env != NULL) {\n        cork_env_free(exec->env);\n    }\n    if (exec->cwd != NULL) {\n        cork_strfree(exec->cwd);\n    }\n    cork_buffer_done(&exec->description);\n    cork_delete(struct cork_exec, exec);\n}\n\nconst char *\ncork_exec_description(struct cork_exec *exec)\n{\n    return exec->description.buf;\n}\n\nconst char *\ncork_exec_program(struct cork_exec *exec)\n{\n    return exec->program;\n}\n\nsize_t\ncork_exec_param_count(struct cork_exec *exec)\n{\n    return cork_array_size(&exec->params);\n}\n\nconst char *\ncork_exec_param(struct cork_exec *exec, size_t index)\n{\n    return cork_array_at(&exec->params, index);\n}\n\nvoid\ncork_exec_add_param(struct cork_exec *exec, const char *param)\n{\n    /* Don't add the first parameter to the description; that's a copy of the\n     * program name, which we've already added. */\n    if (!cork_array_is_empty(&exec->params)) {\n        cork_buffer_append(&exec->description, \" \", 1);\n        cork_buffer_append_string(&exec->description, param);\n    }\n    cork_array_append(&exec->params, cork_strdup(param));\n}\n\nstruct cork_env *\ncork_exec_env(struct cork_exec *exec)\n{\n    return exec->env;\n}\n\nvoid\ncork_exec_set_env(struct cork_exec *exec, struct cork_env *env)\n{\n    if (exec->env != NULL) {\n        cork_env_free(exec->env);\n    }\n    exec->env = env;\n}\n\nconst char *\ncork_exec_cwd(struct cork_exec *exec)\n{\n    return exec->cwd;\n}\n\nvoid\ncork_exec_set_cwd(struct cork_exec *exec, const char *directory)\n{\n    if (exec->cwd != NULL) {\n        cork_strfree(exec->cwd);\n    }\n    exec->cwd = cork_strdup(directory);\n}\n\nint\ncork_exec_run(struct cork_exec *exec)\n{\n    const char  **params;\n\n    /* Make sure the parameter array is NULL-terminated. */\n    cork_array_append(&exec->params, NULL);\n    params = cork_array_elements(&exec->params);\n\n    /* Fill in the requested environment */\n    if (exec->env != NULL) {\n        cork_env_replace_current(exec->env);\n    }\n\n    /* Change the working directory, if requested */\n    if (exec->cwd != NULL) {\n        ri_check_posix(chdir(exec->cwd));\n    }\n\n    /* Execute the new program */\n    ri_check_posix(execvp(exec->program, (char * const *) params));\n\n    /* This is unreachable */\n    return 0;\n}\n"
  },
  {
    "path": "src/libcork/posix/files.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifdef __GNU__\n#define _GNU_SOURCE\n#endif\n#include <assert.h>\n#include <dirent.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include \"libcork/core/attributes.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/array.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/helpers/errors.h\"\n#include \"libcork/helpers/posix.h\"\n#include \"libcork/os/files.h\"\n#include \"libcork/os/subprocess.h\"\n\n\n#if !defined(CORK_DEBUG_FILES)\n#define CORK_DEBUG_FILES  0\n#endif\n\n#if CORK_DEBUG_FILES\n#include <stdio.h>\n#define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define DEBUG(...) /* no debug messages */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Paths\n */\n\nstruct cork_path {\n    struct cork_buffer  given;\n};\n\nstatic struct cork_path *\ncork_path_new_internal(const char *str, size_t length)\n{\n    struct cork_path  *path = cork_new(struct cork_path);\n    cork_buffer_init(&path->given);\n    if (length == 0) {\n        cork_buffer_ensure_size(&path->given, 16);\n        cork_buffer_set(&path->given, \"\", 0);\n    } else {\n        cork_buffer_set(&path->given, str, length);\n    }\n    return path;\n}\n\nstruct cork_path *\ncork_path_new(const char *source)\n{\n    return cork_path_new_internal(source, source == NULL? 0: strlen(source));\n}\n\nstruct cork_path *\ncork_path_clone(const struct cork_path *other)\n{\n    return cork_path_new_internal(other->given.buf, other->given.size);\n}\n\nvoid\ncork_path_free(struct cork_path *path)\n{\n    cork_buffer_done(&path->given);\n    cork_delete(struct cork_path, path);\n}\n\n\nvoid\ncork_path_set(struct cork_path *path, const char *content)\n{\n    if (content == NULL) {\n        cork_buffer_clear(&path->given);\n    } else {\n        cork_buffer_set_string(&path->given, content);\n    }\n}\n\nconst char *\ncork_path_get(const struct cork_path *path)\n{\n    return path->given.buf;\n}\n\n#define cork_path_get(path) ((const char *) (path)->given.buf)\n#define cork_path_size(path)  ((path)->given.size)\n#define cork_path_truncate(path, size) \\\n    (cork_buffer_truncate(&(path)->given, (size)))\n\n\nint\ncork_path_set_cwd(struct cork_path *path)\n{\n#ifdef __GNU__\n    char *dirname = get_current_dir_name();\n    rip_check_posix(dirname);\n    cork_buffer_set(&path->given, dirname, strlen(dirname));\n    free(dirname);\n#else\n    cork_buffer_ensure_size(&path->given, PATH_MAX);\n    rip_check_posix(getcwd(path->given.buf, PATH_MAX));\n    path->given.size = strlen(path->given.buf);\n#endif\n    return 0;\n}\n\nstruct cork_path *\ncork_path_cwd(void)\n{\n    struct cork_path  *path = cork_path_new(NULL);\n    ei_check(cork_path_set_cwd(path));\n    return path;\n\nerror:\n    cork_path_free(path);\n    return NULL;\n}\n\n\nint\ncork_path_set_absolute(struct cork_path *path)\n{\n    struct cork_buffer  buf;\n\n    if (path->given.size > 0 &&\n        cork_buffer_char(&path->given, 0) == '/') {\n        /* The path is already absolute. */\n        return 0;\n    }\n\n#ifdef __GNU__\n    char *dirname;\n    dirname = get_current_dir_name();\n    ep_check_posix(dirname);\n    cork_buffer_init(&buf);\n    cork_buffer_set(&buf, dirname, strlen(dirname));\n    free(dirname);\n#else\n    cork_buffer_init(&buf);\n    cork_buffer_ensure_size(&buf, PATH_MAX);\n    ep_check_posix(getcwd(buf.buf, PATH_MAX));\n    buf.size = strlen(buf.buf);\n#endif\n    cork_buffer_append(&buf, \"/\", 1);\n    cork_buffer_append_copy(&buf, &path->given);\n    cork_buffer_done(&path->given);\n    path->given = buf;\n    return 0;\n\nerror:\n    cork_buffer_done(&buf);\n    return -1;\n}\n\nstruct cork_path *\ncork_path_absolute(const struct cork_path *other)\n{\n    struct cork_path  *path = cork_path_clone(other);\n    ei_check(cork_path_set_absolute(path));\n    return path;\n\nerror:\n    cork_path_free(path);\n    return NULL;\n}\n\n\nvoid\ncork_path_append(struct cork_path *path, const char *more)\n{\n    if (more == NULL || more[0] == '\\0') {\n        return;\n    }\n\n    if (more[0] == '/') {\n        /* If more starts with a \"/\", then it's absolute, and should replace\n         * the contents of the current path. */\n        cork_buffer_set_string(&path->given, more);\n    } else {\n        /* Otherwise, more is relative, and should be appended to the current\n         * path.  If the current given path doesn't end in a \"/\", then we need\n         * to add one to keep the path well-formed. */\n\n        if (path->given.size > 0 &&\n            cork_buffer_char(&path->given, path->given.size - 1) != '/') {\n            cork_buffer_append(&path->given, \"/\", 1);\n        }\n\n        cork_buffer_append_string(&path->given, more);\n    }\n}\n\nstruct cork_path *\ncork_path_join(const struct cork_path *other, const char *more)\n{\n    struct cork_path  *path = cork_path_clone(other);\n    cork_path_append(path, more);\n    return path;\n}\n\nvoid\ncork_path_append_path(struct cork_path *path, const struct cork_path *more)\n{\n    cork_path_append(path, more->given.buf);\n}\n\nstruct cork_path *\ncork_path_join_path(const struct cork_path *other, const struct cork_path *more)\n{\n    struct cork_path  *path = cork_path_clone(other);\n    cork_path_append_path(path, more);\n    return path;\n}\n\n\nvoid\ncork_path_set_basename(struct cork_path *path)\n{\n    char  *given = path->given.buf;\n    const char  *last_slash = strrchr(given, '/');\n    if (last_slash != NULL) {\n        size_t  offset = last_slash - given;\n        size_t  basename_length = path->given.size - offset - 1;\n        memmove(given, last_slash + 1, basename_length);\n        given[basename_length] = '\\0';\n        path->given.size = basename_length;\n    }\n}\n\nstruct cork_path *\ncork_path_basename(const struct cork_path *other)\n{\n    struct cork_path  *path = cork_path_clone(other);\n    cork_path_set_basename(path);\n    return path;\n}\n\n\nvoid\ncork_path_set_dirname(struct cork_path *path)\n{\n    const char  *given = path->given.buf;\n    const char  *last_slash = strrchr(given, '/');\n    if (last_slash == NULL) {\n        cork_buffer_clear(&path->given);\n    } else {\n        size_t  offset = last_slash - given;\n        if (offset == 0) {\n            /* A special case for the immediate subdirectories of \"/\" */\n            cork_buffer_truncate(&path->given, 1);\n        } else {\n            cork_buffer_truncate(&path->given, offset);\n        }\n    }\n}\n\nstruct cork_path *\ncork_path_dirname(const struct cork_path *other)\n{\n    struct cork_path  *path = cork_path_clone(other);\n    cork_path_set_dirname(path);\n    return path;\n}\n\n\n/*-----------------------------------------------------------------------\n * Lists of paths\n */\n\nstruct cork_path_list {\n    cork_array(struct cork_path *)  array;\n    struct cork_buffer  string;\n};\n\nstruct cork_path_list *\ncork_path_list_new_empty(void)\n{\n    struct cork_path_list  *list = cork_new(struct cork_path_list);\n    cork_array_init(&list->array);\n    cork_buffer_init(&list->string);\n    return list;\n}\n\nvoid\ncork_path_list_free(struct cork_path_list *list)\n{\n    size_t  i;\n    for (i = 0; i < cork_array_size(&list->array); i++) {\n        struct cork_path  *path = cork_array_at(&list->array, i);\n        cork_path_free(path);\n    }\n    cork_array_done(&list->array);\n    cork_buffer_done(&list->string);\n    cork_delete(struct cork_path_list, list);\n}\n\nconst char *\ncork_path_list_to_string(const struct cork_path_list *list)\n{\n    return list->string.buf;\n}\n\nvoid\ncork_path_list_add(struct cork_path_list *list, struct cork_path *path)\n{\n    cork_array_append(&list->array, path);\n    if (cork_array_size(&list->array) > 1) {\n        cork_buffer_append(&list->string, \":\", 1);\n    }\n    cork_buffer_append_string(&list->string, cork_path_get(path));\n}\n\nsize_t\ncork_path_list_size(const struct cork_path_list *list)\n{\n    return cork_array_size(&list->array);\n}\n\nconst struct cork_path *\ncork_path_list_get(const struct cork_path_list *list, size_t index)\n{\n    return cork_array_at(&list->array, index);\n}\n\nstatic void\ncork_path_list_append_string(struct cork_path_list *list, const char *str)\n{\n    struct cork_path  *path;\n    const char  *curr = str;\n    const char  *next;\n\n    while ((next = strchr(curr, ':')) != NULL) {\n        size_t  size = next - curr;\n        path = cork_path_new_internal(curr, size);\n        cork_path_list_add(list, path);\n        curr = next + 1;\n    }\n\n    path = cork_path_new(curr);\n    cork_path_list_add(list, path);\n}\n\nstruct cork_path_list *\ncork_path_list_new(const char *str)\n{\n    struct cork_path_list  *list = cork_path_list_new_empty();\n    cork_path_list_append_string(list, str);\n    return list;\n}\n\n\n/*-----------------------------------------------------------------------\n * Files\n */\n\nstruct cork_file {\n    struct cork_path  *path;\n    struct stat  stat;\n    enum cork_file_type  type;\n    bool  has_stat;\n};\n\nstatic void\ncork_file_init(struct cork_file *file, struct cork_path *path)\n{\n    file->path = path;\n    file->has_stat = false;\n}\n\nstruct cork_file *\ncork_file_new(const char *path)\n{\n    return cork_file_new_from_path(cork_path_new(path));\n}\n\nstruct cork_file *\ncork_file_new_from_path(struct cork_path *path)\n{\n    struct cork_file  *file = cork_new(struct cork_file);\n    cork_file_init(file, path);\n    return file;\n}\n\nstatic void\ncork_file_reset(struct cork_file *file)\n{\n    file->has_stat = false;\n}\n\nstatic void\ncork_file_done(struct cork_file *file)\n{\n    cork_path_free(file->path);\n}\n\nvoid\ncork_file_free(struct cork_file *file)\n{\n    cork_file_done(file);\n    cork_delete(struct cork_file, file);\n}\n\nconst struct cork_path *\ncork_file_path(struct cork_file *file)\n{\n    return file->path;\n}\n\nstatic int\ncork_file_stat(struct cork_file *file)\n{\n    if (file->has_stat) {\n        return 0;\n    } else {\n        int  rc;\n        rc = stat(cork_path_get(file->path), &file->stat);\n\n        if (rc == -1) {\n            if (errno == ENOENT || errno == ENOTDIR) {\n                file->type = CORK_FILE_MISSING;\n                file->has_stat = true;\n                return 0;\n            } else {\n                cork_system_error_set();\n                return -1;\n            }\n        }\n\n        if (S_ISREG(file->stat.st_mode)) {\n            file->type = CORK_FILE_REGULAR;\n        } else if (S_ISDIR(file->stat.st_mode)) {\n            file->type = CORK_FILE_DIRECTORY;\n        } else if (S_ISLNK(file->stat.st_mode)) {\n            file->type = CORK_FILE_SYMLINK;\n        } else {\n            file->type = CORK_FILE_UNKNOWN;\n        }\n\n        file->has_stat = true;\n        return 0;\n    }\n}\n\nint\ncork_file_exists(struct cork_file *file, bool *exists)\n{\n    rii_check(cork_file_stat(file));\n    *exists = (file->type != CORK_FILE_MISSING);\n    return 0;\n}\n\nint\ncork_file_type(struct cork_file *file, enum cork_file_type *type)\n{\n    rii_check(cork_file_stat(file));\n    *type = file->type;\n    return 0;\n}\n\n\nstruct cork_file *\ncork_path_list_find_file(const struct cork_path_list *list,\n                         const char *rel_path)\n{\n    size_t  i;\n    size_t  count = cork_path_list_size(list);\n    struct cork_file  *file;\n\n    for (i = 0; i < count; i++) {\n        const struct cork_path  *path = cork_path_list_get(list, i);\n        struct cork_path  *joined = cork_path_join(path, rel_path);\n        bool  exists;\n        file = cork_file_new_from_path(joined);\n        ei_check(cork_file_exists(file, &exists));\n        if (exists) {\n            return file;\n        } else {\n            cork_file_free(file);\n        }\n    }\n\n    cork_error_set_printf\n        (ENOENT, \"%s not found in %s\",\n         rel_path, cork_path_list_to_string(list));\n    return NULL;\n\nerror:\n    cork_file_free(file);\n    return NULL;\n}\n\n\n/*-----------------------------------------------------------------------\n * Directories\n */\n\nint\ncork_file_iterate_directory(struct cork_file *file,\n                            cork_file_directory_iterator iterator,\n                            void *user_data)\n{\n    DIR  *dir = NULL;\n    struct dirent  *entry;\n    size_t  dir_path_size;\n    struct cork_path  *child_path;\n    struct cork_file  child_file;\n\n    rip_check_posix(dir = opendir(cork_path_get(file->path)));\n    child_path = cork_path_clone(file->path);\n    cork_file_init(&child_file, child_path);\n    dir_path_size = cork_path_size(child_path);\n\n    errno = 0;\n    while ((entry = readdir(dir)) != NULL) {\n        /* Skip the \".\" and \"..\" entries */\n        if (strcmp(entry->d_name, \".\") == 0 ||\n            strcmp(entry->d_name, \"..\") == 0) {\n            continue;\n        }\n\n        cork_path_append(child_path, entry->d_name);\n        ei_check(cork_file_stat(&child_file));\n\n        /* If the entry is a subdirectory, recurse into it. */\n        ei_check(iterator(&child_file, entry->d_name, user_data));\n\n        /* Remove this entry name from the path buffer. */\n        cork_path_truncate(child_path, dir_path_size);\n        cork_file_reset(&child_file);\n\n        /* We have to reset errno to 0 because of the ambiguous way readdir uses\n         * a return value of NULL.  Other functions may return normally yet set\n         * errno to a non-zero value.  dlopen on Mac OS X is an ogreish example.\n         * Since an error readdir is indicated by returning NULL and setting\n         * errno to indicate the error, then we need to reset it to zero before\n         * each call.  We shall assume, perhaps to our great misery, that\n         * functions within this loop do proper error checking and act\n         * accordingly. */\n        errno = 0;\n    }\n\n    /* Check errno immediately after the while loop terminates */\n    if (CORK_UNLIKELY(errno != 0)) {\n        cork_system_error_set();\n        goto error;\n    }\n\n    cork_file_done(&child_file);\n    rii_check_posix(closedir(dir));\n    return 0;\n\nerror:\n    cork_file_done(&child_file);\n    rii_check_posix(closedir(dir));\n    return -1;\n}\n\nstatic int\ncork_file_mkdir_one(struct cork_file *file, cork_file_mode mode,\n                    unsigned int flags)\n{\n    DEBUG(\"mkdir %s\\n\", cork_path_get(file->path));\n\n    /* First check if the directory already exists. */\n    rii_check(cork_file_stat(file));\n    if (file->type == CORK_FILE_DIRECTORY) {\n        DEBUG(\"  Already exists!\\n\");\n        if (!(flags & CORK_FILE_PERMISSIVE)) {\n            cork_system_error_set_explicit(EEXIST);\n            return -1;\n        } else {\n            return 0;\n        }\n    } else if (file->type != CORK_FILE_MISSING) {\n        DEBUG(\"  Exists and not a directory!\\n\");\n        cork_system_error_set_explicit(EEXIST);\n        return -1;\n    }\n\n    /* If the caller asked for a recursive mkdir, then make sure the parent\n     * directory exists. */\n    if (flags & CORK_FILE_RECURSIVE) {\n        struct cork_path  *parent = cork_path_dirname(file->path);\n        DEBUG(\"  Checking parent %s\\n\", cork_path_get(parent));\n        if (parent->given.size == 0) {\n            /* There is no parent; we're either at the filesystem root (for an\n             * absolute path) or the current directory (for a relative one).\n             * Either way, we can assume it already exists. */\n            cork_path_free(parent);\n        } else {\n            int  rc;\n            struct cork_file  parent_file;\n            cork_file_init(&parent_file, parent);\n            rc = cork_file_mkdir_one\n                (&parent_file, mode, flags | CORK_FILE_PERMISSIVE);\n            cork_file_done(&parent_file);\n            rii_check(rc);\n        }\n    }\n\n    /* Create the directory already! */\n    DEBUG(\"  Creating %s\\n\", cork_path_get(file->path));\n    rii_check_posix(mkdir(cork_path_get(file->path), mode));\n    return 0;\n}\n\nint\ncork_file_mkdir(struct cork_file *file, cork_file_mode mode,\n                unsigned int flags)\n{\n    return cork_file_mkdir_one(file, mode, flags);\n}\n\nstatic int\ncork_file_remove_iterator(struct cork_file *file, const char *rel_name,\n                          void *user_data)\n{\n    unsigned int  *flags = user_data;\n    return cork_file_remove(file, *flags);\n}\n\nint\ncork_file_remove(struct cork_file *file, unsigned int flags)\n{\n    DEBUG(\"rm %s\\n\", cork_path_get(file->path));\n    rii_check(cork_file_stat(file));\n\n    if (file->type == CORK_FILE_MISSING) {\n        if (flags & CORK_FILE_PERMISSIVE) {\n            return 0;\n        } else {\n            cork_system_error_set_explicit(ENOENT);\n            return -1;\n        }\n    } else if (file->type == CORK_FILE_DIRECTORY) {\n        if (flags & CORK_FILE_RECURSIVE) {\n            /* The user asked that we delete the contents of the directory\n             * first. */\n            rii_check(cork_file_iterate_directory\n                      (file, cork_file_remove_iterator, &flags));\n        }\n\n        rii_check_posix(rmdir(cork_path_get(file->path)));\n        return 0;\n    } else {\n        rii_check(unlink(cork_path_get(file->path)));\n        return 0;\n    }\n}\n\n\n/*-----------------------------------------------------------------------\n * Lists of files\n */\n\nstruct cork_file_list {\n    cork_array(struct cork_file *)  array;\n};\n\nstruct cork_file_list *\ncork_file_list_new_empty(void)\n{\n    struct cork_file_list  *list = cork_new(struct cork_file_list);\n    cork_array_init(&list->array);\n    return list;\n}\n\nvoid\ncork_file_list_free(struct cork_file_list *list)\n{\n    size_t  i;\n    for (i = 0; i < cork_array_size(&list->array); i++) {\n        struct cork_file  *file = cork_array_at(&list->array, i);\n        cork_file_free(file);\n    }\n    cork_array_done(&list->array);\n    cork_delete(struct cork_file_list, list);\n}\n\nvoid\ncork_file_list_add(struct cork_file_list *list, struct cork_file *file)\n{\n    cork_array_append(&list->array, file);\n}\n\nsize_t\ncork_file_list_size(struct cork_file_list *list)\n{\n    return cork_array_size(&list->array);\n}\n\nstruct cork_file *\ncork_file_list_get(struct cork_file_list *list, size_t index)\n{\n    return cork_array_at(&list->array, index);\n}\n\nstruct cork_file_list *\ncork_file_list_new(struct cork_path_list *path_list)\n{\n    struct cork_file_list  *list = cork_file_list_new_empty();\n    size_t  count = cork_path_list_size(path_list);\n    size_t  i;\n\n    for (i = 0; i < count; i++) {\n        const struct cork_path  *path = cork_path_list_get(path_list, i);\n        struct cork_file  *file = cork_file_new(cork_path_get(path));\n        cork_array_append(&list->array, file);\n    }\n\n    return list;\n}\n\n\nstruct cork_file_list *\ncork_path_list_find_files(const struct cork_path_list *path_list,\n                          const char *rel_path)\n{\n    size_t  i;\n    size_t  count = cork_path_list_size(path_list);\n    struct cork_file_list  *list = cork_file_list_new_empty();\n    struct cork_file  *file;\n\n    for (i = 0; i < count; i++) {\n        const struct cork_path  *path = cork_path_list_get(path_list, i);\n        struct cork_path  *joined = cork_path_join(path, rel_path);\n        bool  exists;\n        file = cork_file_new_from_path(joined);\n        ei_check(cork_file_exists(file, &exists));\n        if (exists) {\n            cork_file_list_add(list, file);\n        } else {\n            cork_file_free(file);\n        }\n    }\n\n    return list;\n\nerror:\n    cork_file_list_free(list);\n    cork_file_free(file);\n    return NULL;\n}\n\n\n/*-----------------------------------------------------------------------\n * Standard paths and path lists\n */\n\n#define empty_string(str)  ((str) == NULL || (str)[0] == '\\0')\n\nstruct cork_path *\ncork_path_home(void)\n{\n    const char  *path = cork_env_get(NULL, \"HOME\");\n    if (empty_string(path)) {\n        cork_undefined(\"Cannot determine home directory\");\n        return NULL;\n    } else {\n        return cork_path_new(path);\n    }\n}\n\n\nstruct cork_path_list *\ncork_path_config_paths(void)\n{\n    struct cork_path_list  *list = cork_path_list_new_empty();\n    const char  *var;\n    struct cork_path  *path;\n\n    /* The first entry should be the user's configuration directory.  This is\n     * specified by $XDG_CONFIG_HOME, with $HOME/.config as the default. */\n    var = cork_env_get(NULL, \"XDG_CONFIG_HOME\");\n    if (empty_string(var)) {\n        ep_check(path = cork_path_home());\n        cork_path_append(path, \".config\");\n        cork_path_list_add(list, path);\n    } else {\n        path = cork_path_new(var);\n        cork_path_list_add(list, path);\n    }\n\n    /* The remaining entries should be the system-wide configuration\n     * directories.  These are specified by $XDG_CONFIG_DIRS, with /etc/xdg as\n     * the default. */\n    var = cork_env_get(NULL, \"XDG_CONFIG_DIRS\");\n    if (empty_string(var)) {\n        path = cork_path_new(\"/etc/xdg\");\n        cork_path_list_add(list, path);\n    } else {\n        cork_path_list_append_string(list, var);\n    }\n\n    return list;\n\nerror:\n    cork_path_list_free(list);\n    return NULL;\n}\n\nstruct cork_path_list *\ncork_path_data_paths(void)\n{\n    struct cork_path_list  *list = cork_path_list_new_empty();\n    const char  *var;\n    struct cork_path  *path;\n\n    /* The first entry should be the user's data directory.  This is specified\n     * by $XDG_DATA_HOME, with $HOME/.local/share as the default. */\n    var = cork_env_get(NULL, \"XDG_DATA_HOME\");\n    if (empty_string(var)) {\n        ep_check(path = cork_path_home());\n        cork_path_append(path, \".local/share\");\n        cork_path_list_add(list, path);\n    } else {\n        path = cork_path_new(var);\n        cork_path_list_add(list, path);\n    }\n\n    /* The remaining entries should be the system-wide configuration\n     * directories.  These are specified by $XDG_DATA_DIRS, with\n     * /usr/local/share:/usr/share as the the default. */\n    var = cork_env_get(NULL, \"XDG_DATA_DIRS\");\n    if (empty_string(var)) {\n        path = cork_path_new(\"/usr/local/share\");\n        cork_path_list_add(list, path);\n        path = cork_path_new(\"/usr/share\");\n        cork_path_list_add(list, path);\n    } else {\n        cork_path_list_append_string(list, var);\n    }\n\n    return list;\n\nerror:\n    cork_path_list_free(list);\n    return NULL;\n}\n\nstruct cork_path *\ncork_path_user_cache_path(void)\n{\n    const char  *var;\n    struct cork_path  *path;\n\n    /* The user's cache directory is specified by $XDG_CACHE_HOME, with\n     * $HOME/.cache as the default. */\n    var = cork_env_get(NULL, \"XDG_CACHE_HOME\");\n    if (empty_string(var)) {\n        rpp_check(path = cork_path_home());\n        cork_path_append(path, \".cache\");\n        return path;\n    } else {\n        return cork_path_new(var);\n    }\n}\n\nstruct cork_path *\ncork_path_user_runtime_path(void)\n{\n    const char  *var;\n\n    /* The user's cache directory is specified by $XDG_RUNTIME_DIR, with\n     * no default given by the spec. */\n    var = cork_env_get(NULL, \"XDG_RUNTIME_DIR\");\n    if (empty_string(var)) {\n        cork_undefined(\"Cannot determine user-specific runtime directory\");\n        return NULL;\n    } else {\n        return cork_path_new(var);\n    }\n}\n"
  },
  {
    "path": "src/libcork/posix/process.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os/process.h\"\n#include \"libcork/helpers/errors.h\"\n\n\n#if !defined(CORK_DEBUG_PROCESS)\n#define CORK_DEBUG_PROCESS  0\n#endif\n\n#if CORK_DEBUG_PROCESS\n#include <stdio.h>\n#define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define DEBUG(...) /* no debug messages */\n#endif\n\n\nstruct cork_cleanup_entry {\n    struct cork_dllist_item  item;\n    int  priority;\n    const char  *name;\n    cork_cleanup_function  function;\n};\n\nstatic struct cork_cleanup_entry *\ncork_cleanup_entry_new(const char *name, int priority,\n                       cork_cleanup_function function)\n{\n    struct cork_cleanup_entry  *self = cork_new(struct cork_cleanup_entry);\n    self->priority = priority;\n    self->name = cork_strdup(name);\n    self->function = function;\n    return self;\n}\n\nstatic void\ncork_cleanup_entry_free(struct cork_cleanup_entry *self)\n{\n    cork_strfree(self->name);\n    cork_delete(struct cork_cleanup_entry, self);\n}\n\nstatic struct cork_dllist  cleanup_entries = CORK_DLLIST_INIT(cleanup_entries);\nstatic bool  cleanup_registered = false;\n\nstatic void\ncork_cleanup_call_one(struct cork_dllist_item *item, void *user_data)\n{\n    struct cork_cleanup_entry  *entry =\n        cork_container_of(item, struct cork_cleanup_entry, item);\n    cork_cleanup_function  function = entry->function;\n    DEBUG(\"Call cleanup function [%d] %s\\n\", entry->priority, entry->name);\n    /* We need to free the entry before calling the entry's function, since one\n     * of the functions that libcork registers frees the allocator instance that\n     * we'd use to free the entry.  If we called the function first, the\n     * allocator would be freed before we could use it to free the entry. */\n    cork_cleanup_entry_free(entry);\n    function();\n}\n\nstatic void\ncork_cleanup_call_all(void)\n{\n    cork_dllist_map(&cleanup_entries, cork_cleanup_call_one, NULL);\n}\n\nstatic void\ncork_cleanup_entry_add(struct cork_cleanup_entry *entry)\n{\n    struct cork_dllist_item  *curr;\n\n    if (CORK_UNLIKELY(!cleanup_registered)) {\n        atexit(cork_cleanup_call_all);\n        cleanup_registered = true;\n    }\n\n    /* Linear search through the list of existing cleanup functions.  When we\n     * find the first existing function with a higher priority, we've found\n     * where to insert the new function. */\n    for (curr = cork_dllist_start(&cleanup_entries);\n         !cork_dllist_is_end(&cleanup_entries, curr); curr = curr->next) {\n        struct cork_cleanup_entry  *existing =\n            cork_container_of(curr, struct cork_cleanup_entry, item);\n        if (existing->priority > entry->priority) {\n            cork_dllist_add_before(&existing->item, &entry->item);\n            return;\n        }\n    }\n\n    /* If we fall through the loop, then the new function should be appended to\n     * the end of the list. */\n    cork_dllist_add(&cleanup_entries, &entry->item);\n}\n\n\nCORK_API void\ncork_cleanup_at_exit_named(const char *name, int priority,\n                           cork_cleanup_function function)\n{\n    struct cork_cleanup_entry  *entry =\n        cork_cleanup_entry_new(name, priority, function);\n    DEBUG(\"Register cleanup function [%d] %s\\n\", priority, name);\n    cork_cleanup_entry_add(entry);\n}\n"
  },
  {
    "path": "src/libcork/posix/subprocess.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <signal.h>\n#include <sys/select.h>\n#include <sys/wait.h>\n#include <unistd.h>\n\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os/subprocess.h\"\n#include \"libcork/threads/basics.h\"\n#include \"libcork/helpers/errors.h\"\n#include \"libcork/helpers/posix.h\"\n\n\n#if !defined(CORK_DEBUG_SUBPROCESS)\n#define CORK_DEBUG_SUBPROCESS  0\n#endif\n\n#if CORK_DEBUG_SUBPROCESS\n#include <stdio.h>\n#define DEBUG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define DEBUG(...) /* no debug messages */\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Subprocess groups\n */\n\n#define BUF_SIZE  4096\n\nstruct cork_subprocess_group {\n    cork_array(struct cork_subprocess *)  subprocesses;\n};\n\nstruct cork_subprocess_group *\ncork_subprocess_group_new(void)\n{\n    struct cork_subprocess_group  *group =\n        cork_new(struct cork_subprocess_group);\n    cork_pointer_array_init\n        (&group->subprocesses, (cork_free_f) cork_subprocess_free);\n    return group;\n}\n\nvoid\ncork_subprocess_group_free(struct cork_subprocess_group *group)\n{\n    cork_array_done(&group->subprocesses);\n    cork_delete(struct cork_subprocess_group, group);\n}\n\nvoid\ncork_subprocess_group_add(struct cork_subprocess_group *group,\n                          struct cork_subprocess *sub)\n{\n    cork_array_append(&group->subprocesses, sub);\n}\n\n\n/*-----------------------------------------------------------------------\n * Pipes (parent reads)\n */\n\nstruct cork_read_pipe {\n    struct cork_stream_consumer  *consumer;\n    int  fds[2];\n    bool  first;\n};\n\nstatic void\ncork_read_pipe_init(struct cork_read_pipe *p, struct cork_stream_consumer *consumer)\n{\n    p->consumer = consumer;\n    p->fds[0] = -1;\n    p->fds[1] = -1;\n}\n\nstatic int\ncork_read_pipe_close_read(struct cork_read_pipe *p)\n{\n    if (p->fds[0] != -1) {\n        DEBUG(\"Closing read pipe %d\\n\", p->fds[0]);\n        rii_check_posix(close(p->fds[0]));\n        p->fds[0] = -1;\n    }\n    return 0;\n}\n\nstatic int\ncork_read_pipe_close_write(struct cork_read_pipe *p)\n{\n    if (p->fds[1] != -1) {\n        DEBUG(\"Closing write pipe %d\\n\", p->fds[1]);\n        rii_check_posix(close(p->fds[1]));\n        p->fds[1] = -1;\n    }\n    return 0;\n}\n\nstatic void\ncork_read_pipe_close(struct cork_read_pipe *p)\n{\n    cork_read_pipe_close_read(p);\n    cork_read_pipe_close_write(p);\n}\n\nstatic void\ncork_read_pipe_done(struct cork_read_pipe *p)\n{\n    cork_read_pipe_close(p);\n}\n\nstatic int\ncork_read_pipe_open(struct cork_read_pipe *p)\n{\n    if (p->consumer != NULL) {\n        int  flags;\n\n        /* We want the read end of the pipe to be non-blocking. */\n        DEBUG(\"[read] Opening pipe\\n\");\n        rii_check_posix(pipe(p->fds));\n        DEBUG(\"[read]   Got read=%d write=%d\\n\", p->fds[0], p->fds[1]);\n        DEBUG(\"[read]   Setting non-blocking flag on read pipe\\n\");\n        ei_check_posix(flags = fcntl(p->fds[0], F_GETFD));\n        flags |= O_NONBLOCK;\n        ei_check_posix(fcntl(p->fds[0], F_SETFD, flags));\n    }\n\n    p->first = true;\n    return 0;\n\nerror:\n    cork_read_pipe_close(p);\n    return -1;\n}\n\nstatic int\ncork_read_pipe_dup(struct cork_read_pipe *p, int fd)\n{\n    if (p->fds[1] != -1) {\n        rii_check_posix(dup2(p->fds[1], fd));\n    }\n    return 0;\n}\n\nstatic int\ncork_read_pipe_read(struct cork_read_pipe *p, char *buf, bool *progress)\n{\n    if (p->fds[0] == -1) {\n        return 0;\n    }\n\n    do {\n        DEBUG(\"[read] Reading from pipe %d\\n\", p->fds[0]);\n        ssize_t  bytes_read = read(p->fds[0], buf, BUF_SIZE);\n        if (bytes_read == -1) {\n            if (errno == EAGAIN) {\n                /* We've exhausted all of the data currently available. */\n                DEBUG(\"[read]   No more bytes without blocking\\n\");\n                return 0;\n            } else if (errno == EINTR) {\n                /* Interrupted by a signal; return so that our wait loop can\n                 * catch that. */\n                DEBUG(\"[read]   Interrupted by signal\\n\");\n                return 0;\n            } else {\n                /* An actual error */\n                cork_system_error_set();\n                DEBUG(\"[read]   Error: %s\\n\", cork_error_message());\n                return -1;\n            }\n        } else if (bytes_read == 0) {\n            DEBUG(\"[read]   End of stream\\n\");\n            *progress = true;\n            rii_check(cork_stream_consumer_eof(p->consumer));\n            rii_check_posix(close(p->fds[0]));\n            p->fds[0] = -1;\n            return 0;\n        } else {\n            DEBUG(\"[read]   Got %zd bytes\\n\", bytes_read);\n            *progress = true;\n            rii_check(cork_stream_consumer_data\n                      (p->consumer, buf, bytes_read, p->first));\n            p->first = false;\n        }\n    } while (true);\n}\n\nstatic bool\ncork_read_pipe_is_finished(struct cork_read_pipe *p)\n{\n    return p->fds[0] == -1;\n}\n\n\n/*-----------------------------------------------------------------------\n * Pipes (parent writes)\n */\n\nstruct cork_write_pipe {\n    struct cork_stream_consumer  consumer;\n    int  fds[2];\n};\n\nstatic int\ncork_write_pipe_close_read(struct cork_write_pipe *p)\n{\n    if (p->fds[0] != -1) {\n        DEBUG(\"[write] Closing read pipe %d\\n\", p->fds[0]);\n        rii_check_posix(close(p->fds[0]));\n        p->fds[0] = -1;\n    }\n    return 0;\n}\n\nstatic int\ncork_write_pipe_close_write(struct cork_write_pipe *p)\n{\n    if (p->fds[1] != -1) {\n        DEBUG(\"[write] Closing write pipe %d\\n\", p->fds[1]);\n        rii_check_posix(close(p->fds[1]));\n        p->fds[1] = -1;\n    }\n    return 0;\n}\n\nstatic int\ncork_write_pipe__data(struct cork_stream_consumer *consumer,\n                      const void *buf, size_t size, bool is_first_chunk)\n{\n    struct cork_write_pipe  *p =\n        cork_container_of(consumer, struct cork_write_pipe, consumer);\n    rii_check_posix(write(p->fds[1], buf, size));\n    return 0;\n}\n\nstatic int\ncork_write_pipe__eof(struct cork_stream_consumer *consumer)\n{\n    struct cork_write_pipe  *p =\n        cork_container_of(consumer, struct cork_write_pipe, consumer);\n    return cork_write_pipe_close_write(p);\n}\n\nstatic void\ncork_write_pipe__free(struct cork_stream_consumer *consumer)\n{\n}\n\nstatic void\ncork_write_pipe_init(struct cork_write_pipe *p)\n{\n    p->consumer.data = cork_write_pipe__data;\n    p->consumer.eof = cork_write_pipe__eof;\n    p->consumer.free = cork_write_pipe__free;\n    p->fds[0] = -1;\n    p->fds[1] = -1;\n}\n\nstatic void\ncork_write_pipe_close(struct cork_write_pipe *p)\n{\n    cork_write_pipe_close_read(p);\n    cork_write_pipe_close_write(p);\n}\n\nstatic void\ncork_write_pipe_done(struct cork_write_pipe *p)\n{\n    cork_write_pipe_close(p);\n}\n\nstatic int\ncork_write_pipe_open(struct cork_write_pipe *p)\n{\n    DEBUG(\"[write] Opening writer pipe\\n\");\n    rii_check_posix(pipe(p->fds));\n    DEBUG(\"[write]   Got read=%d write=%d\\n\", p->fds[0], p->fds[1]);\n    return 0;\n}\n\nstatic int\ncork_write_pipe_dup(struct cork_write_pipe *p, int fd)\n{\n    if (p->fds[0] != -1) {\n        rii_check_posix(dup2(p->fds[0], fd));\n    }\n    return 0;\n}\n\n\n/*-----------------------------------------------------------------------\n * Subprocesses\n */\n\nstruct cork_subprocess {\n    pid_t  pid;\n    struct cork_write_pipe  stdin_pipe;\n    struct cork_read_pipe  stdout_pipe;\n    struct cork_read_pipe  stderr_pipe;\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_run_f  run;\n    int  *exit_code;\n    char  buf[BUF_SIZE];\n};\n\nstruct cork_subprocess *\ncork_subprocess_new(void *user_data, cork_free_f free_user_data,\n                    cork_run_f run,\n                    struct cork_stream_consumer *stdout_consumer,\n                    struct cork_stream_consumer *stderr_consumer,\n                    int *exit_code)\n{\n    struct cork_subprocess  *self = cork_new(struct cork_subprocess);\n    cork_write_pipe_init(&self->stdin_pipe);\n    cork_read_pipe_init(&self->stdout_pipe, stdout_consumer);\n    cork_read_pipe_init(&self->stderr_pipe, stderr_consumer);\n    self->pid = 0;\n    self->user_data = user_data;\n    self->free_user_data = free_user_data;\n    self->run = run;\n    self->exit_code = exit_code;\n    return self;\n}\n\nvoid\ncork_subprocess_free(struct cork_subprocess *self)\n{\n    cork_free_user_data(self);\n    cork_write_pipe_done(&self->stdin_pipe);\n    cork_read_pipe_done(&self->stdout_pipe);\n    cork_read_pipe_done(&self->stderr_pipe);\n    cork_delete(struct cork_subprocess, self);\n}\n\nstruct cork_stream_consumer *\ncork_subprocess_stdin(struct cork_subprocess *self)\n{\n    return &self->stdin_pipe.consumer;\n}\n\n\n/*-----------------------------------------------------------------------\n * Executing another program\n */\n\nstatic int\ncork_exec__run(void *vself)\n{\n    struct cork_exec  *exec = vself;\n    return cork_exec_run(exec);\n}\n\nstatic void\ncork_exec__free(void *vself)\n{\n    struct cork_exec  *exec = vself;\n    cork_exec_free(exec);\n}\n\nstruct cork_subprocess *\ncork_subprocess_new_exec(struct cork_exec *exec,\n                         struct cork_stream_consumer *out,\n                         struct cork_stream_consumer *err,\n                         int *exit_code)\n{\n    return cork_subprocess_new\n        (exec, cork_exec__free,\n         cork_exec__run,\n         out, err, exit_code);\n}\n\n\n/*-----------------------------------------------------------------------\n * Running subprocesses\n */\n\nint\ncork_subprocess_start(struct cork_subprocess *self)\n{\n    pid_t  pid;\n\n    /* Create the stdout and stderr pipes. */\n    if (cork_write_pipe_open(&self->stdin_pipe) == -1) {\n        return -1;\n    }\n    if (cork_read_pipe_open(&self->stdout_pipe) == -1) {\n        cork_write_pipe_close(&self->stdin_pipe);\n        return -1;\n    }\n    if (cork_read_pipe_open(&self->stderr_pipe) == -1) {\n        cork_write_pipe_close(&self->stdin_pipe);\n        cork_read_pipe_close(&self->stdout_pipe);\n        return -1;\n    }\n\n    /* Fork the child process. */\n    DEBUG(\"Forking child process\\n\");\n    pid = fork();\n    if (pid == 0) {\n        /* Child process */\n        int  rc;\n\n        /* Close the parent's end of the pipes */\n        DEBUG(\"[child] \");\n        cork_write_pipe_close_write(&self->stdin_pipe);\n        DEBUG(\"[child] \");\n        cork_read_pipe_close_read(&self->stdout_pipe);\n        DEBUG(\"[child] \");\n        cork_read_pipe_close_read(&self->stderr_pipe);\n\n        /* Bind the stdout and stderr pipes */\n        if (cork_write_pipe_dup(&self->stdin_pipe, STDIN_FILENO) == -1) {\n            _exit(EXIT_FAILURE);\n        }\n        if (cork_read_pipe_dup(&self->stdout_pipe, STDOUT_FILENO) == -1) {\n            _exit(EXIT_FAILURE);\n        }\n        if (cork_read_pipe_dup(&self->stderr_pipe, STDERR_FILENO) == -1) {\n            _exit(EXIT_FAILURE);\n        }\n\n        /* Run the subprocess */\n        rc = self->run(self->user_data);\n        if (CORK_LIKELY(rc == 0)) {\n            _exit(EXIT_SUCCESS);\n        } else {\n            fprintf(stderr, \"%s\\n\", cork_error_message());\n            _exit(EXIT_FAILURE);\n        }\n    } else if (pid < 0) {\n        /* Error forking */\n        cork_system_error_set();\n        return -1;\n    } else {\n        /* Parent process */\n        DEBUG(\"  Child PID=%d\\n\", (int) pid);\n        self->pid = pid;\n        cork_write_pipe_close_read(&self->stdin_pipe);\n        cork_read_pipe_close_write(&self->stdout_pipe);\n        cork_read_pipe_close_write(&self->stderr_pipe);\n        return 0;\n    }\n}\n\nstatic int\ncork_subprocess_reap(struct cork_subprocess *self, int flags, bool *progress)\n{\n    int  pid;\n    int  status;\n    rii_check_posix(pid = waitpid(self->pid, &status, flags));\n    if (pid == self->pid) {\n        *progress = true;\n        self->pid = 0;\n        if (self->exit_code != NULL) {\n            *self->exit_code = WEXITSTATUS(status);\n        }\n    }\n    return 0;\n}\n\nint\ncork_subprocess_abort(struct cork_subprocess *self)\n{\n    if (self->pid > 0) {\n        CORK_ATTR_UNUSED bool  progress;\n        DEBUG(\"Terminating child process %d\\n\", (int) self->pid);\n        kill(self->pid, SIGTERM);\n        return cork_subprocess_reap(self, 0, &progress);\n    } else {\n        return 0;\n    }\n}\n\nbool\ncork_subprocess_is_finished(struct cork_subprocess *self)\n{\n    return (self->pid == 0)\n        && cork_read_pipe_is_finished(&self->stdout_pipe)\n        && cork_read_pipe_is_finished(&self->stderr_pipe);\n}\n\n#if defined(__APPLE__)\n#include <pthread.h>\n#define THREAD_YIELD   pthread_yield_np\n#elif defined(__linux__) || defined(BSD) || defined(__FreeBSD_kernel__) || defined(__GNU__)\n#include <sched.h>\n#define THREAD_YIELD   sched_yield\n#else\n#error \"Unknown thread yield implementation\"\n#endif\n\nstatic void\ncork_subprocess_yield(unsigned int *spin_count)\n{\n    /* Adapted from\n     * http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning */\n\n    if (*spin_count < 10) {\n        /* Spin-wait */\n        cork_pause();\n    } else if (*spin_count < 20) {\n        /* A more intense spin-wait */\n        int  i;\n        for (i = 0; i < 50; i++) {\n            cork_pause();\n        }\n    } else if (*spin_count < 22) {\n        THREAD_YIELD();\n    } else if (*spin_count < 24) {\n        usleep(0);\n    } else if (*spin_count < 50) {\n        usleep(1);\n    } else if (*spin_count < 75) {\n        usleep((*spin_count - 49) * 1000);\n    } else {\n        usleep(25000);\n    }\n\n    (*spin_count)++;\n}\n\nstatic int\ncork_subprocess_drain_(struct cork_subprocess *self, bool *progress)\n{\n    rii_check(cork_read_pipe_read(&self->stdout_pipe, self->buf, progress));\n    rii_check(cork_read_pipe_read(&self->stderr_pipe, self->buf, progress));\n    if (self->pid > 0) {\n        return cork_subprocess_reap(self, WNOHANG, progress);\n    } else {\n        return 0;\n    }\n}\n\nbool\ncork_subprocess_drain(struct cork_subprocess *self)\n{\n    bool  progress;\n    cork_subprocess_drain_(self, &progress);\n    return progress;\n}\n\nint\ncork_subprocess_wait(struct cork_subprocess *self)\n{\n    unsigned int  spin_count = 0;\n    bool  progress;\n    while (!cork_subprocess_is_finished(self)) {\n        progress = false;\n        rii_check(cork_subprocess_drain_(self, &progress));\n        if (!progress) {\n            cork_subprocess_yield(&spin_count);\n        }\n    }\n    return 0;\n}\n\n\n/*-----------------------------------------------------------------------\n * Running subprocess groups\n */\n\nstatic int\ncork_subprocess_group_terminate(struct cork_subprocess_group *group)\n{\n    size_t  i;\n    for (i = 0; i < cork_array_size(&group->subprocesses); i++) {\n        struct cork_subprocess  *sub = cork_array_at(&group->subprocesses, i);\n        rii_check(cork_subprocess_abort(sub));\n    }\n    return 0;\n}\n\nint\ncork_subprocess_group_start(struct cork_subprocess_group *group)\n{\n    size_t  i;\n    DEBUG(\"Starting subprocess group\\n\");\n    /* Start each subprocess. */\n    for (i = 0; i < cork_array_size(&group->subprocesses); i++) {\n        struct cork_subprocess  *sub = cork_array_at(&group->subprocesses, i);\n        ei_check(cork_subprocess_start(sub));\n    }\n    return 0;\n\nerror:\n    cork_subprocess_group_terminate(group);\n    return -1;\n}\n\n\nint\ncork_subprocess_group_abort(struct cork_subprocess_group *group)\n{\n    DEBUG(\"Aborting subprocess group\\n\");\n    return cork_subprocess_group_terminate(group);\n}\n\n\nbool\ncork_subprocess_group_is_finished(struct cork_subprocess_group *group)\n{\n    size_t  i;\n    for (i = 0; i < cork_array_size(&group->subprocesses); i++) {\n        struct cork_subprocess  *sub = cork_array_at(&group->subprocesses, i);\n        bool  sub_finished = cork_subprocess_is_finished(sub);\n        if (!sub_finished) {\n            return false;\n        }\n    }\n    return true;\n}\n\nstatic int\ncork_subprocess_group_drain_(struct cork_subprocess_group *group,\n                             bool *progress)\n{\n    size_t  i;\n    for (i = 0; i < cork_array_size(&group->subprocesses); i++) {\n        struct cork_subprocess  *sub = cork_array_at(&group->subprocesses, i);\n        rii_check(cork_subprocess_drain_(sub, progress));\n    }\n    return 0;\n}\n\nbool\ncork_subprocess_group_drain(struct cork_subprocess_group *group)\n{\n    bool  progress = false;\n    cork_subprocess_group_drain_(group, &progress);\n    return progress;\n}\n\nint\ncork_subprocess_group_wait(struct cork_subprocess_group *group)\n{\n    unsigned int  spin_count = 0;\n    bool  progress;\n    DEBUG(\"Waiting for subprocess group to finish\\n\");\n    while (!cork_subprocess_group_is_finished(group)) {\n        progress = false;\n        rii_check(cork_subprocess_group_drain_(group, &progress));\n        if (!progress) {\n            cork_subprocess_yield(&spin_count);\n        }\n    }\n    return 0;\n}\n"
  },
  {
    "path": "src/libcork/pthreads/thread.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#if defined(__linux)\n/* This is needed on Linux to get the pthread_setname_np function. */\n#if !defined(_GNU_SOURCE)\n#define _GNU_SOURCE 1\n#endif\n#endif\n\n#include <assert.h>\n#include <string.h>\n\n#include <pthread.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/threads/basics.h\"\n\n\n/*-----------------------------------------------------------------------\n * Current thread\n */\n\nstatic volatile cork_thread_id  last_thread_descriptor = 0;\n\nstruct cork_thread {\n    const char  *name;\n    cork_thread_id  id;\n    pthread_t  thread_id;\n    void  *user_data;\n    cork_free_f  free_user_data;\n    cork_run_f  run;\n    cork_error  error_code;\n    struct cork_buffer  error_message;\n    bool  started;\n    bool  joined;\n};\n\nstruct cork_thread_descriptor {\n    struct cork_thread  *current_thread;\n    cork_thread_id  id;\n};\n\ncork_tls(struct cork_thread_descriptor, cork_thread_descriptor);\n\nstruct cork_thread *\ncork_current_thread_get(void)\n{\n    struct cork_thread_descriptor  *desc = cork_thread_descriptor_get();\n    return desc->current_thread;\n}\n\ncork_thread_id\ncork_current_thread_get_id(void)\n{\n    struct cork_thread_descriptor  *desc = cork_thread_descriptor_get();\n    if (CORK_UNLIKELY(desc->id == 0)) {\n        if (desc->current_thread == NULL) {\n            desc->id = cork_uint_atomic_add(&last_thread_descriptor, 1);\n        } else {\n            desc->id = desc->current_thread->id;\n        }\n    }\n    return desc->id;\n}\n\n\n/*-----------------------------------------------------------------------\n * Threads\n */\n\nstruct cork_thread *\ncork_thread_new(const char *name,\n                void *user_data, cork_free_f free_user_data,\n                cork_run_f run)\n{\n    struct cork_thread  *self = cork_new(struct cork_thread);\n    self->name = cork_strdup(name);\n    self->id = cork_uint_atomic_add(&last_thread_descriptor, 1);\n    self->user_data = user_data;\n    self->free_user_data = free_user_data;\n    self->run = run;\n    self->error_code = CORK_ERROR_NONE;\n    cork_buffer_init(&self->error_message);\n    self->started = false;\n    self->joined = false;\n    return self;\n}\n\nstatic void\ncork_thread_free_private(struct cork_thread *self)\n{\n    cork_strfree(self->name);\n    cork_free_user_data(self);\n    cork_buffer_done(&self->error_message);\n    cork_delete(struct cork_thread, self);\n}\n\nvoid\ncork_thread_free(struct cork_thread *self)\n{\n    assert(!self->started);\n    cork_thread_free_private(self);\n}\n\nconst char *\ncork_thread_get_name(struct cork_thread *self)\n{\n    return self->name;\n}\n\ncork_thread_id\ncork_thread_get_id(struct cork_thread *self)\n{\n    return self->id;\n}\n\n#define PTHREADS_MAX_THREAD_NAME_LENGTH  16\n\nstatic void *\ncork_thread_pthread_run(void *vself)\n{\n    int  rc;\n    struct cork_thread  *self = vself;\n    struct cork_thread_descriptor  *desc = cork_thread_descriptor_get();\n#if defined(__APPLE__) && defined(__MACH__)\n    char  thread_name[PTHREADS_MAX_THREAD_NAME_LENGTH];\n#endif\n\n    desc->current_thread = self;\n    desc->id = self->id;\n    rc = self->run(self->user_data);\n\n#if defined(__APPLE__) && defined(__MACH__)\n    /* On Mac OS X, we set the name of the current thread, not of an arbitrary\n     * thread of our choosing. */\n    strncpy(thread_name, self->name, PTHREADS_MAX_THREAD_NAME_LENGTH);\n    thread_name[PTHREADS_MAX_THREAD_NAME_LENGTH - 1] = '\\0';\n    pthread_setname_np(thread_name);\n#endif\n\n    /* If an error occurred in the body of the thread, save the error into the\n     * cork_thread object so that we can propagate that error when some calls\n     * cork_thread_join. */\n    if (CORK_UNLIKELY(rc != 0)) {\n        if (CORK_LIKELY(cork_error_occurred())) {\n            self->error_code = cork_error_code();\n            cork_buffer_set_string(&self->error_message, cork_error_message());\n        } else {\n            self->error_code = CORK_UNKNOWN_ERROR;\n            cork_buffer_set_string(&self->error_message, \"Unknown error\");\n        }\n    }\n\n    return NULL;\n}\n\nint\ncork_thread_start(struct cork_thread *self)\n{\n    int  rc;\n    pthread_t  thread_id;\n#if defined(__linux) && ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 12))\n    char  thread_name[PTHREADS_MAX_THREAD_NAME_LENGTH];\n#endif\n\n    assert(!self->started);\n\n    rc = pthread_create(&thread_id, NULL, cork_thread_pthread_run, self);\n    if (CORK_UNLIKELY(rc != 0)) {\n        cork_system_error_set_explicit(rc);\n        return -1;\n    }\n\n#if defined(__linux) && ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 12))\n    /* On Linux we choose which thread to name via an explicit thread ID.\n     * However, pthread_setname_np() isn't supported on versions of glibc\n     * earlier than 2.12. So we need to check for a MINOR version of 12 or\n     * higher. */\n    strncpy(thread_name, self->name, PTHREADS_MAX_THREAD_NAME_LENGTH);\n    thread_name[PTHREADS_MAX_THREAD_NAME_LENGTH - 1] = '\\0';\n    pthread_setname_np(thread_id, thread_name);\n#endif\n\n    self->thread_id = thread_id;\n    self->started = true;\n    return 0;\n}\n\nint\ncork_thread_join(struct cork_thread *self)\n{\n    int  rc;\n\n    assert(self->started && !self->joined);\n\n    rc = pthread_join(self->thread_id, NULL);\n    if (CORK_UNLIKELY(rc != 0)) {\n        cork_system_error_set_explicit(rc);\n        cork_thread_free_private(self);\n        return -1;\n    }\n\n    if (CORK_UNLIKELY(self->error_code != CORK_ERROR_NONE)) {\n        cork_error_set_printf\n            (self->error_code, \"Error from thread %s: %s\",\n             self->name, (char *) self->error_message.buf);\n        cork_thread_free_private(self);\n        return -1;\n    }\n\n    cork_thread_free_private(self);\n    return 0;\n}\n"
  },
  {
    "path": "src/libcork.pc.in",
    "content": "PACKAGE_TARNAME=@PACKAGE_TARNAME@\nprefix=@prefix@\nexec_prefix=@exec_prefix@\ndatarootdir=@datarootdir@\ndocdir=@docdir@\nincludedir=@includedir@\nlibdir=@libdir@\nsphinxdir=${docdir}/html\n\nName: libcork\nDescription: A simple, easily embeddable cross-platform C library\nVersion: @VERSION@\nURL: https://libcork.io/\nLibs: -L${libdir} -lcork\nLibs.private: @PTHREAD_LIBS@\nCflags: -I${includedir} @PTHREAD_CFLAGS@\n"
  },
  {
    "path": "tests/.gitattributes",
    "content": "*.t       -whitespace\ncram.py   -diff\n"
  },
  {
    "path": "tests/.gitignore",
    "content": "*.t.err\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2011, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\ninclude_directories(\n    ${CMAKE_SOURCE_DIR}/include\n    ${CMAKE_BINARY_DIR}/include\n    ${CMAKE_CURRENT_BINARY_DIR}\n)\n\nfind_package(PythonInterp)\n\n#-----------------------------------------------------------------------\n# Build the test cases\n\nmacro(make_test test_name)\n  add_executable(${test_name} ${test_name}.c)\n  add_test(${test_name} ${test_name})\n  if (ENABLE_SHARED_TESTS)\n    target_link_libraries(${test_name} ${CHECK_LIBRARIES} libcork-shared)\n  else (ENABLE_SHARED_TESTS)\n    set_target_properties(${test_name} PROPERTIES COMPILE_DEFINITIONS CORK_EMBEDDED_TEST=1)\n    target_link_libraries(${test_name} ${CHECK_LIBRARIES} libcork-static)\n  endif (ENABLE_SHARED_TESTS)\nendmacro(make_test)\n\nmake_test(test-array)\nmake_test(test-bitset)\nmake_test(test-buffer)\nmake_test(test-core)\nmake_test(test-dllist)\nmake_test(test-files)\nmake_test(test-gc)\nmake_test(test-hash-table)\nmake_test(test-managed-buffer)\nmake_test(test-mempool)\nmake_test(test-ring-buffer)\nmake_test(test-slice)\nmake_test(test-subprocess)\nmake_test(test-threads)\nmake_test(test-u128)\n\n#-----------------------------------------------------------------------\n# Test suite for 128-bit integers\n\n# We use Python to generate a LARGE pile of test cases for our 128-bit integer\n# arithmetic functions.\n\nadd_custom_target(u128-test-suite)\nadd_dependencies(test-u128 u128-test-suite)\n\nmacro(make_u128_suite op)\n    set(generator \"${CMAKE_CURRENT_SOURCE_DIR}/create-u128-test-cases.py\")\n    set(test_suite_file \"${CMAKE_CURRENT_BINARY_DIR}/u128-tests-${op}.c.in\")\n    add_custom_command(\n        OUTPUT \"${test_suite_file}\"\n        COMMAND\n          \"${PYTHON_EXECUTABLE}\" \"${generator}\" \"${op}\" \"${test_suite_file}\"\n        COMMENT \"Generating u128 ${op} test cases\"\n        DEPENDS \"${generator}\"\n    )\n    add_custom_target(u128-test-${op} DEPENDS \"${test_suite_file}\")\n    add_dependencies(u128-test-suite u128-test-${op})\nendmacro(make_u128_suite)\n\nmake_u128_suite(eq)\nmake_u128_suite(ne)\nmake_u128_suite(lt)\nmake_u128_suite(le)\nmake_u128_suite(gt)\nmake_u128_suite(ge)\nmake_u128_suite(shl)\nmake_u128_suite(shr)\nmake_u128_suite(add)\nmake_u128_suite(sub)\n\n#-----------------------------------------------------------------------\n# Command-line tests\n\nif (NOT CRAM_EXECUTABLE)\n    set(CRAM_EXECUTABLE \"${CMAKE_CURRENT_SOURCE_DIR}/cram.py\")\nendif (NOT CRAM_EXECUTABLE)\n\nif (PYTHON_EXECUTABLE)\n    configure_file(ccram ${CMAKE_BINARY_DIR}/ccram COPYONLY)\n    file(GLOB_RECURSE TESTS \"${CMAKE_CURRENT_SOURCE_DIR}/*.t\")\n    foreach(TEST ${TESTS})\n        get_filename_component(TEST_NAME \"${TEST}\" NAME_WE)\n        add_test(\n            ${TEST_NAME}\n            ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}\n            ${CMAKE_BINARY_DIR}/ccram\n                --python ${PYTHON_EXECUTABLE}\n                --root ${CMAKE_SOURCE_DIR}\n                --build ${CMAKE_BINARY_DIR}/src\n                --cram ${CRAM_EXECUTABLE}\n                --tests ${TEST}\n        )\n    endforeach(TEST)\nelse (PYTHON_EXECUTABLE)\n    message(WARNING \"Unable to find Python; skipping cram tests.\")\nendif (PYTHON_EXECUTABLE)\n"
  },
  {
    "path": "tests/COPYING.cram.txt",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year  name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "tests/ccram",
    "content": "#!/bin/sh\n\nset -e\n\nif [ \"$1\" = \"--python\" ]; then\n    shift\n    PYTHON=\"$1\"\n    shift\nelse\n    PYTHON=python\nfi\n\nif [ \"$1\" = \"--root\" ]; then\n    shift\n    ROOT=\"$1\"\n    shift\nelse\n    ROOT=$(dirname $PWD)\nfi\n\nif [ \"$1\" = \"--build\" ]; then\n    shift\n    BUILD=\"$1\"\n    shift\nelse\n    BUILD=$PWD\nfi\n\nif [ \"$1\" = \"--cram\" ]; then\n    shift\n    CRAM=\"$1\"\n    shift\nelse\n    CRAM=\"$ROOT/tests/cram.py\"\nfi\n\nif [ \"$1\" = \"--tests\" ]; then\n    shift\n    TESTS=\"$1\"\n    shift\nelse\n    TESTS=../tests\nfi\n\nexport ROOT\n\nPATH=\"$BUILD:$PATH\" exec \"$PYTHON\" \"$CRAM\" \"$@\" \"$TESTS\"\n"
  },
  {
    "path": "tests/cork-hash.t",
    "content": "Make sure that our stable hash is really stable.\n\n  $ cork-hash foo\n  0xf6a5c420\n  $ cork-hash bar\n  0x450e998d\n  $ cork-hash tests.h\n  0x0b0628ee\n  $ cork-hash \"A longer string\"\n  0x53a2c885\n"
  },
  {
    "path": "tests/cork-initializer.t",
    "content": "We need to sort the output, since there's no guarantee about which order our\ninitializer functions will run in.\n\n  $ cork-initializer | sort\n  Finalizer 1\n  Initializer 1\n  Initializer 2\n"
  },
  {
    "path": "tests/cork-test/cleanup.t",
    "content": "  $ cork-test cleanup\n  Cleanup function 0\n  Cleanup function 1\n  Cleanup function 2\n  Cleanup function 3\n  Cleanup function 4\n  Cleanup function 5\n"
  },
  {
    "path": "tests/cork-test/directory-watcher.t",
    "content": "This first test makes sure to only create one file or subdirectory in each\ndirectory.  That means that we don't have to sort the output to get a\nreproducible result, which lets us check the ordering of the different events in\nthe callback stucture.\n\n  $ mkdir test1\n  $ mkdir test1/a\n  $ mkdir test1/a/b\n  $ touch test1/a/b/c\n  $ cork-test dir test1\n  Entering a (a)\n    Entering b (a/b)\n      c (a/b/c) (test1/a/b/c)\n    Leaving a/b\n  Leaving a\n  $ cork-test dir --shallow test1\n  Skipping a\n\n  $ mkdir test2\n  $ touch test2/a\n  $ cork-test dir test2\n  a (a) (test2/a)\n  $ cork-test dir --shallow test2\n  a (a) (test2/a)\n\nA more complex directory structure.  We have to sort the output, since there's\nno guarantee in what order the directory walker will encounter the files.\n\n  $ mkdir test3\n  $ mkdir test3/d1\n  $ mkdir test3/d2\n  $ touch test3/d2/a\n  $ touch test3/d2/b\n  $ mkdir test3/d3\n  $ touch test3/d3/a\n  $ touch test3/d3/b\n  $ touch test3/d3/c\n  $ mkdir test3/d3/s1\n  $ mkdir test3/d3/s1/s2\n  $ touch test3/d3/s1/s2/a\n  $ cork-test dir --only-files test3 | sort\n  d2/a\n  d2/b\n  d3/a\n  d3/b\n  d3/c\n  d3/s1/s2/a\n\nTest what happens when the directory doesn't exit.\n\n  $ cork-test dir missing\n  No such file or directory\n  [1]\n  $ cork-test dir --only-files missing\n  No such file or directory\n  [1]\n  $ cork-test dir --shallow missing\n  No such file or directory\n  [1]\n"
  },
  {
    "path": "tests/cork-test/help1-c1-s1.t",
    "content": "  $ cork-test c1 s1 --help\n  Usage: cork-test c1 s1 [<options>] <filename>\n  \n  This is a pretty cool command.\n"
  },
  {
    "path": "tests/cork-test/help1-c1-s2.t",
    "content": "  $ cork-test c1 s2 --help\n  Usage: cork-test c1 s2 [<options>] <filename>\n  \n  This is an excellent command.\n"
  },
  {
    "path": "tests/cork-test/help1-c1.t",
    "content": "  $ cork-test c1 --help\n  Usage: cork-test c1 <command> [<options>]\n  \n  Available commands:\n    s1  Subcommand 1\n    s2  Subcommand 2\n"
  },
  {
    "path": "tests/cork-test/help1-c2.t",
    "content": "  $ cork-test c2 --help\n  Usage: cork-test c2 [<options>] <filename>\n  \n  This command is pretty decent.\n"
  },
  {
    "path": "tests/cork-test/help1-root.t",
    "content": "  $ cork-test --help\n  Usage: cork-test <command> [<options>]\n  \n  Available commands:\n    c1       Command 1 (now with subcommands)\n    c2       Command 2\n    pwd      Print working directory\n    mkdir    Create a directory\n    rm       Remove a file or directory\n    find     Search for a file in a list of directories\n    paths    Print out standard paths for the current user\n    dir      Print the contents of a directory\n    sub      Run a subcommand\n    cleanup  Test process cleanup functions\n"
  },
  {
    "path": "tests/cork-test/help2-c1-s1.t",
    "content": "  $ cork-test c1 s1 -h\n  Usage: cork-test c1 s1 [<options>] <filename>\n  \n  This is a pretty cool command.\n"
  },
  {
    "path": "tests/cork-test/help2-c1-s2.t",
    "content": "  $ cork-test c1 s2 -h\n  Usage: cork-test c1 s2 [<options>] <filename>\n  \n  This is an excellent command.\n"
  },
  {
    "path": "tests/cork-test/help2-c1.t",
    "content": "  $ cork-test c1 -h\n  Usage: cork-test c1 <command> [<options>]\n  \n  Available commands:\n    s1  Subcommand 1\n    s2  Subcommand 2\n"
  },
  {
    "path": "tests/cork-test/help2-c2.t",
    "content": "  $ cork-test c2 -h\n  Usage: cork-test c2 [<options>] <filename>\n  \n  This command is pretty decent.\n"
  },
  {
    "path": "tests/cork-test/help2-root.t",
    "content": "  $ cork-test -h\n  Usage: cork-test <command> [<options>]\n  \n  Available commands:\n    c1       Command 1 (now with subcommands)\n    c2       Command 2\n    pwd      Print working directory\n    mkdir    Create a directory\n    rm       Remove a file or directory\n    find     Search for a file in a list of directories\n    paths    Print out standard paths for the current user\n    dir      Print the contents of a directory\n    sub      Run a subcommand\n    cleanup  Test process cleanup functions\n"
  },
  {
    "path": "tests/cork-test/help3-c1-s1.t",
    "content": "  $ cork-test help c1 s1\n  Usage: cork-test c1 s1 [<options>] <filename>\n  \n  This is a pretty cool command.\n"
  },
  {
    "path": "tests/cork-test/help3-c1-s2.t",
    "content": "  $ cork-test help c1 s2\n  Usage: cork-test c1 s2 [<options>] <filename>\n  \n  This is an excellent command.\n"
  },
  {
    "path": "tests/cork-test/help3-c1.t",
    "content": "  $ cork-test help c1\n  Usage: cork-test c1 <command> [<options>]\n  \n  Available commands:\n    s1  Subcommand 1\n    s2  Subcommand 2\n"
  },
  {
    "path": "tests/cork-test/help3-c2.t",
    "content": "  $ cork-test help c2\n  Usage: cork-test c2 [<options>] <filename>\n  \n  This command is pretty decent.\n"
  },
  {
    "path": "tests/cork-test/help3-root.t",
    "content": "  $ cork-test help\n  Usage: cork-test <command> [<options>]\n  \n  Available commands:\n    c1       Command 1 (now with subcommands)\n    c2       Command 2\n    pwd      Print working directory\n    mkdir    Create a directory\n    rm       Remove a file or directory\n    find     Search for a file in a list of directories\n    paths    Print out standard paths for the current user\n    dir      Print the contents of a directory\n    sub      Run a subcommand\n    cleanup  Test process cleanup functions\n"
  },
  {
    "path": "tests/cork-test/no-command-c1.t",
    "content": "  $ cork-test c1\n  No command given.\n  Usage: cork-test c1 <command> [<options>]\n  \n  Available commands:\n    s1  Subcommand 1\n    s2  Subcommand 2\n  [1]\n"
  },
  {
    "path": "tests/cork-test/no-command-root.t",
    "content": "  $ cork-test\n  No command given.\n  Usage: cork-test <command> [<options>]\n  \n  Available commands:\n    c1       Command 1 (now with subcommands)\n    c2       Command 2\n    pwd      Print working directory\n    mkdir    Create a directory\n    rm       Remove a file or directory\n    find     Search for a file in a list of directories\n    paths    Print out standard paths for the current user\n    dir      Print the contents of a directory\n    sub      Run a subcommand\n    cleanup  Test process cleanup functions\n  [1]\n"
  },
  {
    "path": "tests/cork-test/run-c1-s1-f-t.t",
    "content": "  $ cork-test c1 -f foo s1 -t\n  You chose command \"c1 s1\".  Good for you!\n  And you gave the --test option!  Look at that.\n  And you want the file to be foo.  Sure thing.\n"
  },
  {
    "path": "tests/cork-test/run-c1-s1-f.t",
    "content": "  $ cork-test c1 -f foo s1\n  You chose command \"c1 s1\".  Good for you!\n  And you want the file to be foo.  Sure thing.\n"
  },
  {
    "path": "tests/cork-test/run-c1-s1-t.t",
    "content": "  $ cork-test c1 s1 -t\n  You chose command \"c1 s1\".  Good for you!\n  And you gave the --test option!  Look at that.\n"
  },
  {
    "path": "tests/cork-test/run-c1-s1-test.t",
    "content": "  $ cork-test c1 s1 --test\n  You chose command \"c1 s1\".  Good for you!\n  And you gave the --test option!  Look at that.\n"
  },
  {
    "path": "tests/cork-test/run-c1-s1.t",
    "content": "  $ cork-test c1 s1\n  You chose command \"c1 s1\".  Good for you!\n"
  },
  {
    "path": "tests/cork-test/run-c1-s2-f.t",
    "content": "  $ cd $TESTDIR\n  $ cork-test c1 -f ../test-input.txt s2\n  You chose command \"c1 s2\".  Fantastico!\n  And you want the file to be ../test-input.txt.  Sure thing.\n  Hello, world\n  What is up\n"
  },
  {
    "path": "tests/cork-test/run-c1-s2-file.t",
    "content": "  $ cd $TESTDIR\n  $ cork-test c1 --file ../test-input.txt s2\n  You chose command \"c1 s2\".  Fantastico!\n  And you want the file to be ../test-input.txt.  Sure thing.\n  Hello, world\n  What is up\n"
  },
  {
    "path": "tests/cork-test/run-c1-s2.t",
    "content": "  $ cork-test c1 s2\n  You chose command \"c1 s2\".  Fantastico!\n"
  },
  {
    "path": "tests/cork-test/run-c2.t",
    "content": "  $ cork-test c2\n  You chose command \"c2\".  That's pretty good.\n"
  },
  {
    "path": "tests/cork-test/run-find-01.t",
    "content": "  $ cork-test mkdir --recursive a/b/c/b\n\n  $ cork-test find b a\n  a/b\n  $ cork-test find b a/b/c\n  a/b/c/b\n  $ cork-test find b a:a/b/c\n  a/b\n  $ cork-test find b a/b/c:a\n  a/b/c/b\n\n  $ cork-test find b/c a\n  a/b/c\n  $ cork-test find b/c a/b/c\n  b/c not found in a/b/c\n  [1]\n\n  $ cork-test find d a\n  d not found in a\n  [1]\n  $ cork-test find d a:a/b:a/b/c\n  d not found in a:a/b:a/b/c\n  [1]\n"
  },
  {
    "path": "tests/cork-test/run-find-all-01.t",
    "content": "  $ cork-test mkdir --recursive a/b/c/b\n\n  $ cork-test find --all b a\n  a/b\n  $ cork-test find --all b a/b/c\n  a/b/c/b\n  $ cork-test find --all b a:a/b/c\n  a/b\n  a/b/c/b\n  $ cork-test find --all b a/b/c:a\n  a/b/c/b\n  a/b\n\n  $ cork-test find --all b/c a\n  a/b/c\n  $ cork-test find --all b/c a/b/c\n\n  $ cork-test find --all d a\n  $ cork-test find --all d a:a/b:a/b/c\n"
  },
  {
    "path": "tests/cork-test/run-mkdir-01.t",
    "content": "  $ cork-test mkdir a\n  $ find a | sort\n  a\n\n  $ cork-test mkdir a\n  $ find a | sort\n  a\n\n  $ cork-test mkdir --require a\n  File exists\n  [1]\n  $ find a | sort\n  a\n\n  $ cork-test mkdir --recursive a/b/c\n  $ find a | sort\n  a\n  a/b\n  a/b/c\n\n  $ cork-test mkdir --recursive a/b\n  $ find a | sort\n  a\n  a/b\n  a/b/c\n\n  $ cork-test mkdir --recursive --require a/b\n  File exists\n  [1]\n  $ find a | sort\n  a\n  a/b\n  a/b/c\n\n  $ cork-test mkdir --recursive --require a/b/d\n  $ find a | sort\n  a\n  a/b\n  a/b/c\n  a/b/d\n"
  },
  {
    "path": "tests/cork-test/run-paths-01.t",
    "content": "  $ HOME= \\\n  >     cork-test paths\n  Cannot determine home directory\n  [1]\n\n  $ HOME=/home/test \\\n  > XDG_CONFIG_HOME= \\\n  > XDG_DATA_HOME= \\\n  > XDG_CONFIG_DIRS= \\\n  > XDG_DATA_DIRS= \\\n  > XDG_CACHE_HOME= \\\n  > XDG_RUNTIME_DIR= \\\n  >     cork-test paths\n  Home:    /home/test\n  Config:  /home/test/.config:/etc/xdg\n  Data:    /home/test/.local/share:/usr/local/share:/usr/share\n  Cache:   /home/test/.cache\n  Cannot determine user-specific runtime directory\n  [1]\n\n  $ HOME=/home/test \\\n  > XDG_CONFIG_HOME= \\\n  > XDG_DATA_HOME= \\\n  > XDG_CONFIG_DIRS= \\\n  > XDG_DATA_DIRS= \\\n  > XDG_CACHE_HOME= \\\n  > XDG_RUNTIME_DIR=/run/user/test \\\n  >     cork-test paths\n  Home:    /home/test\n  Config:  /home/test/.config:/etc/xdg\n  Data:    /home/test/.local/share:/usr/local/share:/usr/share\n  Cache:   /home/test/.cache\n  Runtime: /run/user/test\n\n  $ HOME=/home/test \\\n  > XDG_CONFIG_HOME=/home/test/custom-config \\\n  > XDG_DATA_HOME=/home/test/share \\\n  > XDG_CONFIG_DIRS=/etc \\\n  > XDG_DATA_DIRS=/usr/share \\\n  > XDG_CACHE_HOME=/tmp/cache/test \\\n  > XDG_RUNTIME_DIR=/run/user/test \\\n  >     cork-test paths\n  Home:    /home/test\n  Config:  /home/test/custom-config:/etc\n  Data:    /home/test/share:/usr/share\n  Cache:   /tmp/cache/test\n  Runtime: /run/user/test\n"
  },
  {
    "path": "tests/cork-test/run-pwd-01.t",
    "content": "  $ a=$(cork-test pwd)\n  $ b=$(pwd)\n  $ [ \"$a\" = \"$b\" ]\n"
  },
  {
    "path": "tests/cork-test/run-rm-01.t",
    "content": "  $ cork-test mkdir --recursive --require a/b/c\n  $ cork-test mkdir --recursive --require a/b/d\n  $ find a 2>/dev/null | sort\n  a\n  a/b\n  a/b/c\n  a/b/d\n\n  $ cork-test rm --require a/b/d\n  $ find a 2>/dev/null | sort\n  a\n  a/b\n  a/b/c\n\n  $ cork-test rm --require a/b/d\n  No such file or directory\n  [1]\n  $ find a 2>/dev/null | sort\n  a\n  a/b\n  a/b/c\n\n  $ cork-test rm --require --recursive a/b/c\n  $ find a 2>/dev/null | sort\n  a\n  a/b\n\n  $ cork-test rm --recursive a\n  $ find a 2>/dev/null | sort\n"
  },
  {
    "path": "tests/cork-test/run-sub-01.t",
    "content": "  $ cork-test sub echo Hello world\n  echo Hello world\n  Hello world\n"
  },
  {
    "path": "tests/cork-test/run-sub-02.t",
    "content": "  $ cork-test sub false\n  false\n"
  },
  {
    "path": "tests/cork-test/run-sub-03.t",
    "content": "  $ CORK_TEST_VAR=\"Hello world\" cork-test sub sh -c 'echo $CORK_TEST_VAR'\n  sh -c echo $CORK_TEST_VAR\n  Hello world\n"
  },
  {
    "path": "tests/cork-test/run-sub-04.t",
    "content": "  $ cork-test sub bad-command\n  bad-command\n  No such file or directory\n"
  },
  {
    "path": "tests/cork-test/run-sub-05.t",
    "content": "  $ cork-test sub -d / pwd\n  pwd\n  /\n"
  },
  {
    "path": "tests/cork-test/run-sub-06.t",
    "content": "  $ cork-test sub -i foo cat\n  cat\n  foo\n"
  },
  {
    "path": "tests/cram.py",
    "content": "#!/usr/bin/env python\n\"\"\"Functional testing framework for command line applications\"\"\"\n\nimport difflib\nimport itertools\nimport optparse\nimport os\nimport re\nimport signal\nimport subprocess\nimport sys\nimport shutil\nimport time\nimport tempfile\n\ntry:\n    import configparser\nexcept ImportError:\n    import ConfigParser as configparser\n\n__all__ = ['main', 'test']\n\ndef findtests(paths):\n    \"\"\"Yield tests in paths in sorted order\"\"\"\n    for p in paths:\n        if os.path.isdir(p):\n            for root, dirs, files in os.walk(p):\n                if os.path.basename(root).startswith('.'):\n                    continue\n                for f in sorted(files):\n                    if not f.startswith('.') and f.endswith('.t'):\n                        yield os.path.normpath(os.path.join(root, f))\n        else:\n            yield os.path.normpath(p)\n\ndef regex(pattern, s):\n    \"\"\"Match a regular expression or return False if invalid.\n\n    >>> [bool(regex(r, 'foobar')) for r in ('foo.*', '***')]\n    [True, False]\n    \"\"\"\n    try:\n        return re.match(pattern + r'\\Z', s)\n    except re.error:\n        return False\n\ndef glob(el, l):\n    r\"\"\"Match a glob-like pattern.\n\n    The only supported special characters are * and ?. Escaping is\n    supported.\n\n    >>> bool(glob(r'\\* \\\\ \\? fo?b*', '* \\\\ ? foobar'))\n    True\n    \"\"\"\n    i, n = 0, len(el)\n    res = ''\n    while i < n:\n        c = el[i]\n        i += 1\n        if c == '\\\\' and el[i] in '*?\\\\':\n            res += el[i - 1:i + 1]\n            i += 1\n        elif c == '*':\n            res += '.*'\n        elif c == '?':\n            res += '.'\n        else:\n            res += re.escape(c)\n    return regex(res, l)\n\nannotations = {'glob': glob, 're': regex}\n\ndef match(el, l):\n    \"\"\"Match patterns based on annotations\"\"\"\n    for k in annotations:\n        ann = ' (%s)\\n' % k\n        if el.endswith(ann) and annotations[k](el[:-len(ann)], l[:-1]):\n            return True\n    return False\n\nclass SequenceMatcher(difflib.SequenceMatcher, object):\n    \"\"\"Like difflib.SequenceMatcher, but matches globs and regexes\"\"\"\n\n    def find_longest_match(self, alo, ahi, blo, bhi):\n        \"\"\"Find longest matching block in a[alo:ahi] and b[blo:bhi]\"\"\"\n        # SequenceMatcher uses find_longest_match() to slowly whittle down\n        # the differences between a and b until it has each matching block.\n        # Because of this, we can end up doing the same matches many times.\n        matches = []\n        for n, (el, line) in enumerate(zip(self.a[alo:ahi], self.b[blo:bhi])):\n            if el != line and match(el, line):\n                # This fools the superclass's method into thinking that the\n                # regex/glob in a is identical to b by replacing a's line (the\n                # expected output) with b's line (the actual output).\n                self.a[alo + n] = line\n                matches.append((n, el))\n        ret = super(SequenceMatcher, self).find_longest_match(alo, ahi,\n                                                              blo, bhi)\n        # Restore the lines replaced above. Otherwise, the diff output\n        # would seem to imply that the tests never had any regexes/globs.\n        for n, el in matches:\n            self.a[alo + n] = el\n        return ret\n\ndef unified_diff(a, b, fromfile='', tofile='', fromfiledate='',\n                 tofiledate='', n=3, lineterm='\\n', matcher=SequenceMatcher):\n    \"\"\"Compare two sequences of lines; generate the delta as a unified diff.\n\n    This is like difflib.unified_diff(), but allows custom matchers.\n    \"\"\"\n    started = False\n    for group in matcher(None, a, b).get_grouped_opcodes(n):\n        if not started:\n            fromdate = fromfiledate and '\\t%s' % fromfiledate or ''\n            todate = fromfiledate and '\\t%s' % tofiledate or ''\n            yield '--- %s%s%s' % (fromfile, fromdate, lineterm)\n            yield '+++ %s%s%s' % (tofile, todate, lineterm)\n            started = True\n        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]\n        yield \"@@ -%d,%d +%d,%d @@%s\" % (i1 + 1, i2 - i1, j1 + 1, j2 - j1,\n                                         lineterm)\n        for tag, i1, i2, j1, j2 in group:\n            if tag == 'equal':\n                for line in a[i1:i2]:\n                    yield ' ' + line\n                continue\n            if tag == 'replace' or tag == 'delete':\n                for line in a[i1:i2]:\n                    yield '-' + line\n            if tag == 'replace' or tag == 'insert':\n                for line in b[j1:j2]:\n                    yield '+' + line\n\nneedescape = re.compile(r'[\\x00-\\x09\\x0b-\\x1f\\x7f-\\xff]').search\nescapesub = re.compile(r'[\\x00-\\x09\\x0b-\\x1f\\\\\\x7f-\\xff]').sub\nescapemap = dict((chr(i), r'\\x%02x' % i) for i in range(256))\nescapemap.update({'\\\\': '\\\\\\\\', '\\r': r'\\r', '\\t': r'\\t'})\n\ndef escape(s):\n    \"\"\"Like the string-escape codec, but doesn't escape quotes\"\"\"\n    return escapesub(lambda m: escapemap[m.group(0)], s[:-1]) + ' (esc)\\n'\n\ndef makeresetsigpipe():\n    \"\"\"Make a function to reset SIGPIPE to SIG_DFL (for use in subprocesses).\n\n    Doing subprocess.Popen(..., preexec_fn=makeresetsigpipe()) will prevent\n    Python's SIGPIPE handler (SIG_IGN) from being inherited by the\n    child process.\n    \"\"\"\n    if sys.platform == 'win32' or getattr(signal, 'SIGPIPE', None) is None:\n        return None\n    return lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)\n\ndef test(path, shell, indent=2):\n    \"\"\"Run test at path and return input, output, and diff.\n\n    This returns a 3-tuple containing the following:\n\n        (list of lines in test, same list with actual output, diff)\n\n    diff is a generator that yields the diff between the two lists.\n\n    If a test exits with return code 80, the actual output is set to\n    None and diff is set to [].\n    \"\"\"\n    indent = ' ' * indent\n    cmdline = '%s$ ' % indent\n    conline = '%s> ' % indent\n\n    f = open(path)\n    abspath = os.path.abspath(path)\n    env = os.environ.copy()\n    env['TESTDIR'] = os.path.dirname(abspath)\n    env['TESTFILE'] = os.path.basename(abspath)\n    p = subprocess.Popen([shell, '-'], bufsize=-1, stdin=subprocess.PIPE,\n                         stdout=subprocess.PIPE, stderr=subprocess.STDOUT,\n                         universal_newlines=True, env=env,\n                         preexec_fn=makeresetsigpipe(),\n                         close_fds=os.name == 'posix')\n    salt = 'CRAM%s' % time.time()\n\n    after = {}\n    refout, postout = [], []\n    i = pos = prepos = -1\n    stdin = []\n    for i, line in enumerate(f):\n        refout.append(line)\n        if line.startswith(cmdline):\n            after.setdefault(pos, []).append(line)\n            prepos = pos\n            pos = i\n            stdin.append('echo \"\\n%s %s $?\"\\n' % (salt, i))\n            stdin.append(line[len(cmdline):])\n        elif line.startswith(conline):\n            after.setdefault(prepos, []).append(line)\n            stdin.append(line[len(conline):])\n        elif not line.startswith(indent):\n            after.setdefault(pos, []).append(line)\n    stdin.append('echo \"\\n%s %s $?\"\\n' % (salt, i + 1))\n\n    output = p.communicate(input=''.join(stdin))[0]\n    if p.returncode == 80:\n        return (refout, None, [])\n\n    # Add a trailing newline to the input script if it's missing.\n    if refout and not refout[-1].endswith('\\n'):\n        refout[-1] += '\\n'\n\n    # We use str.split instead of splitlines to get consistent\n    # behavior between Python 2 and 3. In 3, we use unicode strings,\n    # which has more line breaks than \\n and \\r.\n    pos = -1\n    ret = 0\n    for i, line in enumerate(output[:-1].split('\\n')):\n        line += '\\n'\n        if line.startswith(salt):\n            presalt = postout.pop()\n            if presalt != '%s\\n' % indent:\n                postout.append(presalt[:-1] + ' (no-eol)\\n')\n            ret = int(line.split()[2])\n            if ret != 0:\n                postout.append('%s[%s]\\n' % (indent, ret))\n            postout += after.pop(pos, [])\n            pos = int(line.split()[1])\n        else:\n            if needescape(line):\n                line = escape(line)\n            postout.append(indent + line)\n    postout += after.pop(pos, [])\n\n    diffpath = os.path.basename(abspath)\n    diff = unified_diff(refout, postout, diffpath, diffpath + '.err')\n    for firstline in diff:\n        return refout, postout, itertools.chain([firstline], diff)\n    return refout, postout, []\n\ndef prompt(question, answers, auto=None):\n    \"\"\"Write a prompt to stdout and ask for answer in stdin.\n\n    answers should be a string, with each character a single\n    answer. An uppercase letter is considered the default answer.\n\n    If an invalid answer is given, this asks again until it gets a\n    valid one.\n\n    If auto is set, the question is answered automatically with the\n    specified value.\n    \"\"\"\n    default = [c for c in answers if c.isupper()]\n    while True:\n        sys.stdout.write('%s [%s] ' % (question, answers))\n        sys.stdout.flush()\n        if auto is not None:\n            sys.stdout.write(auto + '\\n')\n            sys.stdout.flush()\n            return auto\n\n        answer = sys.stdin.readline().strip().lower()\n        if not answer and default:\n            return default[0]\n        elif answer and answer in answers.lower():\n            return answer\n\ndef log(msg=None, verbosemsg=None, verbose=False):\n    \"\"\"Write msg to standard out and flush.\n\n    If verbose is True, write verbosemsg instead.\n    \"\"\"\n    if verbose:\n        msg = verbosemsg\n    if msg:\n        sys.stdout.write(msg)\n        sys.stdout.flush()\n\ndef patch(cmd, diff, path):\n    \"\"\"Run echo [lines from diff] | cmd -p0\"\"\"\n    p = subprocess.Popen([cmd, '-p0'], bufsize=-1, stdin=subprocess.PIPE,\n                         universal_newlines=True,\n                         preexec_fn=makeresetsigpipe(),\n                         cwd=path,\n                         close_fds=os.name == 'posix')\n    p.communicate(''.join(diff))\n    return p.returncode == 0\n\ndef run(paths, tmpdir, shell, quiet=False, verbose=False, patchcmd=None,\n        answer=None, indent=2):\n    \"\"\"Run tests in paths in tmpdir.\n\n    If quiet is True, diffs aren't printed. If verbose is True,\n    filenames and status information are printed.\n\n    If patchcmd is set, a prompt is written to stdout asking if\n    changed output should be merged back into the original test. The\n    answer is read from stdin. If 'y', the test is patched using patch\n    based on the changed output.\n    \"\"\"\n    cwd = os.getcwd()\n    seen = set()\n    basenames = set()\n    skipped = failed = 0\n    for i, path in enumerate(findtests(paths)):\n        abspath = os.path.abspath(path)\n        if abspath in seen:\n            continue\n        seen.add(abspath)\n\n        log(None, '%s: ' % path, verbose)\n        if not os.stat(abspath).st_size:\n            skipped += 1\n            log('s', 'empty\\n', verbose)\n        else:\n            basename = os.path.basename(path)\n            if basename in basenames:\n                basename = '%s-%s' % (basename, i)\n            else:\n                basenames.add(basename)\n            testdir = os.path.join(tmpdir, basename)\n            os.mkdir(testdir)\n            try:\n                os.chdir(testdir)\n                refout, postout, diff = test(abspath, shell, indent)\n            finally:\n                os.chdir(cwd)\n\n            errpath = abspath + '.err'\n            if postout is None:\n                skipped += 1\n                log('s', 'skipped\\n', verbose)\n            elif not diff:\n                log('.', 'passed\\n', verbose)\n                if os.path.exists(errpath):\n                    os.remove(errpath)\n            else:\n                failed += 1\n                log('!', 'failed\\n', verbose)\n                if not quiet:\n                    log('\\n', None, verbose)\n                errfile = open(errpath, 'w')\n                try:\n                    for line in postout:\n                        errfile.write(line)\n                finally:\n                    errfile.close()\n                if not quiet:\n                    if patchcmd:\n                        diff = list(diff)\n                    for line in diff:\n                        log(line)\n                    if (patchcmd and\n                        prompt('Accept this change?', 'yN', answer) == 'y'):\n                        if patch(patchcmd, diff, os.path.dirname(abspath)):\n                            log(None, '%s: merged output\\n' % path, verbose)\n                            os.remove(errpath)\n                        else:\n                            log('%s: merge failed\\n' % path)\n    log('\\n', None, verbose)\n    log('# Ran %s tests, %s skipped, %s failed.\\n'\n        % (len(seen), skipped, failed))\n    return bool(failed)\n\ndef which(cmd):\n    \"\"\"Return the patch to cmd or None if not found\"\"\"\n    for p in os.environ['PATH'].split(os.pathsep):\n        path = os.path.join(p, cmd)\n        if os.path.isfile(path) and os.access(path, os.X_OK):\n            return os.path.abspath(path)\n    return None\n\ndef expandpath(path):\n    \"\"\"Expands ~ and environment variables in path\"\"\"\n    return os.path.expanduser(os.path.expandvars(path))\n\nclass OptionParser(optparse.OptionParser):\n    \"\"\"Like optparse.OptionParser, but supports setting values through\n    CRAM= and .cramrc.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self._config_opts = {}\n        optparse.OptionParser.__init__(self, *args, **kwargs)\n\n    def add_option(self, *args, **kwargs):\n        option = optparse.OptionParser.add_option(self, *args, **kwargs)\n        if option.dest and option.dest != 'version':\n            key = option.dest.replace('_', '-')\n            self._config_opts[key] = option.action == 'store_true'\n        return option\n\n    def parse_args(self, args=None, values=None):\n        config = configparser.RawConfigParser()\n        config.read(expandpath(os.environ.get('CRAMRC', '.cramrc')))\n        defaults = {}\n        for key, isbool in self._config_opts.items():\n            try:\n                if isbool:\n                    try:\n                        value = config.getboolean('cram', key)\n                    except ValueError:\n                        value = config.get('cram', key)\n                        self.error('--%s: invalid boolean value: %r'\n                                   % (key, value))\n                else:\n                    value = config.get('cram', key)\n            except (configparser.NoSectionError, configparser.NoOptionError):\n                pass\n            else:\n                defaults[key] = value\n        self.set_defaults(**defaults)\n\n        eargs = os.environ.get('CRAM', '').strip()\n        if eargs:\n            import shlex\n            args = args or []\n            args += shlex.split(eargs)\n\n        try:\n            return optparse.OptionParser.parse_args(self, args, values)\n        except optparse.OptionValueError:\n            self.error(str(sys.exc_info()[1]))\n\ndef main(args):\n    \"\"\"Main entry point.\n\n    args should not contain the script name.\n    \"\"\"\n    p = OptionParser(usage='cram [OPTIONS] TESTS...', prog='cram')\n    p.add_option('-V', '--version', action='store_true',\n                 help='show version information and exit')\n    p.add_option('-q', '--quiet', action='store_true',\n                 help=\"don't print diffs\")\n    p.add_option('-v', '--verbose', action='store_true',\n                 help='show filenames and test status')\n    p.add_option('-i', '--interactive', action='store_true',\n                 help='interactively merge changed test output')\n    p.add_option('-y', '--yes', action='store_true',\n                 help='answer yes to all questions')\n    p.add_option('-n', '--no', action='store_true',\n                 help='answer no to all questions')\n    p.add_option('-E', '--preserve-env', action='store_true',\n                 help=\"don't reset common environment variables\")\n    p.add_option('--keep-tmpdir', action='store_true',\n                 help='keep temporary directories')\n    p.add_option('--shell', action='store', default='/bin/sh', metavar='PATH',\n                 help='shell to use for running tests')\n    p.add_option('--indent', action='store', default=2, metavar='NUM',\n                 type='int', help='number of spaces to use for indentation')\n    opts, paths = p.parse_args(args)\n\n    if opts.version:\n        sys.stdout.write(\"\"\"Cram CLI testing framework (version 0.6)\n\nCopyright (C) 2010-2011 Brodie Rao <brodie@bitheap.org> and others\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\"\"\")\n        return\n\n    conflicts = [('-y', opts.yes, '-n', opts.no),\n                 ('-q', opts.quiet, '-i', opts.interactive)]\n    for s1, o1, s2, o2 in conflicts:\n        if o1 and o2:\n            sys.stderr.write('options %s and %s are mutually exclusive\\n'\n                             % (s1, s2))\n            return 2\n\n    patchcmd = None\n    if opts.interactive:\n        patchcmd = which('patch')\n        if not patchcmd:\n            sys.stderr.write('patch(1) required for -i\\n')\n            return 2\n\n    if not paths:\n        sys.stdout.write(p.get_usage())\n        return 2\n\n    badpaths = [path for path in paths if not os.path.exists(path)]\n    if badpaths:\n        sys.stderr.write('no such file: %s\\n' % badpaths[0])\n        return 2\n\n    tmpdir = os.environ['CRAMTMP'] = tempfile.mkdtemp('', 'cramtests-')\n    proctmp = os.path.join(tmpdir, 'tmp')\n    os.mkdir(proctmp)\n    for s in ('TMPDIR', 'TEMP', 'TMP'):\n        os.environ[s] = proctmp\n\n    if not opts.preserve_env:\n        for s in ('LANG', 'LC_ALL', 'LANGUAGE'):\n            os.environ[s] = 'C'\n        os.environ['TZ'] = 'GMT'\n        os.environ['CDPATH'] = ''\n        os.environ['COLUMNS'] = '80'\n        os.environ['GREP_OPTIONS'] = ''\n\n    if opts.yes:\n        answer = 'y'\n    elif opts.no:\n        answer = 'n'\n    else:\n        answer = None\n\n    try:\n        return run(paths, tmpdir, opts.shell, opts.quiet, opts.verbose,\n                   patchcmd, answer, opts.indent)\n    finally:\n        if opts.keep_tmpdir:\n            log('# Kept temporary directory: %s\\n' % tmpdir)\n        else:\n            shutil.rmtree(tmpdir)\n\nif __name__ == '__main__':\n    try:\n        sys.exit(main(sys.argv[1:]))\n    except KeyboardInterrupt:\n        pass\n"
  },
  {
    "path": "tests/create-u128-test-cases.py",
    "content": "# -*- coding: utf-8 -*-\n# ----------------------------------------------------------------------\n# Copyright © 2017, libcork authors\n# All rights reserved.\n#\n# Please see the COPYING file in this distribution for license details.\n# ----------------------------------------------------------------------\n\n# Generates some test cases for our u128 types.\n\nfrom __future__ import print_function\n\nimport operator\nimport random\nimport sys\n\ntest_count = 25000\nrandom.seed()\n\ndef random_shift_count():\n    # We want to test values [0, 128)\n    return int(random.random() * 128)\n\ndef random_128():\n    result = 0\n    for i in range(4):\n        result = result << 32\n        result = result + int(random.random() * 2**32)\n    return result\n\ndef dec_128(value):\n    return format(value, \"40d\")\n\ndef hex_128(value):\n    return (\"UINT64_C(0x\" + format(value >> 64, \"016x\") + \"), \" +\n            \"UINT64_C(0x\" + format(value & 0xffffffffffffffff, \"016x\") + \")\")\n\n\ndef output_one_cmp_test_case(op, op_str, lhs, rhs):\n    result = op(lhs, rhs)\n    result_str = \"    \" if result else \"not \"\n    result_c_str = \"true\" if result else \"false\"\n    print()\n    print(\"/*        \", dec_128(lhs), sep=\"\")\n    print(\" * \", result_str, op_str, \" \", dec_128(rhs), sep=\"\")\n    print(\" */\")\n    print(\"{\", sep=\"\")\n    print(\"    \", hex_128(lhs), \",\", sep=\"\")\n    print(\"    \", hex_128(rhs), \",\", sep=\"\")\n    print(\"    \", result_c_str, sep=\"\")\n    print(\"},\", sep=\"\")\n\ndef create_one_cmp_test_case(op, op_str):\n    lhs = random_128()\n    rhs = random_128()\n    output_one_cmp_test_case(op, op_str, lhs, lhs)\n    output_one_cmp_test_case(op, op_str, lhs, rhs)\n    output_one_cmp_test_case(op, op_str, rhs, rhs)\n\n\ndef create_one_shl_test_case():\n    lhs = random_128()\n    rhs = random_shift_count()\n    result = (lhs << rhs) % 2**128\n    print()\n    print(\"/*    \", dec_128(lhs), sep=\"\")\n    print(\" * << \", rhs, sep=\"\")\n    print(\" *  = \", dec_128(result), sep=\"\")\n    print(\" */\")\n    print(\"{\", sep=\"\")\n    print(\"    \", hex_128(lhs), \",\", sep=\"\")\n    print(\"    \", rhs, \",\", sep=\"\")\n    print(\"    \", hex_128(result), sep=\"\")\n    print(\"},\", sep=\"\")\n\n\ndef create_one_shr_test_case():\n    lhs = random_128()\n    rhs = random_shift_count()\n    result = (lhs >> rhs) % 2**128\n    print()\n    print(\"/*    \", dec_128(lhs), sep=\"\")\n    print(\" * >> \", rhs, sep=\"\")\n    print(\" *  = \", dec_128(result), sep=\"\")\n    print(\" */\")\n    print(\"{\", sep=\"\")\n    print(\"    \", hex_128(lhs), \",\", sep=\"\")\n    print(\"    \", rhs, \",\", sep=\"\")\n    print(\"    \", hex_128(result), sep=\"\")\n    print(\"},\", sep=\"\")\n\n\ndef create_one_add_test_case():\n    lhs = random_128()\n    rhs = random_128()\n    result = (lhs + rhs) % 2**128\n    print()\n    print(\"/*    \", dec_128(lhs), sep=\"\")\n    print(\" *  + \", dec_128(rhs), sep=\"\")\n    print(\" *  = \", dec_128(result), sep=\"\")\n    print(\" */\")\n    print(\"{\", sep=\"\")\n    print(\"    \", hex_128(lhs), \",\", sep=\"\")\n    print(\"    \", hex_128(rhs), \",\", sep=\"\")\n    print(\"    \", hex_128(result), sep=\"\")\n    print(\"},\", sep=\"\")\n\n\ndef create_one_sub_test_case():\n    lhs = random_128()\n    rhs = random_128()\n    if lhs < rhs:\n        lhs, rhs = rhs, lhs\n    result = (lhs - rhs) % 2**128\n    print()\n    print(\"/*    \", dec_128(lhs), sep=\"\")\n    print(\" *  - \", dec_128(rhs), sep=\"\")\n    print(\" *  = \", dec_128(result), sep=\"\")\n    print(\" */\")\n    print(\"{\", sep=\"\")\n    print(\"    \", hex_128(lhs), \",\", sep=\"\")\n    print(\"    \", hex_128(rhs), \",\", sep=\"\")\n    print(\"    \", hex_128(result), sep=\"\")\n    print(\"},\", sep=\"\")\n\n\nif len(sys.argv) == 1:\n    print(\"Usage: create-u128-test-cases.py [operator]\")\n    sys.exit(1)\n\nif len(sys.argv) > 2:\n    sys.stdout = open(sys.argv[2], 'w')\n\nprint(\"/* This file is autogenerated.  DO NOT EDIT! */\")\n\nfor i in range(test_count):\n    if sys.argv[1] == \"eq\":\n        create_one_cmp_test_case(operator.eq, \"==\")\n    elif sys.argv[1] == \"ne\":\n        create_one_cmp_test_case(operator.ne, \"!=\")\n    elif sys.argv[1] == \"lt\":\n        create_one_cmp_test_case(operator.lt, \"< \")\n    elif sys.argv[1] == \"le\":\n        create_one_cmp_test_case(operator.le, \"<=\")\n    elif sys.argv[1] == \"gt\":\n        create_one_cmp_test_case(operator.gt, \"> \")\n    elif sys.argv[1] == \"ge\":\n        create_one_cmp_test_case(operator.ge, \">=\")\n    elif sys.argv[1] == \"shl\":\n        create_one_shl_test_case()\n    elif sys.argv[1] == \"shr\":\n        create_one_shr_test_case()\n    elif sys.argv[1] == \"add\":\n        create_one_add_test_case()\n    elif sys.argv[1] == \"sub\":\n        create_one_sub_test_case()\n"
  },
  {
    "path": "tests/helpers.h",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#ifndef TESTS_HELPERS_H\n#define TESTS_HELPERS_H\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/error.h\"\n\n\n/*-----------------------------------------------------------------------\n * Allocators\n */\n\n/* For the \"embedded\" tests, use a custom allocator that debugs every\n * allocation.  For the \"shared\" tests, use the default allocator. */\n\n#if CORK_EMBEDDED_TEST\n\nstatic void\nsetup_allocator(void)\n{\n    struct cork_alloc  *debug = cork_debug_alloc_new(cork_allocator);\n    cork_set_allocator(debug);\n}\n\n#else /* !CORK_EMBEDDED_TEST */\n\nstatic void\nsetup_allocator(void)\n{\n    /* do nothing */\n}\n\n#endif\n\n\n/*-----------------------------------------------------------------------\n * Error reporting\n */\n\n#if !defined(PRINT_EXPECTED_FAILURES)\n#define PRINT_EXPECTED_FAILURES  1\n#endif\n\n#if PRINT_EXPECTED_FAILURES\n#define print_expected_failure() \\\n    printf(\"[expected: %s]\\n\", cork_error_message());\n#else\n#define print_expected_failure()  /* do nothing */\n#endif\n\n\n#define DESCRIBE_TEST \\\n    fprintf(stderr, \"--- %s\\n\", __func__);\n\n\n#define fail_if_error(call) \\\n    do { \\\n        call; \\\n        if (cork_error_occurred()) { \\\n            fail(\"%s\", cork_error_message()); \\\n        } \\\n    } while (0)\n\n#define fail_unless_error(call, ...) \\\n    do { \\\n        call; \\\n        if (!cork_error_occurred()) { \\\n            fail(__VA_ARGS__); \\\n        } else { \\\n            print_expected_failure(); \\\n        } \\\n        cork_error_clear(); \\\n    } while (0)\n\n#define fail_unless_equal(what, format, expected, actual) \\\n    (fail_unless((expected) == (actual), \\\n                 \"%s not equal (expected \" format \\\n                 \", got \" format \")\", \\\n                 (what), (expected), (actual)))\n\n#define fail_unless_streq(what, expected, actual) \\\n    (fail_unless(strcmp((expected), (actual)) == 0, \\\n                 \"%s not equal (expected \\\"%s\\\", got \\\"%s\\\")\", \\\n                 (char *) (what), (char *) (expected), (char *) (actual)))\n\n\n#endif /* TESTS_HELPERS_H */\n"
  },
  {
    "path": "tests/test-array.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/array.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Resizable arrays\n */\n\n#define verify_size(array, expected_size)                                      \\\n    fail_unless(cork_array_size((array)) == expected_size,                     \\\n                \"Unexpected size of array: got %zu, expected %zu\",             \\\n                cork_array_size((array)), expected_size);\n\n#define add_element(element, expected_new_size)                                \\\n    fail_if_error(cork_array_append(&array, element));                         \\\n    verify_size(&array, expected_new_size);\n\n#define add_element0(element, expected_new_size, int_type)                     \\\n    do {                                                                       \\\n        int_type* __element;                                                   \\\n        fail_if_error(__element = cork_array_append_get(&array));              \\\n        *__element = element;                                                  \\\n        verify_size(&array, expected_new_size);                                \\\n    } while (0)\n\n#define test_sum(array, expected) \\\n    do { \\\n        int64_t  sum = 0; \\\n        size_t  i; \\\n        for (i = 0; i < cork_array_size(array); i++) { \\\n            sum += cork_array_at(array, i); \\\n        } \\\n        fail_unless(sum == expected, \\\n                    \"Unexpected sum, got %ld, expected %ld\", \\\n                    (long) sum, (long) expected); \\\n    } while (0)\n\n#define test_int(int_type)                                                     \\\n    START_TEST(test_array_##int_type)                                          \\\n    {                                                                          \\\n        DESCRIBE_TEST;                                                         \\\n                                                                               \\\n        cork_array(int_type) array;                                            \\\n        cork_array(int_type) copy;                                             \\\n        cork_array_init(&array);                                               \\\n                                                                               \\\n        fail_unless(cork_array_size(&array) == 0,                              \\\n                    \"Unexpected size of array: got %zu, expected 0\",           \\\n                    cork_array_size(&array));                                  \\\n                                                                               \\\n        test_sum(&array, 0);                                                   \\\n        add_element(1, 1);                                                     \\\n        test_sum(&array, 1);                                                   \\\n        add_element0(2, 2, int_type);                                          \\\n        test_sum(&array, 3);                                                   \\\n        add_element(3, 3);                                                     \\\n        test_sum(&array, 6);                                                   \\\n        add_element0(4, 4, int_type);                                          \\\n        test_sum(&array, 10);                                                  \\\n        add_element0(5, 5, int_type);                                          \\\n        test_sum(&array, 15);                                                  \\\n        add_element(6, 6);                                                     \\\n        test_sum(&array, 21);                                                  \\\n        add_element(7, 7);                                                     \\\n        test_sum(&array, 28);                                                  \\\n        add_element0(8, 8, int_type);                                          \\\n        test_sum(&array, 36);                                                  \\\n        add_element(9, 9);                                                     \\\n        test_sum(&array, 45);                                                  \\\n        add_element0(10, 10, int_type);                                        \\\n        test_sum(&array, 55);                                                  \\\n                                                                               \\\n        cork_array_init(&copy);                                                \\\n        fail_if_error(cork_array_copy(&copy, &array, NULL, NULL));             \\\n        test_sum(&copy, 55);                                                   \\\n                                                                               \\\n        cork_array_remove(&copy, 9);                                           \\\n        verify_size(&copy, 9);                                                 \\\n        test_sum(&copy, 45);                                                   \\\n                                                                               \\\n        cork_array_remove_range(&copy, 2, 3);                                  \\\n        verify_size(&copy, 6);                                                 \\\n        test_sum(&copy, 33);                                                   \\\n                                                                               \\\n        cork_array_done(&array);                                               \\\n        cork_array_done(&copy);                                                \\\n    }                                                                          \\\n    END_TEST\n\ntest_int(int8_t)\ntest_int(int16_t)\ntest_int(int32_t)\ntest_int(int64_t)\n\n\n/*-----------------------------------------------------------------------\n * String arrays\n */\n\n#define add_string(element, expected_new_size)                                 \\\n    fail_if_error(cork_string_array_append(&array, element));                  \\\n    verify_size(&array, expected_new_size);\n\n#define test_string(array, index, expected) \\\n    do { \\\n        const char  *actual = cork_array_at(array, index); \\\n        fail_unless_streq(\"Array elements\", expected, actual); \\\n    } while (0)\n\nSTART_TEST(test_array_string)\n{\n    DESCRIBE_TEST;\n    struct cork_string_array  array;\n    struct cork_string_array  copy;\n\n    cork_string_array_init(&array);\n    add_string(\"hello\", 1);\n    add_string(\"there\", 2);\n    add_string(\"world\", 3);\n    test_string(&array, 0, \"hello\");\n    test_string(&array, 1, \"there\");\n    test_string(&array, 2, \"world\");\n    cork_array_remove(&array, 0);\n    test_string(&array, 0, \"there\");\n    test_string(&array, 1, \"world\");\n\n    cork_array_clear(&array);\n    add_string(\"reusing\", 1);\n    add_string(\"entries\", 2);\n    test_string(&array, 0, \"reusing\");\n    test_string(&array, 1, \"entries\");\n\n    cork_string_array_init(&copy);\n    cork_string_array_copy(&copy, &array);\n    test_string(&copy, 0, \"reusing\");\n    test_string(&copy, 1, \"entries\");\n    cork_array_done(&copy);\n\n    add_string(\"hello\", 3);\n    add_string(\"there\", 4);\n    add_string(\"world\", 5);\n    cork_array_remove_range(&array, 1, 2);\n    test_string(&array, 0, \"reusing\");\n    test_string(&array, 1, \"there\");\n    test_string(&array, 2, \"world\");\n    cork_array_remove(&array, 2);\n    test_string(&array, 0, \"reusing\");\n    test_string(&array, 1, \"there\");\n\n    cork_array_done(&array);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Array callbacks\n */\n\nstruct callback_counts {\n    size_t  init;\n    size_t  done;\n    size_t  reuse;\n    size_t  remove;\n};\n\nstatic void\ntest_array__init(void *user_data, void *vvalue)\n{\n    struct callback_counts  *counts = user_data;\n    counts->init++;\n}\n\nstatic void\ntest_array__done(void *user_data, void *vvalue)\n{\n    struct callback_counts  *counts = user_data;\n    counts->done++;\n}\n\nstatic void\ntest_array__reuse(void *user_data, void *vvalue)\n{\n    struct callback_counts  *counts = user_data;\n    counts->reuse++;\n}\n\nstatic void\ntest_array__remove(void *user_data, void *vvalue)\n{\n    struct callback_counts  *counts = user_data;\n    counts->remove++;\n}\n\ntypedef cork_array(unsigned int)  test_array;\n\nstatic void\ntest_array_init(test_array *array, struct callback_counts *counts)\n{\n    memset(counts, 0, sizeof(struct callback_counts));\n    cork_array_init(array);\n    cork_array_set_callback_data(array, counts, NULL);\n    cork_array_set_init(array, test_array__init);\n    cork_array_set_done(array, test_array__done);\n    cork_array_set_reuse(array, test_array__reuse);\n    cork_array_set_remove(array, test_array__remove);\n}\n\n#define check_counts(counts, e_init, e_done, e_reuse, e_remove) \\\n    do { \\\n        fail_unless_equal \\\n            (\"init counts\", \"%zu\", (size_t) e_init, (counts)->init); \\\n        fail_unless_equal \\\n            (\"done counts\", \"%zu\", (size_t) e_done, (counts)->done); \\\n        fail_unless_equal \\\n            (\"reuse counts\", \"%zu\", (size_t) e_reuse, (counts)->reuse); \\\n        fail_unless_equal \\\n            (\"remove counts\", \"%zu\", (size_t) e_remove, (counts)->remove); \\\n    } while (0)\n\nSTART_TEST(test_array_callbacks)\n{\n    DESCRIBE_TEST;\n    struct callback_counts  counts;\n    struct callback_counts  copy_counts;\n    test_array  array;\n    test_array  copy;\n\n    test_array_init(&array, &counts);\n    check_counts(&counts, 0, 0, 0, 0);\n    cork_array_append(&array, 0);\n    cork_array_append(&array, 1);\n    check_counts(&counts, 2, 0, 0, 0);\n    cork_array_append(&array, 2);\n    cork_array_append(&array, 3);\n    check_counts(&counts, 4, 0, 0, 0);\n    cork_array_clear(&array);\n    check_counts(&counts, 4, 0, 0, 4);\n    cork_array_append(&array, 0);\n    cork_array_append(&array, 1);\n    check_counts(&counts, 4, 0, 2, 4);\n    cork_array_append(&array, 2);\n    cork_array_append(&array, 3);\n    check_counts(&counts, 4, 0, 4, 4);\n    cork_array_append(&array, 4);\n    check_counts(&counts, 5, 0, 4, 4);\n\n    test_array_init(&copy, &copy_counts);\n    check_counts(&copy_counts, 0, 0, 0, 0);\n    cork_array_copy(&copy, &array, NULL, NULL);\n    check_counts(&copy_counts, 5, 0, 0, 0);\n    cork_array_done(&copy);\n    check_counts(&copy_counts, 5, 5, 0, 0);\n\n    test_array_init(&copy, &copy_counts);\n    check_counts(&copy_counts, 0, 0, 0, 0);\n    cork_array_append(&copy, 0);\n    cork_array_append(&copy, 1);\n    check_counts(&copy_counts, 2, 0, 0, 0);\n    cork_array_copy(&copy, &array, NULL, NULL);\n    check_counts(&copy_counts, 5, 0, 2, 2);\n    cork_array_done(&copy);\n    check_counts(&copy_counts, 5, 5, 2, 2);\n\n    test_array_init(&copy, &copy_counts);\n    check_counts(&copy_counts, 0, 0, 0, 0);\n    cork_array_append(&copy, 0);\n    cork_array_append(&copy, 1);\n    cork_array_append(&copy, 2);\n    cork_array_append(&copy, 3);\n    cork_array_append(&copy, 4);\n    cork_array_append(&copy, 5);\n    cork_array_append(&copy, 6);\n    check_counts(&copy_counts, 7, 0, 0, 0);\n    cork_array_copy(&copy, &array, NULL, NULL);\n    check_counts(&copy_counts, 7, 0, 5, 7);\n    cork_array_done(&copy);\n    check_counts(&copy_counts, 7, 7, 5, 7);\n\n    cork_array_done(&array);\n    check_counts(&counts, 5, 5, 4, 4);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"array\");\n\n    TCase  *tc_ds = tcase_create(\"array\");\n    tcase_add_test(tc_ds, test_array_int8_t);\n    tcase_add_test(tc_ds, test_array_int16_t);\n    tcase_add_test(tc_ds, test_array_int32_t);\n    tcase_add_test(tc_ds, test_array_int64_t);\n    tcase_add_test(tc_ds, test_array_string);\n    tcase_add_test(tc_ds, test_array_callbacks);\n    suite_add_tcase(s, tc_ds);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-bitset.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/bitset.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Bit sets\n */\n\nstatic void\ntest_bitset_of_size(size_t bit_count)\n{\n    size_t  i;\n    struct cork_bitset  *set1 = cork_bitset_new(bit_count);\n    struct cork_bitset set2;\n\n    for (i = 0; i < bit_count; i++) {\n        cork_bitset_set(set1, i, true);\n        fail_unless(cork_bitset_get(set1, i), \"Unexpected value for bit %zu\", i);\n    }\n\n    for (i = 0; i < bit_count; i++) {\n        cork_bitset_set(set1, i, false);\n        fail_if(cork_bitset_get(set1, i), \"Unexpected value for bit %zu\", i);\n    }\n    cork_bitset_free(set1);\n\n    cork_bitset_init(&set2, bit_count);\n    for (i = 0; i < bit_count; i++) {\n        cork_bitset_set(&set2, i, true);\n        fail_unless(cork_bitset_get(&set2, i), \"Unexpected value for bit %zu\", i);\n    }\n\n    for (i = 0; i < bit_count; i++) {\n        cork_bitset_set(&set2, i, false);\n        fail_if(cork_bitset_get(&set2, i), \"Unexpected value for bit %zu\", i);\n    }\n    cork_bitset_done(&set2);\n}\n\nSTART_TEST(test_bitset)\n{\n    DESCRIBE_TEST;\n    /* Test a variety of sizes, with and without spillover bits. */\n    test_bitset_of_size(1);\n    test_bitset_of_size(2);\n    test_bitset_of_size(3);\n    test_bitset_of_size(4);\n    test_bitset_of_size(5);\n    test_bitset_of_size(6);\n    test_bitset_of_size(7);\n    test_bitset_of_size(8);\n    test_bitset_of_size(9);\n    test_bitset_of_size(10);\n    test_bitset_of_size(11);\n    test_bitset_of_size(12);\n    test_bitset_of_size(13);\n    test_bitset_of_size(14);\n    test_bitset_of_size(15);\n    test_bitset_of_size(16);\n    test_bitset_of_size(65535);\n    test_bitset_of_size(65536);\n    test_bitset_of_size(65537);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"bits\");\n\n    TCase  *tc_ds = tcase_create(\"bits\");\n    tcase_set_timeout(tc_ds, 120.0);\n    tcase_add_test(tc_ds, test_bitset);\n    suite_add_tcase(s, tc_ds);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2009, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/ds/managed-buffer.h\"\n#include \"libcork/ds/stream.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Buffers\n */\n\nstatic void\ncheck_buffers(const struct cork_buffer *buf1, const struct cork_buffer *buf2)\n{\n    fail_unless(cork_buffer_equal(buf1, buf2),\n                \"Buffers should be equal: got %zu:%s, expected %zu:%s\",\n                buf1->size, buf1->buf, buf2->size, buf2->buf);\n}\n\nstatic void\ncheck_buffer(const struct cork_buffer *buf, const char *expected)\n{\n    size_t  expected_len = strlen(expected);\n    fail_unless(buf->size == expected_len,\n                \"Unexpected buffer content: got %zu:%s, expected %zu:%s\",\n                buf->size, buf->buf, expected_len, expected);\n}\n\nSTART_TEST(test_buffer)\n{\n    static char  SRC[] =\n        \"Here is some text.\";\n    size_t  SRC_LEN = strlen(SRC);\n\n    struct cork_buffer  buffer1;\n    struct cork_buffer  *buffer2;\n    struct cork_buffer  *buffer3;\n    struct cork_buffer  buffer4;\n\n    cork_buffer_init(&buffer1);\n    fail_if_error(cork_buffer_set(&buffer1, SRC, SRC_LEN));\n\n    fail_unless(cork_buffer_char(&buffer1, 0) == 'H',\n                \"Unexpected character at position 0: got %c, expected %c\",\n                (int) cork_buffer_char(&buffer1, 0), (int) 'H');\n\n    fail_unless(cork_buffer_byte(&buffer1, 1) == (uint8_t) 'e',\n                \"Unexpected character at position 1: got %c, expected %c\",\n                (int) cork_buffer_byte(&buffer1, 1), (int) 'e');\n\n    fail_if_error(buffer2 = cork_buffer_new());\n    fail_if_error(cork_buffer_set_string(buffer2, SRC));\n    check_buffers(&buffer1, buffer2);\n\n    fail_if_error(buffer3 = cork_buffer_new());\n    fail_if_error(cork_buffer_printf\n                  (buffer3, \"Here is %s text.\", \"some\"));\n    check_buffers(&buffer1, buffer3);\n\n    cork_buffer_init(&buffer4);\n    cork_buffer_copy(&buffer4, &buffer1);\n    check_buffers(&buffer1, &buffer4);\n\n    cork_buffer_done(&buffer1);\n    cork_buffer_free(buffer2);\n    cork_buffer_free(buffer3);\n    cork_buffer_done(&buffer4);\n}\nEND_TEST\n\n\nSTART_TEST(test_buffer_append)\n{\n    static char  SRC1[] = \"abcd\";\n    size_t  SRC1_LEN = 4;\n    static char  SRC2[] = \"efg\";\n    size_t  SRC2_LEN = 3;\n    static char  SRC3[] = \"hij\";\n    static char  SRC4[] = \"kl\";\n    static char  EXPECTED[] = \"abcdefghijkl\";\n    struct cork_buffer  buffer1;\n    struct cork_buffer  buffer2;\n    struct cork_buffer  *buffer3;\n\n    cork_buffer_init(&buffer1);\n\n    /*\n     * Let's try setting some data, then clearing it, before we do our\n     * appends.\n     */\n\n    fail_if_error(cork_buffer_set(&buffer1, SRC2, SRC2_LEN));\n    cork_buffer_clear(&buffer1);\n\n    /*\n     * Okay now do the appends.\n     */\n\n    fail_if_error(cork_buffer_append(&buffer1, SRC1, SRC1_LEN));\n    fail_if_error(cork_buffer_append(&buffer1, SRC2, SRC2_LEN));\n    fail_if_error(cork_buffer_append_string(&buffer1, SRC3));\n    fail_if_error(cork_buffer_append_string(&buffer1, SRC4));\n\n    cork_buffer_init(&buffer2);\n    fail_if_error(cork_buffer_set_string(&buffer2, EXPECTED));\n    check_buffers(&buffer1, &buffer2);\n\n    fail_if_error(buffer3 = cork_buffer_new());\n    fail_if_error(cork_buffer_set(buffer3, SRC1, SRC1_LEN));\n    fail_if_error(cork_buffer_append_printf\n                  (buffer3, \"%s%s%s\", SRC2, SRC3, SRC4));\n    check_buffers(&buffer1, buffer3);\n\n    fail_unless(cork_buffer_equal(&buffer1, buffer3),\n                \"Buffers should be equal: got %zu:%s, expected %zu:%s\",\n                buffer1.size, buffer1.buf, buffer3->size, buffer3->buf);\n\n    cork_buffer_done(&buffer1);\n    cork_buffer_done(&buffer2);\n    cork_buffer_free(buffer3);\n}\nEND_TEST\n\n\nSTART_TEST(test_buffer_slicing)\n{\n    static char  SRC[] =\n        \"Here is some text.\";\n\n    struct cork_buffer  *buffer;\n    struct cork_managed_buffer  *managed;\n    struct cork_slice  slice1;\n    struct cork_slice  slice2;\n\n    fail_if_error(buffer = cork_buffer_new());\n    fail_if_error(cork_buffer_set_string(buffer, SRC));\n\n    fail_if_error(managed = cork_buffer_to_managed_buffer\n                  (buffer));\n    cork_managed_buffer_unref(managed);\n\n    fail_if_error(buffer = cork_buffer_new());\n    fail_if_error(cork_buffer_set_string(buffer, SRC));\n\n    fail_if_error(cork_buffer_to_slice(buffer, &slice1));\n\n    fail_if_error(cork_slice_copy_offset(&slice2, &slice1, 2));\n    cork_slice_finish(&slice2);\n\n    fail_if_error(cork_slice_copy_offset(&slice2, &slice1, buffer->size));\n    cork_slice_finish(&slice2);\n\n    fail_if_error(cork_slice_copy_fast(&slice2, &slice1, 2, 2));\n    cork_slice_finish(&slice2);\n\n    fail_if_error(cork_slice_copy_offset_fast(&slice2, &slice1, 2));\n    cork_slice_finish(&slice2);\n\n    fail_if_error(cork_slice_copy_offset(&slice2, &slice1, 0));\n    fail_if_error(cork_slice_slice_offset_fast(&slice2, 2));\n    fail_if_error(cork_slice_slice_fast(&slice2, 0, 2));\n    fail_if_error(cork_slice_slice(&slice1, 2, 2));\n    fail_unless(cork_slice_equal(&slice1, &slice2), \"Slices should be equal\");\n    cork_slice_finish(&slice2);\n\n    cork_slice_finish(&slice1);\n}\nEND_TEST\n\n\nSTART_TEST(test_buffer_stream)\n{\n    static char  SRC1[] = \"abcd\";\n    size_t  SRC1_LEN = 4;\n    static char  SRC2[] = \"efg\";\n    size_t  SRC2_LEN = 3;\n\n    static char  EXPECTED[] = \"000abcdefg\";\n    static size_t  EXPECTED_SIZE = 10;\n\n    struct cork_buffer  buffer1;\n    struct cork_buffer  buffer2;\n    struct cork_stream_consumer  *consumer;\n\n    cork_buffer_init(&buffer1);\n    cork_buffer_append_string(&buffer1, \"000\");\n    fail_if_error(consumer =\n                  cork_buffer_to_stream_consumer(&buffer1));\n\n    /* chunk #1 */\n    fail_if_error(cork_stream_consumer_data(consumer, SRC1, SRC1_LEN, true));\n\n    /* chunk #2 */\n    fail_if_error(cork_stream_consumer_data(consumer, SRC2, SRC2_LEN, false));\n\n    /* eof */\n    fail_if_error(cork_stream_consumer_eof(consumer));\n\n    /* check the result */\n    cork_buffer_init(&buffer2);\n    fail_if_error(cork_buffer_set(&buffer2, EXPECTED, EXPECTED_SIZE));\n    check_buffers(&buffer1, &buffer2);\n\n    cork_stream_consumer_free(consumer);\n    cork_buffer_done(&buffer1);\n    cork_buffer_done(&buffer2);\n}\nEND_TEST\n\n\nstatic void\ncheck_c_string_(const char *content, size_t length,\n                const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    cork_buffer_append_c_string(&buf, content, length);\n    check_buffer(&buf, expected);\n    cork_buffer_done(&buf);\n}\n\n#define check_c_string(c)  (check_c_string_(c, sizeof(c) - 1, #c))\n#define check_c_string_ex(c, e)  (check_c_string_(c, sizeof(c) - 1, e))\n\nSTART_TEST(test_buffer_c_string)\n{\n    check_c_string(\"\");\n    check_c_string(\"hello world\");\n    check_c_string(\"\\x00\");\n    check_c_string(\"\\f\\n\\r\\t\\v\");\n    check_c_string_ex(\"\\x0d\\x0a\", \"\\\"\\\\n\\\\r\\\"\");\n}\nEND_TEST\n\n\nstatic void\ncheck_pretty_print_(size_t indent, const char *content, size_t length,\n                    const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    cork_buffer_append_binary(&buf, indent, content, length);\n    check_buffer(&buf, expected);\n    cork_buffer_done(&buf);\n}\n\n#define check_pretty_print(i, c, e) \\\n    (check_pretty_print_((i), (c), sizeof((c)) - 1, (e)))\n\nSTART_TEST(test_buffer_pretty_print)\n{\n    check_pretty_print(0, \"\", \"\");\n    check_pretty_print(0, \"hello world\", \"hello world\");\n    check_pretty_print\n        (0, \"hello\\nworld\",\n         \"(multiline)\\n\"\n         \"hello\\n\"\n         \"world\");\n    check_pretty_print\n        (0, \"hello\\n\\x00world\\r\\x80hello again\",\n         \"(hex)\\n\"\n         \"68 65 6c 6c 6f 0a 00 77 6f 72 6c 64 0d 80 68 65  |hello..world..he|\\n\"\n         \"6c 6c 6f 20 61 67 61 69 6e                       |llo again|\");\n\n    check_pretty_print(2, \"\", \"\");\n    check_pretty_print(2, \"hello world\", \"hello world\");\n    check_pretty_print\n        (2, \"hello\\nworld\",\n         \"(multiline)\\n\"\n         \"  hello\\n\"\n         \"  world\");\n    check_pretty_print\n        (2, \"hello\\n\\x00world\\r\\x80hello again\",\n         \"(hex)\\n\"\n         \"  \"\n         \"68 65 6c 6c 6f 0a 00 77 6f 72 6c 64 0d 80 68 65  |hello..world..he|\\n\"\n         \"  \"\n         \"6c 6c 6f 20 61 67 61 69 6e                       |llo again|\");\n\n    check_pretty_print(4, \"\", \"\");\n    check_pretty_print(4, \"hello world\", \"hello world\");\n    check_pretty_print\n        (4, \"hello\\nworld\",\n         \"(multiline)\\n\"\n         \"    hello\\n\"\n         \"    world\");\n    check_pretty_print\n        (4, \"hello\\n\\x00world\\r\\x80hello again\",\n         \"(hex)\\n\"\n         \"    \"\n         \"68 65 6c 6c 6f 0a 00 77 6f 72 6c 64 0d 80 68 65  |hello..world..he|\\n\"\n         \"    \"\n         \"6c 6c 6f 20 61 67 61 69 6e                       |llo again|\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"buffer\");\n\n    TCase  *tc_buffer = tcase_create(\"buffer\");\n    tcase_add_test(tc_buffer, test_buffer);\n    tcase_add_test(tc_buffer, test_buffer_append);\n    tcase_add_test(tc_buffer, test_buffer_slicing);\n    tcase_add_test(tc_buffer, test_buffer_stream);\n    tcase_add_test(tc_buffer, test_buffer_c_string);\n    tcase_add_test(tc_buffer, test_buffer_pretty_print);\n    suite_add_tcase(s, tc_buffer);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n\n/*-----------------------------------------------------------------------\n * Inline declarations\n */\n\nvoid\ncork_buffer_copy(struct cork_buffer* dest, const struct cork_buffer* src);\n\nvoid\ncork_buffer_append_copy(struct cork_buffer* dest,\n                        const struct cork_buffer* src);\n"
  },
  {
    "path": "tests/test-core.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/config.h\"\n#include \"libcork/core/byte-order.h\"\n#include \"libcork/core/error.h\"\n#include \"libcork/core/hash.h\"\n#include \"libcork/core/id.h\"\n#include \"libcork/core/net-addresses.h\"\n#include \"libcork/core/timestamp.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/core/u128.h\"\n#include \"libcork/os/subprocess.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Core types\n */\n\nSTART_TEST(test_bool)\n{\n    bool  value;\n\n    value = true;\n    fail_unless(value, \"Unexpected true value\");\n\n    value = false;\n    fail_if(value, \"Unexpected false value\");\n}\nEND_TEST\n\nSTART_TEST(test_int_types)\n{\n    /*\n     * Make sure we have all of the C99 fixed-size integer types\n     * available.\n     */\n\n#define TEST_INT_TYPE(type) \\\n    { \\\n        type  i = 0; \\\n        fail_unless(i == 0, \"Unexpected value for \" #type); \\\n    }\n\n    TEST_INT_TYPE(int8_t);\n    TEST_INT_TYPE(int16_t);\n    TEST_INT_TYPE(int32_t);\n    TEST_INT_TYPE(int64_t);\n    TEST_INT_TYPE(uint8_t);\n    TEST_INT_TYPE(uint16_t);\n    TEST_INT_TYPE(uint32_t);\n    TEST_INT_TYPE(uint64_t);\n    TEST_INT_TYPE(size_t);\n    TEST_INT_TYPE(ptrdiff_t);\n    TEST_INT_TYPE(intptr_t);\n    TEST_INT_TYPE(uintptr_t);\n\n#undef TEST_INT_TYPE\n}\nEND_TEST\n\n\nSTART_TEST(test_int_sizeof)\n{\n    /*\n     * Test that our CORK_SIZEOF_FOO preprocessor macros match the\n     * results of the builtin sizeof operator.\n     */\n\n#define TEST_SIZEOF(TYPE, type) \\\n    { \\\n        fail_unless(CORK_SIZEOF_##TYPE == sizeof(type), \\\n                    \"Incorrect size for \" #type \": got %zu, expected %zu\", \\\n                    (size_t) CORK_SIZEOF_##TYPE, \\\n                    (size_t) sizeof(type)); \\\n    }\n\n    TEST_SIZEOF(SHORT, short)\n    TEST_SIZEOF(SHORT, unsigned short)\n    TEST_SIZEOF(INT, int)\n    TEST_SIZEOF(INT, unsigned int)\n    TEST_SIZEOF(LONG, long)\n    TEST_SIZEOF(LONG, unsigned long)\n    TEST_SIZEOF(POINTER, void *)\n    TEST_SIZEOF(POINTER, int *)\n    TEST_SIZEOF(POINTER, void (*)(void))\n\n#undef TEST_SIZEOF\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Strings\n */\n\nstatic void\ntest_strndup(const char *string, size_t size)\n{\n    const char  *copy;\n\n    copy = cork_strndup(string, size);\n    if (memcmp(string, copy, size) != 0) {\n        fail(\"cork_strndup failed\");\n    }\n    if (cork_strlen(copy) != size) {\n        fail(\"cork_strlen failed\");\n    }\n    cork_strfree(copy);\n\n    copy = cork_xstrndup(string, size);\n    fail_if(copy == NULL, \"cork_xstrndup couldn't allocate copy\");\n    if (memcmp(string, copy, size) != 0) {\n        fail(\"cork_xstrndup failed\");\n    }\n    if (cork_strlen(copy) != size) {\n        fail(\"cork_strlen failed\");\n    }\n    cork_strfree(copy);\n}\n\nSTART_TEST(test_string)\n{\n    DESCRIBE_TEST;\n    test_strndup(\"\", 0);\n    test_strndup(\"abc\", 3);\n    test_strndup(\"abc\\x00xyz\", 7);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Endianness\n */\n\n#define uint8_t_eq(a, b) ((a) == (b))\n#define uint16_t_eq(a, b) ((a) == (b))\n#define uint32_t_eq(a, b) ((a) == (b))\n#define uint64_t_eq(a, b) ((a) == (b))\n\nSTART_TEST(test_endianness)\n{\n#define TEST_ENDIAN(TYPE, type, sz, expected, ...) \\\n    { \\\n        union { uint8_t octets[sz]; type val; }  u = \\\n            { { __VA_ARGS__ } }; \\\n        \\\n        type  from_big = CORK_##TYPE##_BIG_TO_HOST(u.val); \\\n        fail_unless(type##_eq(from_big, expected), \\\n                    \"Unexpected big-to-host \" #type \" value\"); \\\n        \\\n        type  from_big_in_place = u.val; \\\n        CORK_##TYPE##_BIG_TO_HOST_IN_PLACE(from_big_in_place); \\\n        fail_unless(type##_eq(from_big_in_place, expected), \\\n                    \"Unexpected in-place big-to-host \" #type \" value\"); \\\n        \\\n        type  to_big = CORK_##TYPE##_HOST_TO_BIG(expected); \\\n        fail_unless(type##_eq(to_big, u.val), \\\n                    \"Unexpected host-to-big \" #type \" value\"); \\\n        \\\n        type  to_big_in_place = expected; \\\n        CORK_##TYPE##_HOST_TO_BIG_IN_PLACE(to_big_in_place); \\\n        fail_unless(type##_eq(to_big_in_place, u.val), \\\n                    \"Unexpected in-place host-to-big \" #type \" value\"); \\\n        \\\n        int  i; \\\n        for (i = 0; i < sz/2; i++) { \\\n            uint8_t  tmp = u.octets[i]; \\\n            u.octets[i] = u.octets[sz-i-1]; \\\n            u.octets[sz-i-1] = tmp; \\\n        } \\\n        \\\n        type  from_little = CORK_##TYPE##_LITTLE_TO_HOST(u.val); \\\n        fail_unless(type##_eq(from_little, expected), \\\n                    \"Unexpected little-to-host \" #type \" value\"); \\\n        \\\n        type  from_little_in_place = u.val; \\\n        CORK_##TYPE##_LITTLE_TO_HOST_IN_PLACE(from_little_in_place); \\\n        fail_unless(type##_eq(from_little_in_place, expected), \\\n                    \"Unexpected in-place little-to-host \" #type \" value\"); \\\n        \\\n        type  to_little = CORK_##TYPE##_HOST_TO_LITTLE(expected); \\\n        fail_unless(type##_eq(to_little, u.val), \\\n                    \"Unexpected host-to-little \" #type \" value\"); \\\n        \\\n        type  to_little_in_place = expected; \\\n        CORK_##TYPE##_HOST_TO_LITTLE_IN_PLACE(to_little_in_place); \\\n        fail_unless(type##_eq(to_little_in_place, u.val), \\\n                    \"Unexpected in-place host-to-little \" #type \" value\"); \\\n    }\n\n    TEST_ENDIAN(UINT16, uint16_t, 2, 0x0102, 1, 2);\n    TEST_ENDIAN(UINT32, uint32_t, 4, 0x01020304, 1, 2, 3, 4);\n    TEST_ENDIAN(UINT64, uint64_t, 8, UINT64_C(0x0102030405060708),\n                1, 2, 3, 4, 5, 6, 7, 8);\n    TEST_ENDIAN(\n        UINT128, cork_u128, 16,\n        cork_u128_from_32(0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f00), 1, 2,\n        3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0);\n\n#undef TEST_ENDIAN\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Built-in errors\n */\n\nSTART_TEST(test_error_prefix)\n{\n    DESCRIBE_TEST;\n    cork_error_clear();\n    cork_error_set_printf\n        (CORK_UNKNOWN_ERROR, \"%u errors occurred\", (unsigned int) 17);\n    fail_unless_streq(\"Error messages\",\n                      \"17 errors occurred\",\n                      cork_error_message());\n    cork_error_prefix(\"The %s is aborting because \", \"program\");\n    fail_unless_streq(\"Error messages\",\n                      \"The program is aborting because 17 errors occurred\",\n                      cork_error_message());\n    cork_error_clear();\n}\nEND_TEST\n\nSTART_TEST(test_system_error)\n{\n    DESCRIBE_TEST;\n    /* Artificially flag a system error and make sure we can detect it */\n    errno = ENOMEM;\n    cork_error_clear();\n    cork_system_error_set();\n    fail_unless(cork_error_code() == ENOMEM,\n                \"Expected a system error\");\n    printf(\"Got error: %s\\n\", cork_error_message());\n    cork_error_clear();\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Hash values\n */\n\n#define test_hash_func(func, expected, ...) \\\n    fail_unless(func(0, __VA_ARGS__) == expected, \\\n                \"Unexpected hash value 0x%08\" PRIx32 \\\n                \" (expected 0x%08\" PRIx32 \")\", \\\n                func(0, __VA_ARGS__), expected);\n\n#if CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN\n#if CORK_SIZEOF_POINTER == 8\n#define test_hash_buf(buf, len, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_buffer, little64, buf, len)\n#define test_hash_var(var, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_variable, little64, var)\n#else\n#define test_hash_buf(buf, len, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_buffer, little32, buf, len)\n#define test_hash_var(var, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_variable, little32, var)\n#endif\n#else\n#if CORK_SIZEOF_POINTER == 8\n#define test_hash_buf(buf, len, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_buffer, big64, buf, len)\n#define test_hash_var(var, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_variable, big64, var)\n#else\n#define test_hash_buf(buf, len, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_buffer, big32, buf, len)\n#define test_hash_var(var, little32, big32, little64, big64) \\\n    test_hash_func(cork_hash_variable, big32, var)\n#endif\n#endif\n\n\n#define test_stable_hash_buf(buf, len, expected) \\\n    test_hash_func(cork_stable_hash_buffer, expected, buf, len)\n#define test_stable_hash_var(var, expected) \\\n    test_hash_func(cork_stable_hash_variable, expected, var)\n\n\n#define test_big_hash_func(buf, len, e1, e2) \\\n    do { \\\n        cork_big_hash  seed = CORK_BIG_HASH_INIT(); \\\n        cork_big_hash  expected = {cork_u128_from_64(e1, e2)}; \\\n        cork_big_hash  actual = cork_big_hash_buffer(seed, buf, len); \\\n        fail_unless(cork_big_hash_equal(actual, expected), \\\n                    \"\\nUnexpected hash value 0x%016\" PRIx64 \".%016\" PRIx64 \\\n                    \"\\n            (expected 0x%016\" PRIx64 \".%016\" PRIx64 \")\", \\\n                    cork_u128_be64(actual.u128, 0), \\\n                    cork_u128_be64(actual.u128, 1), \\\n                    cork_u128_be64(expected.u128, 0), \\\n                    cork_u128_be64(expected.u128, 1)); \\\n    } while (0)\n\n#if CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN\n#if CORK_SIZEOF_POINTER == 8\n#define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \\\n    test_big_hash_func(buf, len, l64a, l64b)\n#else\n#define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \\\n    test_big_hash_func(buf, len, l32a, l32b)\n#endif\n#else\n#if CORK_SIZEOF_POINTER == 8\n#define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \\\n    test_big_hash_func(buf, len, b64a, b64b)\n#else\n#define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \\\n    test_big_hash_func(buf, len, b32a, b32b)\n#endif\n#endif\n\n\nSTART_TEST(test_hash)\n{\n    DESCRIBE_TEST;\n\n    static const char  BUF[] = \"test\";\n    static size_t  LEN = sizeof(BUF);\n    static const char  LONG_BUF[] =\n        \"this is a much longer test string in the hopes that we have to \"\n        \"go through a few iterations of the hashing loop in order to \"\n        \"calculate the value of the hash which we are trying to compute.\";\n    static size_t  LONG_LEN = sizeof(LONG_BUF);\n    uint32_t  val32 = 1234;\n    uint64_t  val64 = 1234;\n    uint32_t  stable_val32 = CORK_UINT32_HOST_TO_LITTLE(1234);\n    uint64_t  stable_val64 = CORK_UINT64_HOST_TO_LITTLE(1234);\n\n    /* without the NUL terminator */\n    test_stable_hash_buf(BUF, LEN-1, 0xba6bd213);\n    test_hash_buf(BUF, LEN-1,\n      /* little 32 */ 0xba6bd213,\n      /*    big 32 */ 0x29d175e5,\n      /* little 64 */ 0xac7d28cc,\n      /*    big 64 */ 0xac7d28cc);\n    test_big_hash_buf(BUF, LEN-1,\n      /* little 32 */ 0x6f02ef30550c7d68LL, 0x550c7d68550c7d68LL,\n      /*    big 32 */ 0x6f02ef30550c7d68LL, 0x550c7d68550c7d68LL,\n      /* little 64 */ 0xac7d28cc74bde19dLL, 0x9a128231f9bd4d82LL,\n      /*    big 64 */ 0xac7d28cc74bde19dLL, 0x9a128231f9bd4d82LL);\n\n    /* with the NUL terminator */\n    test_stable_hash_buf(BUF, LEN, 0x586fce33);\n    test_hash_buf(BUF, LEN,\n      /* little 32 */ 0x586fce33,\n      /*    big 32 */ 0xe31d1ce0,\n      /* little 64 */ 0xc3812fdf,\n      /*    big 64 */ 0xc3812fdf);\n    test_big_hash_buf(BUF, LEN,\n      /* little 32 */ 0x98c2b52b29ab177cLL, 0x29ab177c29ab177cLL,\n      /*    big 32 */ 0x98c2b52b29ab177cLL, 0x29ab177c29ab177cLL,\n      /* little 64 */ 0xc3812fdf4d18f852LL, 0xc81a9057aa737aecLL,\n      /*    big 64 */ 0xc3812fdf4d18f852LL, 0xc81a9057aa737aecLL);\n\n    /* without the NUL terminator */\n    test_stable_hash_buf(LONG_BUF, LONG_LEN-1, 0x5caacc30);\n    test_hash_buf(LONG_BUF, LONG_LEN-1,\n      /* little 32 */ 0x5caacc30,\n      /*    big 32 */ 0x88f94165,\n      /* little 64 */ 0xcbdc2092,\n      /*    big 64 */ 0x5935f90a);\n    test_big_hash_buf(LONG_BUF, LONG_LEN-1,\n      /* little 32 */ 0x4240d5134fb7793cLL, 0xee7e281c799f335aLL,\n      /*    big 32 */ 0xab564a5e029c92a4LL, 0x0bd80c741093400fLL,\n      /* little 64 */ 0xcbdc20928fa72e9cLL, 0x48de52d2c680420eLL,\n      /*    big 64 */ 0x5935f90a03578c96LL, 0x163e514fff9c30a8LL);\n\n    /* with the NUL terminator */\n    test_stable_hash_buf(LONG_BUF, LONG_LEN, 0x5e37d33d);\n    test_hash_buf(LONG_BUF, LONG_LEN,\n      /* little 32 */ 0x5e37d33d,\n      /*    big 32 */ 0x4977421a,\n      /* little 64 */ 0xe89ec005,\n      /*    big 64 */ 0xf00a12ab);\n    test_big_hash_buf(LONG_BUF, LONG_LEN,\n      /* little 32 */ 0x63bcdcd0c2615146LL, 0x8e7fd7aaece3cab6LL,\n      /*    big 32 */ 0x250b47cda3fc07fdLL, 0x840c4bb606aafbd0LL,\n      /* little 64 */ 0xe89ec0054becb434LL, 0x826391b83f0b4d3eLL,\n      /*    big 64 */ 0xf00a12ab8c919559LL, 0x684ecf4973c66eacLL);\n\n    test_stable_hash_var(stable_val32, 0x6bb65380);\n    test_hash_var(val32,\n      /* little 32 */ 0x6bb65380,\n      /*    big 32 */ 0x6bb65380,\n      /* little 64 */ 0x061fecc8,\n      /*    big 64 */ 0x5b3f7a70);\n\n    test_stable_hash_var(stable_val64, 0x4d5c4063);\n    test_hash_var(val64,\n      /* little 32 */ 0x4d5c4063,\n      /*    big 32 */ 0xbaeee6e9,\n      /* little 64 */ 0xb119ee69,\n      /*    big 64 */ 0x2304b12d);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * IP addresses\n */\n\n#define IPV4_TESTS(good, bad) \\\n    good(\"192.168.1.100\", \"192.168.1.100\"); \\\n    good(\"01.002.0003.00000004\", \"1.2.3.4\"); \\\n    good(\"010.0020.00034.00000089\", \"10.20.34.89\"); \\\n    good(\"0100.000200.00.000\", \"100.200.0.0\"); \\\n    bad(\"\", -1); \\\n    bad(\".\", -1); \\\n    bad(\"192.168.0.\", -1); \\\n    bad(\"192.168.0.1.\", -1); \\\n    bad(\"192..168.0.1\", -1); \\\n    bad(\"192.168.0.1.2\", -1); \\\n    bad(\".168.0.1.2\", -1); \\\n    bad(\"256.0.0.0\", -1); \\\n    bad(\"00256.0.0.0\", -1); \\\n    bad(\"392.0.0.0\", -1); \\\n    bad(\"1920.0.0.0\", -1); \\\n    bad(\"stuv\", -1); \\\n\n#define IPV6_TESTS(good, bad) \\\n    good(\"::\", \"::\"); \\\n    good(\"0:0:0:0:0:0:0:0\", \"::\"); \\\n    good(\"0000:0000:0000:0000:0000:0000:0000:0000\", \"::\"); \\\n    good(\"fe80::\", \"fe80::\"); \\\n    good(\"fe80:0:0:0:0:0:0:0\", \"fe80::\"); \\\n    good(\"fe80:0000:0000:0000:0000:0000:0000:0000\", \"fe80::\"); \\\n    good(\"::1\", \"::1\"); \\\n    good(\"0:0:0:0:0:0:0:1\", \"::1\"); \\\n    good(\"0000:0000:0000:0000:0000:0000:0000:0001\", \"::1\"); \\\n    good(\"fe80::1\", \"fe80::1\"); \\\n    good(\"fe80:0:0:0:0:0:0:1\", \"fe80::1\"); \\\n    good(\"fe80:0000:0000:0000:0000:0000:0000:0001\", \"fe80::1\"); \\\n    good(\"0:1:2:3:4:5:6:7\", \"0:1:2:3:4:5:6:7\"); \\\n    good(\"1230:4567:89ab:cdef:1230:4567:89ab:cdef\", \\\n         \"1230:4567:89ab:cdef:1230:4567:89ab:cdef\"); \\\n    good(\"::ffff:192.168.1.100\", \"::ffff:192.168.1.100\"); \\\n    bad(\"\", -1); \\\n    bad(\":\", -1); \\\n    bad(\"fe80:\", -1); \\\n    bad(\"fe80::1::2\", -1); \\\n    bad(\"1:2:3:4:5:6:7\", -1); \\\n    bad(\"1:2:3:4:5:6:7:8:9\", -1); \\\n    bad(\"::1:\", -1); \\\n    bad(\"fe800::\", -1); \\\n    bad(\"stuv\", -1); \\\n    /* RFC 5952 recommendations */ \\\n    good(\"2001:0db8::0001\", \"2001:db8::1\"); \\\n    good(\"2001:db8:0:0:0:0:2:1\", \"2001:db8::2:1\"); \\\n    good(\"2001:db8:0:1:1:1:1:1\", \"2001:db8:0:1:1:1:1:1\"); \\\n    good(\"2001:0:0:1:0:0:0:1\", \"2001:0:0:1::1\"); \\\n    good(\"2001:db8:0:0:1:0:0:1\", \"2001:db8::1:0:0:1\"); \\\n    good(\"0:1:A:B:C:D:E:F\", \"0:1:a:b:c:d:e:f\"); \\\n\nSTART_TEST(test_ipv4_address)\n{\n    DESCRIBE_TEST;\n\n#define GOOD(str, normalized) \\\n    { \\\n        struct cork_ipv4  addr; \\\n        fail_if_error(cork_ipv4_init(&addr, str)); \\\n        char  actual[CORK_IPV4_STRING_LENGTH]; \\\n        cork_ipv4_to_raw_string(&addr, actual); \\\n        fail_unless(strcmp(actual, normalized) == 0, \\\n                    \"Unexpected string representation: \" \\\n                    \"got \\\"%s\\\", expected \\\"%s\\\"\", \\\n                    actual, normalized); \\\n        \\\n        struct cork_ipv4  addr2; \\\n        cork_ipv4_init(&addr2, normalized); \\\n        fail_unless(cork_ipv4_equal(&addr, &addr2), \\\n                    \"IPv4 instances should be equal\"); \\\n    }\n\n#define BAD(str, unused) \\\n    { \\\n        struct cork_ipv4  addr; \\\n        fail_unless_error \\\n            (cork_ipv4_init(&addr, str), \\\n             \"Shouldn't be able to initialize IPv4 address from \\\"%s\\\"\", \\\n             str); \\\n    }\n\n    IPV4_TESTS(GOOD, BAD);\n    IPV6_TESTS(BAD, BAD);\n\n#undef GOOD\n#undef BAD\n\n    struct cork_ipv4  addr4;\n    unsigned int  ipv4_cidr_good = 30;\n    unsigned int  ipv4_cidr_bad_value = 24;\n    unsigned int  ipv4_cidr_bad_range = 33;\n\n    fprintf(stderr, \"Testing network prefixes\\n\");\n    cork_ipv4_init(&addr4, \"1.2.3.4\");\n    fail_unless(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_good),\n                \"Bad CIDR block for 1.2.3.4 and %u\",\n                ipv4_cidr_good);\n    fail_if(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_bad_value),\n            \"IPv4 CIDR check should fail for %u\",\n            ipv4_cidr_bad_value);\n    fail_if(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_bad_range),\n            \"IPv4 CIDR check should fail for %u\",\n            ipv4_cidr_bad_range);\n}\nEND_TEST\n\n\nSTART_TEST(test_ipv6_address)\n{\n    DESCRIBE_TEST;\n\n#define GOOD(str, normalized) \\\n    { \\\n        struct cork_ipv6  addr; \\\n        fail_if_error(cork_ipv6_init(&addr, str)); \\\n        char  actual[CORK_IPV6_STRING_LENGTH]; \\\n        cork_ipv6_to_raw_string(&addr, actual); \\\n        fail_unless(strcmp(actual, normalized) == 0, \\\n                    \"Unexpected string representation: \" \\\n                    \"got \\\"%s\\\", expected \\\"%s\\\"\", \\\n                    actual, normalized); \\\n        \\\n        struct cork_ipv6  addr2; \\\n        cork_ipv6_init(&addr2, normalized); \\\n        fail_unless(cork_ipv6_equal(&addr, &addr2), \\\n                    \"IPv6 instances should be equal\"); \\\n    }\n\n#define BAD(str, unused) \\\n    { \\\n        struct cork_ipv6  addr; \\\n        fail_unless_error \\\n            (cork_ipv6_init(&addr, str), \\\n             \"Shouldn't be able to initialize IPv6 address from \\\"%s\\\"\", \\\n             str); \\\n    }\n\n    IPV6_TESTS(GOOD, BAD);\n    IPV4_TESTS(BAD, BAD);\n\n#undef GOOD\n#undef BAD\n\n    struct cork_ipv6  addr6;\n    unsigned int  ipv6_cidr_good = 127;\n    unsigned int  ipv6_cidr_bad_value = 64;\n    unsigned int  ipv6_cidr_bad_range = 129;\n\n    fprintf(stderr, \"Testing network prefixes\\n\");\n    cork_ipv6_init(&addr6, \"fe80::200:f8ff:fe21:6000\");\n    fail_unless(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_good),\n                \"Bad CIDR block %u\",\n                ipv6_cidr_good);\n    fail_if(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_bad_value),\n            \"IPv6 CIDR check should fail for %u\",\n            ipv6_cidr_bad_value);\n    fail_if(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_bad_range),\n            \"IPv6 CIDR check should fail for %u\",\n            ipv6_cidr_bad_range);\n}\nEND_TEST\n\n\nSTART_TEST(test_ip_address)\n{\n    DESCRIBE_TEST;\n    struct cork_ip  addr;\n\n#define GOOD(str, normalized) \\\n    { \\\n        struct cork_ip  addr; \\\n        fail_if_error(cork_ip_init(&addr, str)); \\\n        char  actual[CORK_IP_STRING_LENGTH]; \\\n        cork_ip_to_raw_string(&addr, actual); \\\n        fail_unless(strcmp(actual, normalized) == 0, \\\n                    \"Unexpected string representation: \" \\\n                    \"got \\\"%s\\\", expected \\\"%s\\\"\", \\\n                    actual, normalized); \\\n        \\\n        struct cork_ip  addr2; \\\n        cork_ip_init(&addr2, normalized); \\\n        fail_unless(cork_ip_equal(&addr, &addr2), \\\n                    \"IP instances should be equal\"); \\\n    }\n\n#define BAD(str, unused) \\\n    { \\\n        struct cork_ip  addr; \\\n        fail_unless_error \\\n            (cork_ip_init(&addr, str), \\\n             \"Shouldn't be able to initialize IP address from \\\"%s\\\"\", \\\n             str); \\\n    }\n\n    IPV4_TESTS(GOOD, BAD);\n    IPV6_TESTS(GOOD, BAD);\n\n#undef GOOD\n#undef BAD\n\n    struct cork_ipv4  addr4;\n    struct cork_ipv6  addr6;\n\n    fprintf(stderr, \"Testing IP address versions\\n\");\n    cork_ip_init(&addr, \"192.168.1.1\");\n    cork_ipv4_init(&addr4, \"192.168.1.1\");\n    fail_unless(addr.version == 4,\n                \"Unexpected IP address version (expected 4, got %u)\",\n                addr.version);\n    fail_unless(cork_ipv4_equal(&addr.ip.v4, &addr4),\n                \"IP addresses should be equal\");\n\n    cork_ip_init(&addr, \"fe80::1\");\n    cork_ipv6_init(&addr6, \"fe80::1\");\n    fail_unless(addr.version == 6,\n                \"Unexpected IP address version (expected 6, got %u)\",\n                addr.version);\n    fail_unless(cork_ipv6_equal(&addr.ip.v6, &addr6),\n                \"IP addresses should be equal\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Timestamps\n */\n\nstatic void\ntest_timestamp_bad_format(cork_timestamp ts, const char *format)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    fail_unless_error(cork_timestamp_format_utc(ts, format, &buf));\n    cork_buffer_done(&buf);\n}\n\nstatic void\ntest_timestamp_utc_format(cork_timestamp ts, const char *format,\n                          const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    fail_if_error(cork_timestamp_format_utc(ts, format, &buf));\n    fail_unless(strcmp(buf.buf, expected) == 0,\n                \"Unexpected formatted UTC time \"\n                \"(got \\\"%s\\\", expected \\\"%s\\\")\",\n                (char *) buf.buf, expected);\n    cork_buffer_done(&buf);\n}\n\nstatic void\ntest_timestamp_local_format(cork_timestamp ts, const char *format,\n                            const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    fail_if_error(cork_timestamp_format_local(ts, format, &buf));\n    fail_unless(strcmp(buf.buf, expected) == 0,\n                \"Unexpected formatted local time \"\n                \"(got \\\"%s\\\", expected \\\"%s\\\")\",\n                (char *) buf.buf, expected);\n    cork_buffer_done(&buf);\n}\n\nSTART_TEST(test_timestamp)\n{\n    /* All of the local times here are in America/Los_Angeles.  Down at the\n     * bottom of the file we override the TZ environment variable to ensure that\n     * we use a consistent local time zone in the test cases, regardless of the\n     * actual time zone of the current machine. */\n\n    static const uint32_t  TEST_TIME_1 = 700000000;\n    static const char  *FORMATTED_UTC_TIME_1   = \" 1992-03-07 20:26:40 \";\n    static const char  *FORMATTED_LOCAL_TIME_1 = \" 1992-03-07 12:26:40 \";\n\n    static const uint32_t  TEST_TIME_2 = 1200000000;\n    static const char  *FORMATTED_UTC_TIME_2   = \" 2008-01-10 21:20:00 \";\n    static const char  *FORMATTED_LOCAL_TIME_2 = \" 2008-01-10 13:20:00 \";\n\n    static const uint32_t  TEST_TIME_3 = 1305180745;\n    static const char  *FORMATTED_UTC_TIME_3   = \" 2011-05-12 06:12:25 \";\n    static const char  *FORMATTED_LOCAL_TIME_3 = \" 2011-05-11 23:12:25 \";\n\n    cork_timestamp  ts;\n\n    DESCRIBE_TEST;\n\n#define test(unit, expected) \\\n    fail_unless(cork_timestamp_##unit(ts) == expected, \\\n                \"Unexpected \" #unit \" portion of timestamp \" \\\n                \"(got %lu, expected %lu)\", \\\n                (unsigned long) cork_timestamp_##unit(ts), \\\n                (unsigned long) expected);\n\n#define test_format(utc, local) \\\n    test_timestamp_utc_format(ts, \" %Y-%m-%d %H:%M:%S \", utc); \\\n    test_timestamp_local_format(ts, \" %Y-%m-%d %H:%M:%S \", local);\n\n    cork_timestamp_init_sec(&ts, TEST_TIME_1);\n    test(sec, TEST_TIME_1);\n    test(gsec, 0);\n    test(msec, 0);\n    test(usec, 0);\n    test(nsec, 0);\n    test_format(FORMATTED_UTC_TIME_1, FORMATTED_LOCAL_TIME_1);\n\n    cork_timestamp_init_sec(&ts, TEST_TIME_2);\n    test(sec, TEST_TIME_2);\n    test(gsec, 0);\n    test(msec, 0);\n    test(usec, 0);\n    test(nsec, 0);\n    test_format(FORMATTED_UTC_TIME_2, FORMATTED_LOCAL_TIME_2);\n\n    cork_timestamp_init_sec(&ts, TEST_TIME_3);\n    test(sec, TEST_TIME_3);\n    test(gsec, 0);\n    test(msec, 0);\n    test(usec, 0);\n    test(nsec, 0);\n    test_format(FORMATTED_UTC_TIME_3, FORMATTED_LOCAL_TIME_3);\n\n    cork_timestamp_init_gsec(&ts, TEST_TIME_1, 1 << 30);\n    test(sec, TEST_TIME_1);\n    test(gsec, 1 << 30);\n    test(msec, 250);\n    test(usec, 250000);\n    test(nsec, 250000000);\n\n    cork_timestamp_init_msec(&ts, TEST_TIME_1, 500);\n    test(sec, TEST_TIME_1);\n    test(gsec, 1 << 31);\n    test(msec, 500);\n    test(usec, 500000);\n    test(nsec, 500000000);\n\n    cork_timestamp_init_usec(&ts, TEST_TIME_1, 500000);\n    test(sec, TEST_TIME_1);\n    test(gsec, 1 << 31);\n    test(msec, 500);\n    test(usec, 500000);\n    test(nsec, 500000000);\n\n    cork_timestamp_init_nsec(&ts, TEST_TIME_1, 500000000);\n    test(sec, TEST_TIME_1);\n    test(gsec, 1 << 31);\n    test(msec, 500);\n    test(usec, 500000);\n    test(nsec, 500000000);\n}\nEND_TEST\n\nSTART_TEST(test_timestamp_format)\n{\n    cork_timestamp  ts;\n    DESCRIBE_TEST;\n\n    cork_timestamp_init_nsec(&ts, 0, 123456789);\n    test_timestamp_bad_format(ts, \"%f\");\n    test_timestamp_bad_format(ts, \"%0f\");\n    test_timestamp_bad_format(ts, \"%10f\");\n    test_timestamp_utc_format(ts, \"%1f\",   \"1\");\n    test_timestamp_utc_format(ts, \"%2f\",   \"12\");\n    test_timestamp_utc_format(ts, \"%3f\",   \"123\");\n    test_timestamp_utc_format(ts, \"%4f\",   \"1235\");\n    test_timestamp_utc_format(ts, \"%5f\",   \"12346\");\n    test_timestamp_utc_format(ts, \"%6f\",   \"123457\");\n    test_timestamp_utc_format(ts, \"%7f\",   \"1234568\");\n    test_timestamp_utc_format(ts, \"%8f\",   \"12345679\");\n    test_timestamp_utc_format(ts, \"%9f\",   \"123456789\");\n    test_timestamp_utc_format(ts, \"%009f\", \"123456789\");\n\n    cork_timestamp_init_nsec(&ts, 1200000000, 123456789);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Statement expressions\n */\n\nSTART_TEST(test_statement_expr)\n{\n#if CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS\n    int  value = ({ int __x = 0; __x += 2; __x;});\n    fail_unless_equal(\"Statement expression result\", \"%d\", 2, value);\n#endif\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Unique identifiers\n */\n\nSTART_TEST(test_uid)\n{\n    DESCRIBE_TEST;\n    cork_uid_define(test_id_01);\n    cork_uid_define(test_id_02);\n    cork_uid  id1;\n    cork_uid  id2;\n\n    fail_unless_streq(\"UID name\", \"test_id_01\", cork_uid_name(test_id_01));\n    fail_unless_streq(\"UID name\", \"test_id_02\", cork_uid_name(test_id_02));\n\n    id1 = test_id_01;\n    id2 = test_id_02;\n    fail_if(cork_uid_equal(id1, id2), \"Unique IDs aren't unique\");\n\n    id1 = test_id_01;\n    id2 = test_id_01;\n    fail_unless(cork_uid_equal(id1, id2), \"Unique ID isn't equal to itself\");\n\n    id1 = test_id_01;\n    id2 = CORK_UID_NONE;\n    fail_if(cork_uid_equal(id1, id2), \"NULL unique ID isn't unique\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"core\");\n\n    TCase  *tc_types = tcase_create(\"types\");\n    tcase_add_test(tc_types, test_bool);\n    tcase_add_test(tc_types, test_int_types);\n    tcase_add_test(tc_types, test_int_sizeof);\n    suite_add_tcase(s, tc_types);\n\n    TCase  *tc_string = tcase_create(\"string\");\n    tcase_add_test(tc_string, test_string);\n    suite_add_tcase(s, tc_string);\n\n    TCase  *tc_endianness = tcase_create(\"endianness\");\n    tcase_add_test(tc_endianness, test_endianness);\n    suite_add_tcase(s, tc_endianness);\n\n    TCase  *tc_errors = tcase_create(\"errors\");\n    tcase_add_test(tc_errors, test_error_prefix);\n    tcase_add_test(tc_errors, test_system_error);\n    suite_add_tcase(s, tc_errors);\n\n    TCase  *tc_hash = tcase_create(\"hash\");\n    tcase_add_test(tc_hash, test_hash);\n    suite_add_tcase(s, tc_hash);\n\n    TCase  *tc_addresses = tcase_create(\"net-addresses\");\n    tcase_add_test(tc_addresses, test_ipv4_address);\n    tcase_add_test(tc_addresses, test_ipv6_address);\n    tcase_add_test(tc_addresses, test_ip_address);\n    suite_add_tcase(s, tc_addresses);\n\n    TCase  *tc_timestamp = tcase_create(\"timestamp\");\n    tcase_add_test(tc_timestamp, test_timestamp);\n    tcase_add_test(tc_timestamp, test_timestamp_format);\n    suite_add_tcase(s, tc_timestamp);\n\n    TCase  *tc_statement_expr = tcase_create(\"statement_expr\");\n    tcase_add_test(tc_statement_expr, test_statement_expr);\n    suite_add_tcase(s, tc_statement_expr);\n\n    TCase  *tc_uid = tcase_create(\"uid\");\n    tcase_add_test(tc_uid, test_uid);\n    suite_add_tcase(s, tc_uid);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n\n    /* Before anything starts, override the TZ environment variable so that we\n     * get consistent test results. */\n    cork_env_add(NULL, \"TZ\", \"America/Los_Angeles\");\n\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-dllist.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/ds/dllist.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Doubly-linked lists\n */\n\nstruct int64_item {\n    int64_t  value;\n    struct cork_dllist_item  element;\n};\n\nstatic int\nint64_sum(void *user_data, struct cork_dllist_item *element)\n{\n    int64_t  *sum = user_data;\n    struct int64_item  *item =\n        cork_container_of(element, struct int64_item, element);\n    *sum += item->value;\n    return 0;\n}\n\nstatic void\ncheck_int64_list(struct cork_dllist *list, const char *expected)\n{\n    bool  first = true;\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n    struct int64_item  *item;\n    cork_buffer_append_literal(&buf, \"\");\n    cork_dllist_foreach(list, curr, next, struct int64_item, item, element) {\n        if (first) {\n            first = false;\n        } else {\n            cork_buffer_append_literal(&buf, \",\");\n        }\n        cork_buffer_append_printf(&buf, \"%\" PRId64, item->value);\n    }\n    fail_unless_streq(\"List contents\", expected, buf.buf);\n    cork_buffer_done(&buf);\n}\n\nSTART_TEST(test_dllist)\n{\n    struct cork_dllist  list;\n    struct cork_dllist_item  *curr;\n    struct cork_dllist_item  *next;\n    struct int64_item  *item;\n    struct int64_item  item1;\n    struct int64_item  item2;\n    struct int64_item  item3;\n    int64_t  sum;\n\n    cork_dllist_init(&list);\n    fail_unless(cork_dllist_size(&list) == 0,\n                \"Unexpected size of list: got %zu, expected 0\",\n                cork_dllist_size(&list));\n    fail_unless(cork_dllist_is_empty(&list),\n                \"Expected empty list\");\n    check_int64_list(&list, \"\");\n\n    item1.value = 1;\n    cork_dllist_add(&list, &item1.element);\n    fail_unless(cork_dllist_size(&list) == 1,\n                \"Unexpected size of list: got %zu, expected 1\",\n                cork_dllist_size(&list));\n    check_int64_list(&list, \"1\");\n\n    item2.value = 2;\n    cork_dllist_add(&list, &item2.element);\n    fail_unless(cork_dllist_size(&list) == 2,\n                \"Unexpected size of list: got %zu, expected 2\",\n                cork_dllist_size(&list));\n    check_int64_list(&list, \"1,2\");\n\n    item3.value = 3;\n    cork_dllist_add(&list, &item3.element);\n    fail_unless(cork_dllist_size(&list) == 3,\n                \"Unexpected size of list: got %zu, expected 3\",\n                cork_dllist_size(&list));\n    check_int64_list(&list, \"1,2,3\");\n\n    sum = 0;\n    fail_if(cork_dllist_visit(&list, &sum, int64_sum));\n    fail_unless(sum == 6,\n                \"Unexpected sum, got %ld, expected 6\",\n                (long) sum);\n\n    sum = 0;\n    cork_dllist_foreach(&list, curr, next, struct int64_item, item, element) {\n        sum += item->value;\n    }\n    fail_unless(sum == 6,\n                \"Unexpected sum, got %ld, expected 6\",\n                (long) sum);\n\n    cork_dllist_remove(&item2.element);\n    fail_unless(cork_dllist_size(&list) == 2,\n                \"Unexpected size of list: got %zu, expected 2\",\n                cork_dllist_size(&list));\n}\nEND_TEST\n\nSTART_TEST(test_dllist_append)\n{\n    struct cork_dllist  list1 = CORK_DLLIST_INIT(list1);\n    struct cork_dllist  list2 = CORK_DLLIST_INIT(list2);\n    struct int64_item  item1;\n    struct int64_item  item2;\n    struct int64_item  item3;\n    struct int64_item  item4;\n    struct int64_item  item5;\n    struct int64_item  item6;\n    struct int64_item  item7;\n\n    item1.value = 1;\n    cork_dllist_add_to_head(&list1, &item1.element);\n    check_int64_list(&list1, \"1\");\n\n    item2.value = 2;\n    cork_dllist_add_to_head(&list1, &item2.element);\n    check_int64_list(&list1, \"2,1\");\n\n    item3.value = 3;\n    cork_dllist_add_to_tail(&list1, &item3.element);\n    check_int64_list(&list1, \"2,1,3\");\n\n    item4.value = 4;\n    cork_dllist_add_to_tail(&list2, &item4.element);\n    item5.value = 5;\n    cork_dllist_add_to_tail(&list2, &item5.element);\n    cork_dllist_add_list_to_head(&list1, &list2);\n    check_int64_list(&list1, \"4,5,2,1,3\");\n\n    item6.value = 6;\n    cork_dllist_add_to_tail(&list2, &item6.element);\n    item7.value = 7;\n    cork_dllist_add_to_tail(&list2, &item7.element);\n    cork_dllist_add_list_to_tail(&list1, &list2);\n    check_int64_list(&list1, \"4,5,2,1,3,6,7\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"dllist\");\n\n    TCase  *tc_ds = tcase_create(\"dllist\");\n    tcase_add_test(tc_ds, test_dllist);\n    tcase_add_test(tc_ds, test_dllist_append);\n    suite_add_tcase(s, tc_ds);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-files.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2013, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <assert.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/os/files.h\"\n\n#include \"helpers.h\"\n\n\nstatic const char  *program_path;\n\n\n/*-----------------------------------------------------------------------\n * Paths\n */\n\nvoid\nverify_path_content(struct cork_path *path, const char *expected)\n{\n    fail_if(cork_path_get(path) == NULL, \"Path should not have NULL content\");\n    fail_unless_streq(\"Paths\", expected, cork_path_get(path));\n}\n\nvoid\ntest_path(const char *p, const char *expected)\n{\n    struct cork_path  *path;\n    struct cork_path  *cloned;\n    struct cork_path  *set;\n\n    fprintf(stderr, \"path(\\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p == NULL)? \"\": p,\n            expected);\n\n    path = cork_path_new(p);\n    verify_path_content(path, expected);\n\n    cloned = cork_path_clone(path);\n    verify_path_content(cloned, expected);\n    cork_path_free(cloned);\n    cork_path_free(path);\n\n    set = cork_path_new(NULL);\n    cork_path_set(set, p);\n    verify_path_content(set, expected);\n    cork_path_free(set);\n}\n\nSTART_TEST(test_path_01)\n{\n    DESCRIBE_TEST;\n    test_path(NULL, \"\");\n    test_path(\"a\", \"a\");\n    test_path(\"a/b\", \"a/b\");\n}\nEND_TEST\n\n\nvoid\ntest_join(const char *p1, const char *p2, const char *expected)\n{\n    struct cork_path  *path1;\n    struct cork_path  *path2;\n    struct cork_path  *actual;\n\n    fprintf(stderr, \"join(\\\"%s\\\", \\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p1 == NULL)? \"\": p1,\n            (p2 == NULL)? \"\": p2,\n            expected);\n\n    /* Try cork_path_join */\n    path1 = cork_path_new(p1);\n    actual = cork_path_join(path1, p2);\n    verify_path_content(actual, expected);\n    cork_path_free(path1);\n    cork_path_free(actual);\n\n    /* Try cork_path_join_path */\n    path1 = cork_path_new(p1);\n    path2 = cork_path_new(p2);\n    actual = cork_path_join_path(path1, path2);\n    verify_path_content(actual, expected);\n    cork_path_free(path1);\n    cork_path_free(path2);\n    cork_path_free(actual);\n\n    /* Try cork_path_append */\n    actual = cork_path_new(p1);\n    cork_path_append(actual, p2);\n    verify_path_content(actual, expected);\n    cork_path_free(actual);\n\n    /* Try cork_path_append_path */\n    actual = cork_path_new(p1);\n    path2 = cork_path_new(p2);\n    cork_path_append_path(actual, path2);\n    verify_path_content(actual, expected);\n    cork_path_free(path2);\n    cork_path_free(actual);\n}\n\nSTART_TEST(test_path_join_01)\n{\n    DESCRIBE_TEST;\n    test_join(\"a\", \"b\",    \"a/b\");\n    test_join(\"a/\", \"b\",   \"a/b\");\n    test_join(\"\", \"a/b\",   \"a/b\");\n    test_join(\"a/b\", \"\",   \"a/b\");\n    test_join(NULL, \"a/b\", \"a/b\");\n    test_join(\"a/b\", NULL, \"a/b\");\n}\nEND_TEST\n\nSTART_TEST(test_path_join_02)\n{\n    DESCRIBE_TEST;\n    test_join(\"\", \"/b\",   \"/b\");\n    test_join(NULL, \"/b\", \"/b\");\n    test_join(\"a\", \"/b\",  \"/b\");\n    test_join(\"a/\", \"/b\", \"/b\");\n}\nEND_TEST\n\n\nvoid\ntest_basename(const char *p, const char *expected)\n{\n    struct cork_path  *path;\n    struct cork_path  *actual;\n\n    fprintf(stderr, \"basename(\\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p == NULL)? \"\": p,\n            expected);\n\n    /* Try cork_path_basename */\n    path = cork_path_new(p);\n    actual = cork_path_basename(path);\n    verify_path_content(actual, expected);\n    cork_path_free(path);\n    cork_path_free(actual);\n\n    /* Try cork_path_set_basename */\n    actual = cork_path_new(p);\n    cork_path_set_basename(actual);\n    verify_path_content(actual, expected);\n    cork_path_free(actual);\n}\n\nSTART_TEST(test_path_basename_01)\n{\n    DESCRIBE_TEST;\n    test_basename(\"\", \"\");\n    test_basename(NULL, \"\");\n    test_basename(\"a\", \"a\");\n    test_basename(\"a/\", \"\");\n    test_basename(\"a/b\", \"b\");\n    test_basename(\"a/b/\", \"\");\n    test_basename(\"a/b/c\", \"c\");\n    test_basename(\"/a\", \"a\");\n    test_basename(\"/a/\", \"\");\n    test_basename(\"/a/b\", \"b\");\n    test_basename(\"/a/b/\", \"\");\n    test_basename(\"/a/b/c\", \"c\");\n}\nEND_TEST\n\n\nvoid\ntest_dirname(const char *p, const char *expected)\n{\n    struct cork_path  *path;\n    struct cork_path  *actual;\n\n    fprintf(stderr, \"dirname(\\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p == NULL)? \"\": p,\n            expected);\n\n    /* Try cork_path_dirname */\n    path = cork_path_new(p);\n    actual = cork_path_dirname(path);\n    verify_path_content(actual, expected);\n    cork_path_free(path);\n    cork_path_free(actual);\n\n    /* Try cork_path_set_dirname */\n    actual = cork_path_new(p);\n    cork_path_set_dirname(actual);\n    verify_path_content(actual, expected);\n    cork_path_free(actual);\n}\n\nSTART_TEST(test_path_dirname_01)\n{\n    DESCRIBE_TEST;\n    test_dirname(NULL, \"\");\n    test_dirname(\"\", \"\");\n    test_dirname(\"a\", \"\");\n    test_dirname(\"a/\", \"a\");\n    test_dirname(\"a/b\", \"a\");\n    test_dirname(\"a/b/\", \"a/b\");\n    test_dirname(\"a/b/c\", \"a/b\");\n    test_dirname(\"/\", \"/\");\n    test_dirname(\"/a\", \"/\");\n    test_dirname(\"/a/\", \"/a\");\n    test_dirname(\"/a/b\", \"/a\");\n    test_dirname(\"/a/b/\", \"/a/b\");\n    test_dirname(\"/a/b/c\", \"/a/b\");\n}\nEND_TEST\n\n\nvoid\ntest_relative_child(const char *p, const char *f, const char *expected)\n{\n    struct cork_path  *actual;\n\n    fprintf(stderr, \"relative_child(\\\"%s\\\", \\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p == NULL)? \"\": p,\n            (f == NULL)? \"\": f,\n            expected);\n\n    actual = cork_path_new(p);\n    cork_path_set_basename(actual);\n    cork_path_append(actual, f);\n    verify_path_content(actual, expected);\n    cork_path_free(actual);\n}\n\nSTART_TEST(test_path_relative_child_01)\n{\n    DESCRIBE_TEST;\n    test_relative_child(NULL, \"a\", \"a\");\n    test_relative_child(\"\", \"a\", \"a\");\n    test_relative_child(\"a\", \"b\", \"a/b\");\n    test_relative_child(\"a/b\", \"c\", \"b/c\");\n}\nEND_TEST\n\n\nvoid\ntest_set_absolute(const char *p, const char *expected)\n{\n    struct cork_path  *actual;\n\n    fprintf(stderr, \"set_absolute(\\\"%s\\\") ?= \\\"%s\\\"\\n\",\n            (p == NULL)? \"\": p,\n            expected);\n\n    actual = cork_path_new(p);\n    cork_path_set_absolute(actual);\n    if ((p != NULL) && (p[0] == '/')) {\n        /* If the first char in p is a '/', then we want to\n         * test that already have an absolute path string. */\n        verify_path_content(actual, expected);\n    } else {\n        /* Otherwise, we have to construct a new expected path\n         * string using cork_path_cwd since the prepended $ROOT\n         * path is unknown. */\n        struct cork_path  *root_path;\n        struct cork_buffer  *expected_path = cork_buffer_new();\n        root_path = cork_path_cwd();\n        cork_buffer_append_printf\n            (expected_path, \"%s/%s\", cork_path_get(root_path), expected);\n        verify_path_content(actual, (char *) expected_path->buf);\n        cork_path_free(root_path);\n        cork_buffer_free(expected_path);\n    }\n    cork_path_free(actual);\n}\n\nSTART_TEST(test_path_set_absolute_01)\n{\n    /* We test that an absolute path really is so. */\n    DESCRIBE_TEST\n    test_set_absolute(\"\", \"\");\n    test_set_absolute(\"/\", \"/\");\n    test_set_absolute(\"/a\", \"/a\");\n    test_set_absolute(\"/a/b\", \"/a/b\");\n    test_set_absolute(\"/a/b/\", \"/a/b/\");\n    test_set_absolute(\"c/d\", \"c/d\");\n    test_set_absolute(\"c/d/\", \"c/d/\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Lists of paths\n */\n\nvoid\nverify_path_list_content(struct cork_path_list *list, const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    size_t  count = cork_path_list_size(list);\n    size_t  i;\n\n    for (i = 0; i < count; i++) {\n        const struct cork_path  *path = cork_path_list_get(list, i);\n        cork_buffer_append_string(&buf, cork_path_get(path));\n        cork_buffer_append(&buf, \"\\n\", 1);\n    }\n\n    fail_unless_streq(\"path lists\", expected, buf.buf);\n    cork_buffer_done(&buf);\n}\n\nvoid\ntest_path_list(const char *p, const char *expected)\n{\n    struct cork_path_list  *list;\n\n    fprintf(stderr, \"path_list(\\\"%s\\\")\\n\", p);\n\n    list = cork_path_list_new(p);\n    verify_path_list_content(list, expected);\n    fail_unless_streq(\"path lists\", p, cork_path_list_to_string(list));\n    cork_path_list_free(list);\n}\n\nSTART_TEST(test_path_list_01)\n{\n    DESCRIBE_TEST;\n    test_path_list(\"a\", \"a\\n\");\n    test_path_list(\"a/b\", \"a/b\\n\");\n    test_path_list(\":a/b\", \"\\na/b\\n\");\n    test_path_list(\"a:a/b:\", \"a\\na/b\\n\\n\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Files\n */\n\nvoid\ntest_file_exists(const char *filename, bool expected)\n{\n    struct cork_path  *path;\n    struct cork_file  *file;\n    bool  actual;\n    path = cork_path_new(program_path);\n    cork_path_set_dirname(path);\n    cork_path_append(path, filename);\n    file = cork_file_new_from_path(path);\n    fail_if_error(cork_file_exists(file, &actual));\n    fail_unless(actual == expected, \"File %s should%s exist\",\n                cork_path_get(path), expected? \"\": \" not\");\n    cork_file_free(file);\n}\n\nSTART_TEST(test_file_exists_01)\n{\n    DESCRIBE_TEST;\n    test_file_exists(\"test-files\", true);\n    test_file_exists(\"test-nonexistent\", false);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"path\");\n\n    TCase  *tc_path = tcase_create(\"path\");\n    tcase_add_test(tc_path, test_path_01);\n    tcase_add_test(tc_path, test_path_join_01);\n    tcase_add_test(tc_path, test_path_join_02);\n    tcase_add_test(tc_path, test_path_basename_01);\n    tcase_add_test(tc_path, test_path_dirname_01);\n    tcase_add_test(tc_path, test_path_relative_child_01);\n    tcase_add_test(tc_path, test_path_set_absolute_01);\n    suite_add_tcase(s, tc_path);\n\n    TCase  *tc_path_list = tcase_create(\"path-list\");\n    tcase_add_test(tc_path_list, test_path_list_01);\n    suite_add_tcase(s, tc_path_list);\n\n    TCase  *tc_file = tcase_create(\"file\");\n    tcase_add_test(tc_file, test_file_exists_01);\n    suite_add_tcase(s, tc_file);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    assert(argc > 0);\n    program_path = argv[0];\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-gc.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/attributes.h\"\n#include \"libcork/core/gc.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/helpers/gc.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Garbage collector\n */\n\nstruct tree {\n    int  id;\n    struct tree  *left;\n    struct tree  *right;\n};\n\n_free_(tree) {\n    /* nothing to do, I just want to test the macro */\n}\n\n_recurse_(tree) {\n    struct tree  *self = obj;\n    recurse(gc, self->left, ud);\n    recurse(gc, self->right, ud);\n}\n\n/* test all the variations, even though we're only going to use \"tree\" */\n_gc_(tree);\n\n#define tree0__recurse  tree__recurse\nCORK_ATTR_UNUSED static struct cork_gc_obj_iface  tree0__gc;\n_gc_no_free_(tree0);\n\n#define tree1__free  tree__free\nCORK_ATTR_UNUSED static struct cork_gc_obj_iface  tree1__gc;\n_gc_no_recurse_(tree1);\n\nCORK_ATTR_UNUSED static struct cork_gc_obj_iface  tree2__gc;\n_gc_leaf_(tree2);\n\nstruct tree *\ntree_new(int id, struct tree *l, struct tree *r)\n{\n    struct tree  *self = cork_gc_new(tree);\n    self->id = id;\n    self->left = cork_gc_incref(l);\n    self->right = cork_gc_incref(r);\n    return self;\n}\n\nSTART_TEST(test_gc_acyclic_01)\n{\n    DESCRIBE_TEST;\n    cork_gc_init();\n\n    struct tree  *t1 = tree_new(0, NULL, NULL);\n    struct tree  *t2 = tree_new(0, NULL, NULL);\n    struct tree  *t0 = tree_new(0, t1, t2);\n\n    cork_gc_decref(t1);\n    cork_gc_decref(t2);\n    cork_gc_decref(t0);\n\n    cork_gc_done();\n}\nEND_TEST\n\nSTART_TEST(test_gc_cyclic_01)\n{\n    DESCRIBE_TEST;\n    cork_gc_init();\n\n    struct tree  *t1 = tree_new(0, NULL, NULL);\n    struct tree  *t2 = tree_new(0, NULL, NULL);\n    struct tree  *t0 = tree_new(0, t1, t2);\n\n    t1->left = cork_gc_incref(t0);\n\n    cork_gc_decref(t1);\n    cork_gc_decref(t2);\n    cork_gc_decref(t0);\n\n    cork_gc_done();\n}\nEND_TEST\n\nSTART_TEST(test_gc_cyclic_02)\n{\n    DESCRIBE_TEST;\n    cork_gc_init();\n\n    struct tree  *t1 = tree_new(0, NULL, NULL);\n    struct tree  *t2 = tree_new(0, NULL, NULL);\n    struct tree  *t0 = tree_new(0, t1, t2);\n\n    t1->left = cork_gc_incref(t0);\n    t2->left = cork_gc_incref(t2);\n    t2->right = cork_gc_incref(t0);\n\n    cork_gc_decref(t1);\n    cork_gc_decref(t2);\n    cork_gc_decref(t0);\n\n    cork_gc_done();\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"gc\");\n\n    TCase  *tc_gc = tcase_create(\"gc\");\n    tcase_add_test(tc_gc, test_gc_acyclic_01);\n    tcase_add_test(tc_gc, test_gc_cyclic_01);\n    tcase_add_test(tc_gc, test_gc_cyclic_02);\n    suite_add_tcase(s, tc_gc);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n\n"
  },
  {
    "path": "tests/test-hash-table.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/hash.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/buffer.h\"\n#include \"libcork/ds/hash-table.h\"\n\n#include \"helpers.h\"\n\n/*-----------------------------------------------------------------------\n * Integer hash tables\n */\n\nstatic void\nuint64__free(void *vi)\n{\n    uint64_t  *i = vi;\n    cork_delete(uint64_t, i);\n}\n\nstatic bool\nuint64__equals(void *user_data, const void *va, const void *vb)\n{\n    const uint64_t  *a = va;\n    const uint64_t  *b = vb;\n#if 0\n    printf(\"Testing %p (%\" PRIu64 \") and %p (%\" PRIu64 \")\\n\",\n           a, *a, b, *b);\n#endif\n    return *a == *b;\n}\n\nstatic cork_hash\nuint64__hash(void *user_data, const void *velement)\n{\n    const uint64_t  *element = velement;\n#if 0\n    printf(\"Hashing %p (%\" PRIu64 \")\\n\", element, *element);\n#endif\n    return (cork_hash) *element;\n}\n\nstatic enum cork_hash_table_map_result\nuint64_sum(void *vsum, struct cork_hash_table_entry *entry)\n{\n    uint64_t  *sum = vsum;\n    uint64_t  *value = entry->value;\n    *sum += *value;\n    return CORK_HASH_TABLE_MAP_CONTINUE;\n}\n\nstatic void\ntest_map_sum(struct cork_hash_table *table, uint64_t expected)\n{\n    uint64_t  sum = 0;\n    cork_hash_table_map(table, &sum, uint64_sum);\n    fail_unless(sum == expected,\n                \"Unexpected map sum, got %\" PRIu64\n                \", expected %\" PRIu64,\n                sum, expected);\n}\n\nstatic void\ntest_iterator_sum(struct cork_hash_table *table, uint64_t expected)\n{\n    uint64_t  sum = 0;\n    struct cork_hash_table_iterator  iterator;\n    struct cork_hash_table_entry  *entry;\n    cork_hash_table_iterator_init(table, &iterator);\n    while ((entry = cork_hash_table_iterator_next(&iterator)) != NULL) {\n        uint64_t  *value_ptr = entry->value;\n        sum += *value_ptr;\n    }\n    fail_unless(sum == expected,\n                \"Unexpected iterator sum, got %\" PRIu64\n                \", expected %\" PRIu64 \"\",\n                sum, expected);\n}\n\nstatic enum cork_hash_table_map_result\nuint64_to_string(void *vdest, struct cork_hash_table_entry *entry)\n{\n    struct cork_buffer  *dest = vdest;\n    uint64_t  *key = entry->key;\n    uint64_t  *value = entry->value;\n    if (dest->size > 1) {\n        cork_buffer_append(dest, \", \", 2);\n    }\n    cork_buffer_append_printf(dest, \"%\" PRIu64 \":%\" PRIu64, *key, *value);\n    return CORK_HASH_TABLE_MAP_CONTINUE;\n}\n\nstatic void\ntest_map_to_string(struct cork_hash_table *table, const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    cork_buffer_set(&buf, \"[\", 1);\n    cork_hash_table_map(table, &buf, uint64_to_string);\n    cork_buffer_append(&buf, \"]\", 1);\n    fail_unless_streq(\"Integer arrays\", expected, buf.buf);\n    cork_buffer_done(&buf);\n}\n\nstatic void\ntest_iterator_to_string(struct cork_hash_table *table, const char *expected)\n{\n    struct cork_buffer  buf = CORK_BUFFER_INIT();\n    struct cork_hash_table_iterator  iterator;\n    struct cork_hash_table_entry  *entry;\n    cork_buffer_set(&buf, \"[\", 1);\n    cork_hash_table_iterator_init(table, &iterator);\n    while ((entry = cork_hash_table_iterator_next(&iterator)) != NULL) {\n        uint64_t  *key = entry->key;\n        uint64_t  *value = entry->value;\n        if (buf.size > 1) {\n            cork_buffer_append(&buf, \", \", 2);\n        }\n        cork_buffer_append_printf(&buf, \"%\" PRIu64 \":%\" PRIu64, *key, *value);\n    }\n    cork_buffer_append(&buf, \"]\", 1);\n    fail_unless_streq(\"Integer arrays\", expected, buf.buf);\n    cork_buffer_done(&buf);\n}\n\nSTART_TEST(test_uint64_hash_table)\n{\n    struct cork_hash_table  *table;\n    uint64_t  key, *key_ptr, *old_key;\n    void  *v_key, *v_value;\n    uint64_t  *value_ptr, *old_value;\n    bool  is_new;\n    struct cork_hash_table_entry  *entry;\n\n    table = cork_hash_table_new(0, 0);\n    cork_hash_table_set_hash(table, uint64__hash);\n    cork_hash_table_set_equals(table, uint64__equals);\n    cork_hash_table_set_free_key(table, uint64__free);\n    cork_hash_table_set_free_value(table, uint64__free);\n    fail_unless(cork_hash_table_size(table) == 0,\n                \"Hash table should start empty\");\n\n    key = 0;\n    fail_unless(cork_hash_table_get(table, &key) == NULL,\n                \"Shouldn't get value pointer from empty hash table\");\n\n    test_map_sum(table, 0);\n    test_map_to_string(table, \"[]\");\n    test_iterator_sum(table, 0);\n    test_iterator_to_string(table, \"[]\");\n\n    key_ptr = cork_new(uint64_t);\n    *key_ptr = 0;\n    value_ptr = cork_new(uint64_t);\n    *value_ptr = 32;\n    fail_if_error(cork_hash_table_put\n                  (table, key_ptr, value_ptr,\n                   &is_new, &v_key, &v_value));\n    fail_unless(is_new, \"Couldn't append {0=>32} to hash table\");\n    old_key = v_key;\n    old_value = v_value;\n\n    fail_unless(old_key == NULL,\n                \"Unexpected previous key\");\n    fail_unless(old_value == NULL,\n                \"Unexpected previous value\");\n\n    fail_unless(cork_hash_table_size(table) == 1,\n                \"Unexpected size after adding {0->32}\");\n\n    fail_if_error(entry = cork_hash_table_get_or_create\n                  (table, &key, &is_new));\n    fail_if(is_new, \"Shouldn't create new {0=>X} entry\");\n    value_ptr = entry->value;\n    fail_unless(*value_ptr == 32,\n                \"Unexpected value for {0=>X} entry\");\n\n    fail_unless(cork_hash_table_size(table) == 1,\n                \"Unexpected size after retrieving {0->32}\");\n\n    key = 1;\n    fail_if_error(entry = cork_hash_table_get_or_create\n                  (table, &key, &is_new));\n    fail_unless(is_new, \"Should create new {1=>X} entry\");\n    key_ptr = cork_new(uint64_t);\n    *key_ptr = key;\n    entry->key = key_ptr;\n    value_ptr = cork_new(uint64_t);\n    *value_ptr = 2;\n    entry->value = value_ptr;\n\n    fail_unless(cork_hash_table_size(table) == 2,\n                \"Unexpected size after adding {1=>2}\");\n\n    test_map_sum(table, 34);\n    test_map_to_string(table, \"[0:32, 1:2]\");\n    test_iterator_sum(table, 34);\n    test_iterator_to_string(table, \"[0:32, 1:2]\");\n\n    key = 0;\n    fail_unless(cork_hash_table_delete(table, &key, NULL, NULL),\n                \"Couldn't delete {0=>32}\");\n\n    fail_unless(cork_hash_table_size(table) == 1,\n                \"Unexpected size after deleting entry\");\n\n    test_map_to_string(table, \"[1:2]\");\n    test_iterator_to_string(table, \"[1:2]\");\n\n    key = 3;\n    fail_if(cork_hash_table_delete(table, &key, NULL, NULL),\n            \"Shouldn't be able to delete nonexistent {3=>X}\");\n\n    cork_hash_table_delete_entry(table, entry);\n\n    fail_unless(cork_hash_table_size(table) == 0,\n                \"Unexpected size after deleting last entry\");\n\n    /*\n     * Add the entries back so that we can try deleting them using\n     * cork_hash_table_map.\n     */\n\n    key_ptr = cork_new(uint64_t);\n    *key_ptr = 0;\n    value_ptr = cork_new(uint64_t);\n    *value_ptr = 32;\n    fail_if_error(cork_hash_table_put\n                  (table, key_ptr, value_ptr,\n                   &is_new, &v_key, &v_value));\n    fail_unless(is_new, \"Couldn't append {0=>32} to hash table\");\n    old_key = v_key;\n    old_value = v_value;\n\n    key_ptr = cork_new(uint64_t);\n    *key_ptr = 1;\n    value_ptr = cork_new(uint64_t);\n    *value_ptr = 2;\n    fail_if_error(cork_hash_table_put\n                  (table, key_ptr, value_ptr,\n                   &is_new, &v_key, &v_value));\n    fail_unless(is_new, \"Couldn't append {1=>2} to hash table\");\n    old_key = v_key;\n    old_value = v_value;\n\n    cork_hash_table_clear(table);\n    fail_unless(cork_hash_table_size(table) == 0,\n                \"Unexpected size after deleting entries using map\");\n\n    /* And we're done, so let's free everything. */\n    cork_hash_table_free(table);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * String hash tables\n */\n\nSTART_TEST(test_string_hash_table)\n{\n    struct cork_hash_table  *table;\n    char  key[256];\n    void  *value;\n\n    table = cork_string_hash_table_new(0, 0);\n\n    fail_if_error(cork_hash_table_put\n                  (table, \"key1\", (void *) (uintptr_t) 1, NULL, NULL, NULL));\n    fail_unless(cork_hash_table_size(table) == 1,\n                \"Unexpected size after adding {key1->1}\");\n\n    strncpy(key, \"key1\", sizeof(key));\n    fail_if((value = cork_hash_table_get(table, key)) == NULL,\n            \"No entry for key1\");\n\n    fail_unless(value == (void *) (uintptr_t) 1,\n                \"Unexpected value for key1\");\n\n    strncpy(key, \"key2\", sizeof(key));\n    fail_unless((value = cork_hash_table_get(table, key)) == NULL,\n                \"Unexpected entry for key2\");\n\n    cork_hash_table_free(table);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Pointer hash tables\n */\n\nSTART_TEST(test_pointer_hash_table)\n{\n    struct cork_hash_table  *table;\n    int  key1;\n    int  key2;\n    void  *value;\n\n    table = cork_pointer_hash_table_new(0, 0);\n\n    fail_if_error(cork_hash_table_put\n                  (table, &key1, (void *) (uintptr_t) 1, NULL, NULL, NULL));\n    fail_unless(cork_hash_table_size(table) == 1,\n                \"Unexpected size after adding {key1->1}\");\n\n    fail_if((value = cork_hash_table_get(table, &key1)) == NULL,\n            \"No entry for key1\");\n\n    fail_unless(value == (void *) (uintptr_t) 1,\n                \"Unexpected value for key1\");\n\n    fail_unless((value = cork_hash_table_get(table, &key2)) == NULL,\n                \"Unexpected entry for key2\");\n\n    cork_hash_table_free(table);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"hash_table\");\n\n    TCase  *tc_ds = tcase_create(\"hash_table\");\n    tcase_add_test(tc_ds, test_uint64_hash_table);\n    tcase_add_test(tc_ds, test_string_hash_table);\n    tcase_add_test(tc_ds, test_pointer_hash_table);\n    suite_add_tcase(s, tc_ds);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-managed-buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2009, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/managed-buffer.h\"\n#include \"libcork/ds/slice.h\"\n#include \"libcork/helpers/errors.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Helper functions\n */\n\nstruct flag_buffer {\n    struct cork_managed_buffer  parent;\n    bool  *flag;\n};\n\nstatic void\nset_flag_on_free(struct cork_managed_buffer *mbuf)\n{\n    struct flag_buffer  *fbuf =\n        cork_container_of(mbuf, struct flag_buffer, parent);\n    *fbuf->flag = true;\n    cork_delete(struct flag_buffer, fbuf);\n}\n\nstatic struct cork_managed_buffer_iface  FLAG__MANAGED_BUFFER = {\n    set_flag_on_free\n};\n\nstatic struct cork_managed_buffer *\nflag_buffer_new(const void *buf, size_t size, bool *flag)\n{\n    struct flag_buffer  *fbuf = cork_new(struct flag_buffer);\n    fbuf->parent.buf = buf;\n    fbuf->parent.size = size;\n    fbuf->parent.ref_count = 1;\n    fbuf->parent.iface = &FLAG__MANAGED_BUFFER;\n    fbuf->flag = flag;\n    return &fbuf->parent;\n}\n\n\n\n/*-----------------------------------------------------------------------\n * Buffer reference counting\n */\n\nSTART_TEST(test_managed_buffer_refcount)\n{\n    bool  flag = false;\n\n    /*\n     * Make a bunch of references, unreference them all, and then\n     * verify that the free function got called.\n     */\n\n    struct cork_managed_buffer  *pb0;\n    fail_if_error(pb0 = flag_buffer_new(NULL, 0, &flag));\n    struct cork_managed_buffer  *pb1 = cork_managed_buffer_ref(pb0);\n    struct cork_managed_buffer  *pb2 = cork_managed_buffer_ref(pb0);\n    struct cork_managed_buffer  *pb3 = cork_managed_buffer_ref(pb2);\n\n    cork_managed_buffer_unref(pb0);\n    cork_managed_buffer_unref(pb1);\n    cork_managed_buffer_unref(pb2);\n    cork_managed_buffer_unref(pb3);\n\n    fail_unless(flag,\n                \"Managed buffer free function never called.\");\n}\nEND_TEST\n\n\nSTART_TEST(test_managed_buffer_bad_refcount)\n{\n    bool  flag = false;\n\n    /*\n     * Make a bunch of references, forget to unreference one of them,\n     * and then verify that the free function didn't called.\n     */\n\n    struct cork_managed_buffer  *pb0;\n    fail_if_error(pb0 = flag_buffer_new(NULL, 0, &flag));\n    struct cork_managed_buffer  *pb1 = cork_managed_buffer_ref(pb0);\n    struct cork_managed_buffer  *pb2 = cork_managed_buffer_ref(pb0);\n    struct cork_managed_buffer  *pb3 = cork_managed_buffer_ref(pb2);\n\n    cork_managed_buffer_unref(pb0);\n    cork_managed_buffer_unref(pb1);\n    cork_managed_buffer_unref(pb2);\n    /* cork_managed_buffer_unref(pb3);   OH NO! */\n    (void) pb3;\n\n    fail_if(flag,\n            \"Managed buffer free function was called unexpectedly.\");\n\n    /* free the buffer here to quiet valgrind */\n    cork_managed_buffer_unref(pb3);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Slicing\n */\n\nSTART_TEST(test_slice)\n{\n    /* Try to slice a NULL buffer. */\n    struct cork_slice  ps1;\n\n    fail_unless_error(cork_managed_buffer_slice\n                      (&ps1, NULL, 0, 0),\n                      \"Shouldn't be able to slice a NULL buffer\");\n    fail_unless_error(cork_managed_buffer_slice_offset\n                      (&ps1, NULL, 0),\n                      \"Shouldn't be able to slice a NULL buffer\");\n\n    fail_unless_error(cork_slice_copy\n                      (&ps1, NULL, 0, 0),\n                      \"Shouldn't be able to slice a NULL slice\");\n    fail_unless_error(cork_slice_copy_offset\n                      (&ps1, NULL, 0),\n                      \"Shouldn't be able to slice a NULL slice\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Slice reference counting\n */\n\nSTART_TEST(test_slice_refcount)\n{\n    bool  flag = false;\n\n    /*\n     * Make a bunch of slices, finish them all, and then verify that\n     * the free function got called.\n     */\n\n    static char  *BUF =\n        \"abcdefg\";\n    static size_t  LEN = 7;\n\n    struct cork_managed_buffer  *pb;\n    fail_if_error(pb = flag_buffer_new(BUF, LEN, &flag));\n\n    struct cork_slice  ps1;\n    struct cork_slice  ps2;\n    struct cork_slice  ps3;\n\n    fail_if_error(cork_managed_buffer_slice(&ps1, pb, 0, 7));\n    fail_if_error(cork_managed_buffer_slice(&ps2, pb, 1, 1));\n    fail_if_error(cork_managed_buffer_slice(&ps3, pb, 4, 3));\n\n    cork_managed_buffer_unref(pb);\n    cork_slice_finish(&ps1);\n    cork_slice_finish(&ps2);\n    cork_slice_finish(&ps3);\n\n    fail_unless(flag,\n                \"Managed buffer free function never called.\");\n}\nEND_TEST\n\n\nSTART_TEST(test_slice_bad_refcount)\n{\n    bool  flag = false;\n\n    /*\n     * Make a bunch of slices, forget to finish one of them, and then\n     * verify that the free function didn't called.\n     */\n\n    static char  *BUF =\n        \"abcdefg\";\n    static size_t  LEN = 7;\n\n    struct cork_managed_buffer  *pb;\n    fail_if_error(pb = flag_buffer_new(BUF, LEN, &flag));\n\n    struct cork_slice  ps1;\n    struct cork_slice  ps2;\n    struct cork_slice  ps3;\n\n    fail_if_error(cork_managed_buffer_slice(&ps1, pb, 0, 7));\n    fail_if_error(cork_managed_buffer_slice(&ps2, pb, 1, 1));\n    fail_if_error(cork_managed_buffer_slice(&ps3, pb, 4, 3));\n\n    cork_managed_buffer_unref(pb);\n    cork_slice_finish(&ps1);\n    cork_slice_finish(&ps2);\n    /* cork_slice_finish(&ps3);   OH NO! */\n\n    fail_if(flag,\n            \"Managed buffer free function was called unexpectedly.\");\n\n    /* free the slice here to quiet valgrind */\n    cork_slice_finish(&ps3);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Slice equality\n */\n\nSTART_TEST(test_slice_equals_01)\n{\n    /*\n     * Make a bunch of slices, finish them all, and then verify that\n     * the free function got called.\n     */\n\n    static char  *BUF =\n        \"abcdefg\";\n    static size_t  LEN = 7;\n\n    struct cork_managed_buffer  *pb;\n    fail_if_error(pb = cork_managed_buffer_new_copy(BUF, LEN));\n\n    struct cork_slice  ps1;\n    struct cork_slice  ps2;\n\n    fail_if_error(cork_managed_buffer_slice_offset(&ps1, pb, 0));\n    fail_if_error(cork_managed_buffer_slice(&ps2, pb, 0, LEN));\n\n    fail_unless(cork_slice_equal(&ps1, &ps2),\n                \"Slices aren't equal\");\n\n    cork_managed_buffer_unref(pb);\n    cork_slice_finish(&ps1);\n    cork_slice_finish(&ps2);\n}\nEND_TEST\n\n\nSTART_TEST(test_slice_equals_02)\n{\n    /*\n     * Make a bunch of slices, finish them all, and then verify that\n     * the free function got called.\n     */\n\n    static char  *BUF =\n        \"abcdefg\";\n    static size_t  LEN = 7;\n\n    struct cork_managed_buffer  *pb;\n    fail_if_error(pb = cork_managed_buffer_new_copy(BUF, LEN));\n\n    struct cork_slice  ps1;\n    struct cork_slice  ps2;\n    struct cork_slice  ps3;\n\n    fail_if_error(cork_managed_buffer_slice(&ps1, pb, 3, 3));\n\n    fail_if_error(cork_managed_buffer_slice_offset(&ps2, pb, 1));\n    fail_if_error(cork_slice_copy(&ps3, &ps2, 2, 3));\n    fail_if_error(cork_slice_slice(&ps2, 2, 3));\n\n    fail_unless(cork_slice_equal(&ps1, &ps2),\n                \"Slices aren't equal\");\n    fail_unless(cork_slice_equal(&ps1, &ps3),\n                \"Slices aren't equal\");\n\n    cork_managed_buffer_unref(pb);\n    cork_slice_finish(&ps1);\n    cork_slice_finish(&ps2);\n    cork_slice_finish(&ps3);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"managed-buffer\");\n\n    TCase  *tc_buffer_refcount = tcase_create(\"managed-buffer-refcount\");\n    tcase_add_test(tc_buffer_refcount, test_managed_buffer_refcount);\n    tcase_add_test(tc_buffer_refcount, test_managed_buffer_bad_refcount);\n    suite_add_tcase(s, tc_buffer_refcount);\n\n    TCase  *tc_slice = tcase_create(\"slice\");\n    tcase_add_test(tc_slice, test_slice);\n    suite_add_tcase(s, tc_slice);\n\n    TCase  *tc_slice_refcount = tcase_create(\"slice-refcount\");\n    tcase_add_test(tc_slice_refcount, test_slice_refcount);\n    tcase_add_test(tc_slice_refcount, test_slice_bad_refcount);\n    suite_add_tcase(s, tc_slice_refcount);\n\n    TCase  *tc_slice_equality = tcase_create(\"slice-equality\");\n    tcase_add_test(tc_slice_equality, test_slice_equals_01);\n    tcase_add_test(tc_slice_equality, test_slice_equals_02);\n    suite_add_tcase(s, tc_slice_equality);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-mempool.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <signal.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/mempool.h\"\n#include \"libcork/core/types.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Memory pools\n */\n\n\nSTART_TEST(test_mempool_01)\n{\n#define OBJECT_COUNT  16\n    DESCRIBE_TEST;\n    struct cork_mempool  *mp;\n    /* Small enough that we'll have to allocate a couple of blocks */\n    mp = cork_mempool_new_ex(int64_t, 64);\n\n    size_t  i;\n    int64_t  *objects[OBJECT_COUNT];\n    for (i = 0; i < OBJECT_COUNT; i++) {\n        fail_if((objects[i] = cork_mempool_new_object(mp)) == NULL,\n                \"Cannot allocate object #%zu\", i);\n    }\n\n    for (i = 0; i < OBJECT_COUNT; i++) {\n        cork_mempool_free_object(mp, objects[i]);\n    }\n\n    for (i = 0; i < OBJECT_COUNT; i++) {\n        fail_if((objects[i] = cork_mempool_new_object(mp)) == NULL,\n                \"Cannot reallocate object #%zu\", i);\n    }\n\n    for (i = 0; i < OBJECT_COUNT; i++) {\n        cork_mempool_free_object(mp, objects[i]);\n    }\n\n    cork_mempool_free(mp);\n}\nEND_TEST\n\nSTART_TEST(test_mempool_fail_01)\n{\n    DESCRIBE_TEST;\n    struct cork_mempool  *mp;\n    mp = cork_mempool_new(int64_t);\n\n    int64_t  *obj;\n    fail_if((obj = cork_mempool_new_object(mp)) == NULL,\n            \"Cannot allocate object\");\n\n    /* This should raise an assertion since we never freed obj. */\n    cork_mempool_free(mp);\n}\nEND_TEST\n\n\nstatic void\nint64_init(void *user_data, void *vobj)\n{\n    int64_t  *obj = vobj;\n    *obj = 12;\n}\n\nstatic void\nint64_done(void *user_data, void *vobj)\n{\n    size_t  *done_call_count = user_data;\n    (*done_call_count)++;\n}\n\n/* This is based on our knowledge of the internal structure of a memory\n * pool's blocks and objects. */\n\n#define OBJECTS_PER_BLOCK(block_size, obj_size) \\\n    (((block_size) - CORK_SIZEOF_POINTER) / (obj_size + CORK_SIZEOF_POINTER))\n\nSTART_TEST(test_mempool_reuse_01)\n{\n#define BLOCK_SIZE  64\n    DESCRIBE_TEST;\n    size_t  done_call_count = 0;\n    struct cork_mempool  *mp;\n    mp = cork_mempool_new_ex(int64_t, BLOCK_SIZE);\n    cork_mempool_set_user_data(mp, &done_call_count, NULL);\n    cork_mempool_set_init_object(mp, int64_init);\n    cork_mempool_set_done_object(mp, int64_done);\n\n    int64_t  *obj;\n    fail_if((obj = cork_mempool_new_object(mp)) == NULL,\n            \"Cannot allocate object\");\n\n    /* The init_object function sets the value to 12 */\n    fail_unless(*obj == 12, \"Unexpected value %\" PRId64, *obj);\n\n    /* Set the value to something new, free the object, then reallocate.\n     * Since we know memory pools are LIFO, we should get back the same\n     * object, unchanged. */\n    *obj = 42;\n    cork_mempool_free_object(mp, obj);\n    fail_if((obj = cork_mempool_new_object(mp)) == NULL,\n            \"Cannot allocate object\");\n    fail_unless(*obj == 42, \"Unexpected value %\" PRId64, *obj);\n\n    cork_mempool_free_object(mp, obj);\n    cork_mempool_free(mp);\n\n    fail_unless(done_call_count ==\n                OBJECTS_PER_BLOCK(BLOCK_SIZE, sizeof(int64_t)),\n                \"done_object called an unexpected number of times: %zu\",\n                done_call_count);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"mempool\");\n\n    TCase  *tc_mempool = tcase_create(\"mempool\");\n    tcase_add_test(tc_mempool, test_mempool_01);\n#if NDEBUG\n    /* If we're not compiling assertions then this test won't abort */\n    tcase_add_test(tc_mempool, test_mempool_fail_01);\n#else\n    tcase_add_test_raise_signal(tc_mempool, test_mempool_fail_01, SIGABRT);\n#endif\n    tcase_add_test(tc_mempool, test_mempool_reuse_01);\n    suite_add_tcase(s, tc_mempool);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n\n"
  },
  {
    "path": "tests/test-ring-buffer.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <check.h>\n\n#include \"libcork/core/types.h\"\n#include \"libcork/ds/ring-buffer.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Ring buffers\n */\n\nSTART_TEST(test_ring_buffer_1)\n{\n    struct cork_ring_buffer  buf;\n    cork_ring_buffer_init(&buf, 4);\n\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 1) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 2) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 3) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 4) == 0,\n                \"Cannot add to ring buffer\");\n    fail_if(cork_ring_buffer_add(&buf, (void *) 5) == 0,\n            \"Shouldn't be able to add to ring buffer\");\n\n    fail_unless(((intptr_t) cork_ring_buffer_peek(&buf)) == 1,\n                \"Unexpected head of ring buffer (peek)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 1,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 2,\n                \"Unexpected head of ring buffer (pop)\");\n\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 5) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(&buf, (void *) 6) == 0,\n                \"Cannot add to ring buffer\");\n    fail_if(cork_ring_buffer_add(&buf, (void *) 7) == 0,\n            \"Shouldn't be able to add to ring buffer\");\n\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 3,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 4,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 5,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(&buf)) == 6,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(cork_ring_buffer_pop(&buf) == NULL,\n                \"Shouldn't be able to pop from ring buffer\");\n\n    cork_ring_buffer_done(&buf);\n}\nEND_TEST\n\n\nSTART_TEST(test_ring_buffer_2)\n{\n    struct cork_ring_buffer  *buf = cork_ring_buffer_new(4);\n\n    fail_unless(cork_ring_buffer_add(buf, (void *) 1) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(buf, (void *) 2) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(buf, (void *) 3) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(buf, (void *) 4) == 0,\n                \"Cannot add to ring buffer\");\n    fail_if(cork_ring_buffer_add(buf, (void *) 5) == 0,\n            \"Shouldn't be able to add to ring buffer\");\n\n    fail_unless(((intptr_t) cork_ring_buffer_peek(buf)) == 1,\n                \"Unexpected head of ring buffer (peek)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 1,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 2,\n                \"Unexpected head of ring buffer (pop)\");\n\n    fail_unless(cork_ring_buffer_add(buf, (void *) 5) == 0,\n                \"Cannot add to ring buffer\");\n    fail_unless(cork_ring_buffer_add(buf, (void *) 6) == 0,\n                \"Cannot add to ring buffer\");\n    fail_if(cork_ring_buffer_add(buf, (void *) 7) == 0,\n            \"Shouldn't be able to add to ring buffer\");\n\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 3,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 4,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 5,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(((intptr_t) cork_ring_buffer_pop(buf)) == 6,\n                \"Unexpected head of ring buffer (pop)\");\n    fail_unless(cork_ring_buffer_pop(buf) == NULL,\n                \"Shouldn't be able to pop from ring buffer\");\n\n    cork_ring_buffer_free(buf);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"ring_buffer\");\n\n    TCase  *tc_ds = tcase_create(\"ring_buffer\");\n    tcase_add_test(tc_ds, test_ring_buffer_1);\n    tcase_add_test(tc_ds, test_ring_buffer_2);\n    suite_add_tcase(s, tc_ds);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-slice.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2009, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/ds/slice.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Static slices\n */\n\nSTART_TEST(test_static_slice)\n{\n    static char  SRC[] = \"Here is some text.\";\n    size_t  SRC_LEN = sizeof(SRC) - 1;\n\n    struct cork_slice  slice;\n    struct cork_slice  advanced;\n    const void* original;\n    struct cork_slice  copy1;\n    struct cork_slice  lcopy1;\n    cork_slice_init_static(&slice, SRC, SRC_LEN);\n    fail_if_error(cork_slice_copy_offset(&advanced, &slice, 0));\n    fail_if_error(original = cork_slice_advance(&advanced, 4));\n    fail_unless(strcmp(SRC, original) == 0,\n                \"Advance should return original buffer\");\n    fail_if_error(cork_slice_copy(&copy1, &slice, 8, 4));\n    fail_if_error(cork_slice_light_copy(&lcopy1, &slice, 8, 4));\n    fail_if_error(cork_slice_slice(&slice, 8, 4));\n    fail_unless(cork_slice_equal(&slice, &copy1), \"Slices should be equal\");\n    fail_unless(cork_slice_equal(&slice, &lcopy1), \"Slices should be equal\");\n    /* We have to finish lcopy1 first, since it's a light copy. */\n    cork_slice_finish(&lcopy1);\n    cork_slice_finish(&slice);\n    cork_slice_finish(&copy1);\n    cork_slice_finish(&advanced);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Copy-once slices\n */\n\nSTART_TEST(test_copy_once_slice)\n{\n    static char  SRC[] = \"Here is some text.\";\n    size_t  SRC_LEN = sizeof(SRC) - 1;\n\n    struct cork_slice  slice;\n    struct cork_slice  copy1;\n    struct cork_slice  copy2;\n    struct cork_slice  lcopy1;\n    struct cork_slice  lcopy2;\n\n    cork_slice_init_copy_once(&slice, SRC, SRC_LEN);\n    fail_unless(slice.buf == SRC, \"Unexpected slice buffer\");\n\n    fail_if_error(cork_slice_light_copy(&lcopy1, &slice, 8, 4));\n    /* We should still be using the original SRC buffer directly, since we only\n     * created a light copy. */\n    fail_unless(slice.buf == SRC, \"Unexpected slice buffer\");\n    fail_unless(slice.buf + 8 == lcopy1.buf, \"Unexpected slice buffer\");\n\n    fail_if_error(cork_slice_copy(&copy1, &slice, 8, 4));\n    fail_if_error(cork_slice_slice(&slice, 8, 4));\n    /* Once we create a full copy, the content should have been moved into a\n     * managed buffer, which will exist somewhere else in memory than the\n     * original SRC pointer. */\n    fail_unless(slice.buf != SRC, \"Unexpected slice buffer\");\n    fail_unless(slice.buf == copy1.buf, \"Unexpected slice buffer\");\n    /* The light copy that we made previously won't have been moved over to the\n     * new managed buffer, though. */\n    fail_unless(cork_slice_equal(&slice, &copy1), \"Slices should be equal\");\n\n    /* Once we've switched over to the managed buffer, a new light copy should\n     * still point into the managed buffer. */\n    fail_if_error(cork_slice_light_copy(&lcopy2, &slice, 0, 4));\n    fail_unless(slice.buf != SRC, \"Unexpected slice buffer\");\n    fail_unless(slice.buf == lcopy2.buf, \"Unexpected slice buffer\");\n\n    fail_if_error(cork_slice_copy(&copy2, &slice, 0, 4));\n    /* The second full copy should not create a new managed buffer, it should\n     * just increment the existing managed buffer's refcount. */\n    fail_unless(slice.buf == copy2.buf, \"Unexpected slice buffer\");\n    fail_unless(copy1.buf == copy2.buf, \"Unexpected slice buffer\");\n    fail_unless(cork_slice_equal(&slice, &copy2), \"Slices should be equal\");\n    fail_unless(cork_slice_equal(&copy1, &copy2), \"Slices should be equal\");\n\n    /* We have to finish the light copies first. */\n    cork_slice_finish(&lcopy1);\n    cork_slice_finish(&lcopy2);\n    cork_slice_finish(&slice);\n    cork_slice_finish(&copy1);\n    cork_slice_finish(&copy2);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"slice\");\n\n    TCase  *tc_slice = tcase_create(\"slice\");\n    tcase_add_test(tc_slice, test_static_slice);\n    tcase_add_test(tc_slice, test_copy_once_slice);\n    suite_add_tcase(s, tc_slice);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-subprocess.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2011, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <errno.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/config.h\"\n#include \"libcork/core.h\"\n#include \"libcork/ds.h\"\n#include \"libcork/os.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Verifying stream consumer\n */\n\nstruct verify_consumer {\n    struct cork_stream_consumer  parent;\n    struct cork_buffer  buf;\n    const char  *name;\n    const char  *expected;\n};\n\nstatic int\nverify_consumer__data(struct cork_stream_consumer *vself,\n                      const void *buf, size_t size, bool is_first)\n{\n    struct verify_consumer  *self =\n        cork_container_of(vself, struct verify_consumer, parent);\n    if (is_first) {\n        cork_buffer_clear(&self->buf);\n    }\n    cork_buffer_append(&self->buf, buf, size);\n    return 0;\n}\n\nstatic int\nverify_consumer__eof(struct cork_stream_consumer *vself)\n{\n    struct verify_consumer  *self =\n        cork_container_of(vself, struct verify_consumer, parent);\n    const char  *actual = self->buf.buf;\n    if (actual == NULL) {\n        actual = \"\";\n    }\n    fail_unless(strcmp(actual, self->expected) == 0,\n                \"Unexpected %s: got\\n%s\\nexpected\\n%s\\n\", self->name,\n                actual, self->expected);\n    return 0;\n}\n\nstatic void\nverify_consumer__free(struct cork_stream_consumer *vself)\n{\n    struct verify_consumer  *self =\n        cork_container_of(vself, struct verify_consumer, parent);\n    cork_buffer_done(&self->buf);\n    cork_strfree(self->name);\n    cork_strfree(self->expected);\n    cork_delete(struct verify_consumer, self);\n}\n\nstruct cork_stream_consumer *\nverify_consumer_new(const char *name, const char *expected)\n{\n    struct verify_consumer  *self = cork_new(struct verify_consumer);\n    self->parent.data = verify_consumer__data;\n    self->parent.eof = verify_consumer__eof;\n    self->parent.free = verify_consumer__free;\n    cork_buffer_init(&self->buf);\n    self->name = cork_strdup(name);\n    self->expected = cork_strdup(expected);\n    return &self->parent;\n}\n\n\n/*-----------------------------------------------------------------------\n * Helpers\n */\n\nstruct env {\n    const char  *name;\n    const char  *value;\n};\n\nstruct spec {\n    char  *program;\n    char * const  *params;\n    struct env  *env;\n    const char  *expected_stdout;\n    const char  *expected_stderr;\n    int  expected_exit_code;\n    struct cork_stream_consumer  *verify_stdout;\n    struct cork_stream_consumer  *verify_stderr;\n    int  exit_code;\n};\n\nstatic struct cork_env *\ntest_env(struct env *env_spec)\n{\n    struct cork_env  *env;\n    struct env  *curr;\n\n    if (env_spec == NULL) {\n        return NULL;\n    }\n\n    env = cork_env_new();\n    for (curr = env_spec; curr->name != NULL; curr++) {\n        cork_env_add_printf(env, curr->name, \"%s\", curr->value);\n    }\n\n    return env;\n}\n\nstatic void\ntest_subprocesses_(size_t spec_count, struct spec **specs)\n{\n    size_t  i;\n    struct cork_subprocess_group  *group = cork_subprocess_group_new();\n\n    for (i = 0; i < spec_count; i++) {\n        struct spec  *spec = specs[i];\n        struct cork_exec *exec;\n        struct cork_env  *env = test_env(spec->env);\n        struct cork_subprocess  *sub;\n        spec->verify_stdout =\n            verify_consumer_new(\"stdout\", spec->expected_stdout);\n        spec->verify_stderr =\n            verify_consumer_new(\"stderr\", spec->expected_stderr);\n        fail_if_error(exec = cork_exec_new_with_param_array\n                      (spec->program, spec->params));\n        cork_exec_set_env(exec, env);\n        fail_if_error(sub = cork_subprocess_new_exec\n                      (exec, spec->verify_stdout, spec->verify_stderr,\n                       &spec->exit_code));\n        cork_subprocess_group_add(group, sub);\n    }\n\n    fail_if_error(cork_subprocess_group_start(group));\n    fail_if_error(cork_subprocess_group_wait(group));\n\n    for (i = 0; i < spec_count; i++) {\n        struct spec  *spec = specs[i];\n        fail_unless_equal(\"Exit codes\", \"%d\",\n                          spec->expected_exit_code, spec->exit_code);\n        cork_stream_consumer_free(spec->verify_stdout);\n        cork_stream_consumer_free(spec->verify_stderr);\n    }\n\n    cork_subprocess_group_free(group);\n}\n\n#define test_subprocesses(specs) \\\n    test_subprocesses_(sizeof(specs) / sizeof(specs[0]), specs)\n\n\n/*-----------------------------------------------------------------------\n * Subprocesses\n */\n\nstatic char  *echo_01_params[] = { \"echo\", \"hello\", \"world\", NULL };\nstatic struct spec  echo_01 = {\n    \"echo\", echo_01_params, NULL, \"hello world\\n\", \"\", 0\n};\n\nstatic char  *echo_02_params[] = { \"echo\", \"foo\", \"bar\", \"baz\", NULL };\nstatic struct spec  echo_02 = {\n    \"echo\", echo_02_params, NULL, \"foo bar baz\\n\", \"\", 0\n};\n\nstatic char  *echo_03_params[] = { \"sh\", \"-c\", \"echo $CORK_TEST_VAR\", NULL };\nstatic struct env  echo_03_env[] = {\n    { \"CORK_TEST_VAR\", \"hello world\" },\n    { NULL }\n};\nstatic struct spec  echo_03 = {\n    \"sh\", echo_03_params, echo_03_env, \"hello world\\n\", \"\", 0\n};\n\nstatic char  *false_01_params[] = { \"false\", NULL };\nstatic struct spec  false_01 = {\n    \"false\", false_01_params, NULL, \"\", \"\", 1\n};\n\n\nSTART_TEST(test_subprocess_01)\n{\n    DESCRIBE_TEST;\n    struct spec  *specs[] = { &echo_01 };\n    test_subprocesses(specs);\n}\nEND_TEST\n\n\nSTART_TEST(test_subprocess_02)\n{\n    DESCRIBE_TEST;\n    struct spec  *specs[] = { &echo_02 };\n    test_subprocesses(specs);\n}\nEND_TEST\n\n\nSTART_TEST(test_subprocess_03)\n{\n    DESCRIBE_TEST;\n    struct spec  *specs[] = { &echo_03 };\n    test_subprocesses(specs);\n}\nEND_TEST\n\n\nSTART_TEST(test_subprocess_group_01)\n{\n    DESCRIBE_TEST;\n    struct spec  *specs[] = { &echo_01, &echo_02 };\n    test_subprocesses(specs);\n}\nEND_TEST\n\n\nSTART_TEST(test_subprocess_exit_code_01)\n{\n    DESCRIBE_TEST;\n    struct spec  *specs[] = { &false_01 };\n    test_subprocesses(specs);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"subprocess\");\n\n    TCase  *tc_subprocess = tcase_create(\"subprocess\");\n    tcase_add_test(tc_subprocess, test_subprocess_01);\n    tcase_add_test(tc_subprocess, test_subprocess_02);\n    tcase_add_test(tc_subprocess, test_subprocess_03);\n    tcase_add_test(tc_subprocess, test_subprocess_group_01);\n    tcase_add_test(tc_subprocess, test_subprocess_exit_code_01);\n    suite_add_tcase(s, tc_subprocess);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-threads.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2012, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <errno.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"libcork/core/allocator.h\"\n#include \"libcork/core/types.h\"\n#include \"libcork/threads/atomics.h\"\n#include \"libcork/threads/basics.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * Atomics\n */\n\n#define test_atomic_op(name, type, fmt, op, expected) \\\n    do { \\\n        type  actual = cork_##name##_atomic_##op(&val, 1); \\\n        fail_unless_equal(#name, fmt, expected, actual); \\\n    } while (0)\n\n#define test_cas(name, type, fmt, ov, nv) \\\n    do { \\\n        type  actual = cork_##name##_cas(&val, ov, nv); \\\n        fail_unless_equal(#name, fmt, ov, actual); \\\n    } while (0)\n\n#define test_atomic(name, type, fmt) \\\nSTART_TEST(test_atomic_##name) \\\n{ \\\n    DESCRIBE_TEST; \\\n    volatile type  val = 0; \\\n    test_atomic_op(name, type, fmt, add, 1); \\\n    test_atomic_op(name, type, fmt, pre_add, 1); \\\n    test_atomic_op(name, type, fmt, add, 3); \\\n    test_atomic_op(name, type, fmt, pre_add, 3); \\\n    fail_unless_equal(#name, fmt, 4, val); \\\n    test_atomic_op(name, type, fmt, sub, 3); \\\n    test_atomic_op(name, type, fmt, pre_sub, 3); \\\n    test_atomic_op(name, type, fmt, sub, 1); \\\n    test_atomic_op(name, type, fmt, pre_sub, 1); \\\n    fail_unless_equal(#name, fmt, 0, val); \\\n    \\\n    test_cas(name, type, fmt, 0, 1); \\\n    test_cas(name, type, fmt, 1, 10); \\\n    test_cas(name, type, fmt, 10, 2); \\\n    test_cas(name, type, fmt, 2, 0); \\\n    fail_unless_equal(#name, fmt, 0, val); \\\n} \\\nEND_TEST\n\ntest_atomic(int,  int,          \"%d\");\ntest_atomic(uint, unsigned int, \"%u\");\ntest_atomic(size, size_t,       \"%zu\");\n\nSTART_TEST(test_atomic_ptr)\n{\n    DESCRIBE_TEST;\n\n    uint64_t  v0 = 0;\n    uint64_t  v1 = 0;\n    uint64_t  v2 = 0;\n    uint64_t  v3 = 0;\n    uint64_t * volatile  val = &v0;\n\n    test_cas(ptr, uint64_t *, \"%p\", &v0, &v1);\n    test_cas(ptr, uint64_t *, \"%p\", &v1, &v2);\n    test_cas(ptr, uint64_t *, \"%p\", &v2, &v3);\n    test_cas(ptr, uint64_t *, \"%p\", &v3, &v0);\n    fail_unless_equal(\"ptr\", \"%p\", &v0, val);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Once\n */\n\nSTART_TEST(test_once)\n{\n    DESCRIBE_TEST;\n\n    cork_once_barrier(once);\n    static size_t  call_count = 0;\n    static int  value = 0;\n\n#define go \\\n    do { \\\n        call_count++; \\\n        value = 1; \\\n    } while (0)\n\n    cork_once(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n\n    fail_unless_equal(\"Call count\", \"%zu\", 1, call_count);\n}\nEND_TEST\n\nSTART_TEST(test_once_recursive)\n{\n    DESCRIBE_TEST;\n\n    cork_once_barrier(once);\n    static size_t  call_count = 0;\n    static int  value = 0;\n\n#define go \\\n    do { \\\n        call_count++; \\\n        value = 1; \\\n    } while (0)\n\n    cork_once_recursive(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once_recursive(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once_recursive(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n    cork_once_recursive(once, go);\n    fail_unless_equal(\"Value\", \"%d\", 1, value);\n\n    fail_unless_equal(\"Call count\", \"%zu\", 1, call_count);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Thread IDs\n */\n\nSTART_TEST(test_thread_ids)\n{\n    DESCRIBE_TEST;\n    cork_thread_id  id = cork_current_thread_get_id();\n    fail_if(id == CORK_THREAD_NONE, \"Expected a valid thread ID\");\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Threads\n */\n\nstruct cork_test_thread {\n    int  *dest;\n    int  value;\n};\n\nstatic int\ncork_test_thread__run(void *vself)\n{\n    struct cork_test_thread  *self = vself;\n    *self->dest = self->value;\n    return 0;\n}\n\nstatic void\ncork_test_thread__free(void *vself)\n{\n    struct cork_test_thread  *self = vself;\n    cork_delete(struct cork_test_thread, self);\n}\n\nstatic struct cork_thread *\ncork_test_thread_new(const char *name, int *dest, int value)\n{\n    struct cork_test_thread  *self = cork_new(struct cork_test_thread);\n    self->dest = dest;\n    self->value = value;\n    return cork_thread_new\n        (name, self, cork_test_thread__free, cork_test_thread__run);\n}\n\n\nstatic int\ncork_error_thread__run(void *vself)\n{\n    /* The particular error doesn't matter; just want to make sure it gets\n     * propagated from the cork_thread_join call. */\n    cork_system_error_set_explicit(ENOMEM);\n    return -1;\n}\n\n\nSTART_TEST(test_threads_01)\n{\n    struct cork_thread  *t1;\n    int  v1 = -1;\n\n    DESCRIBE_TEST;\n\n    fail_if_error(t1 = cork_test_thread_new(\"test\", &v1, 1));\n    fail_unless_equal(\"Values\", \"%d\", -1, v1);\n    cork_thread_free(t1);\n}\nEND_TEST\n\nSTART_TEST(test_threads_02)\n{\n    struct cork_thread  *t1;\n    int  v1 = -1;\n\n    DESCRIBE_TEST;\n\n    fail_if_error(t1 = cork_test_thread_new(\"test\", &v1, 1));\n    fail_if_error(cork_thread_start(t1));\n    fail_if_error(cork_thread_join(t1));\n    fail_unless_equal(\"Values\", \"%d\", 1, v1);\n}\nEND_TEST\n\nSTART_TEST(test_threads_03)\n{\n    struct cork_thread  *t1;\n    struct cork_thread  *t2;\n    int  v1 = -1;\n    int  v2 = -1;\n\n    DESCRIBE_TEST;\n\n    fail_if_error(t1 = cork_test_thread_new(\"test1\", &v1, 1));\n    fail_if_error(t2 = cork_test_thread_new(\"test2\", &v2, 2));\n    fail_if_error(cork_thread_start(t1));\n    fail_if_error(cork_thread_start(t2));\n    fail_if_error(cork_thread_join(t1));\n    fail_if_error(cork_thread_join(t2));\n    fail_unless_equal(\"Values\", \"%d\", 1, v1);\n    fail_unless_equal(\"Values\", \"%d\", 2, v2);\n}\nEND_TEST\n\nSTART_TEST(test_threads_04)\n{\n    struct cork_thread  *t1;\n    struct cork_thread  *t2;\n    int  v1 = -1;\n    int  v2 = -1;\n\n    DESCRIBE_TEST;\n\n    fail_if_error(t1 = cork_test_thread_new(\"test1\", &v1, 1));\n    fail_if_error(t2 = cork_test_thread_new(\"test2\", &v2, 2));\n    fail_if_error(cork_thread_start(t1));\n    fail_if_error(cork_thread_start(t2));\n    fail_if_error(cork_thread_join(t2));\n    fail_if_error(cork_thread_join(t1));\n    fail_unless_equal(\"Values\", \"%d\", 1, v1);\n    fail_unless_equal(\"Values\", \"%d\", 2, v2);\n}\nEND_TEST\n\nSTART_TEST(test_threads_error_01)\n{\n    DESCRIBE_TEST;\n    struct cork_thread  *t1;\n\n    fail_if_error(t1 = cork_thread_new\n                  (\"test\", NULL, NULL, cork_error_thread__run));\n    fail_if_error(cork_thread_start(t1));\n    fail_unless_error(cork_thread_join(t1));\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"threads\");\n\n    TCase  *tc_atomic = tcase_create(\"atomic\");\n    tcase_add_test(tc_atomic, test_atomic_int);\n    tcase_add_test(tc_atomic, test_atomic_uint);\n    tcase_add_test(tc_atomic, test_atomic_size);\n    tcase_add_test(tc_atomic, test_atomic_ptr);\n    suite_add_tcase(s, tc_atomic);\n\n    TCase  *tc_basics = tcase_create(\"basics\");\n    tcase_add_test(tc_basics, test_once);\n    tcase_add_test(tc_basics, test_once_recursive);\n    tcase_add_test(tc_basics, test_thread_ids);\n    suite_add_tcase(s, tc_basics);\n\n    TCase  *tc_threads = tcase_create(\"threads\");\n    tcase_add_test(tc_threads, test_threads_01);\n    tcase_add_test(tc_threads, test_threads_02);\n    tcase_add_test(tc_threads, test_threads_03);\n    tcase_add_test(tc_threads, test_threads_04);\n    tcase_add_test(tc_threads, test_threads_error_01);\n    suite_add_tcase(s, tc_threads);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  },
  {
    "path": "tests/test-u128.c",
    "content": "/* -*- coding: utf-8 -*-\n * ----------------------------------------------------------------------\n * Copyright © 2017, libcork authors\n * All rights reserved.\n *\n * Please see the COPYING file in this distribution for license details.\n * ----------------------------------------------------------------------\n */\n\n#include <check.h>\n\n#include \"libcork/config.h\"\n#include \"libcork/core/u128.h\"\n#include \"libcork/os/subprocess.h\"\n\n#include \"helpers.h\"\n\n\n/*-----------------------------------------------------------------------\n * 128-bit integers\n */\n\nstatic void\ntest_one_u128_decimal(cork_u128 value, const char *expected)\n{\n    char  buf[CORK_U128_DECIMAL_LENGTH];\n    const char  *actual = cork_u128_to_decimal(buf, value);\n    fail_unless_streq(\"Integers\", expected, actual);\n}\n\nstatic void\ntest_one_u128_hex(cork_u128 value, const char *expected)\n{\n    char  buf[CORK_U128_HEX_LENGTH];\n    const char  *actual = cork_u128_to_hex(buf, value);\n    fail_unless_streq(\"Integers\", expected, actual);\n}\n\nstatic void\ntest_one_u128_padded_hex(cork_u128 value, const char *expected)\n{\n    char  buf[CORK_U128_HEX_LENGTH];\n    const char  *actual = cork_u128_to_padded_hex(buf, value);\n    fail_unless_streq(\"Integers\", expected, actual);\n}\n\nstatic void\ntest_one_u128_print_from_32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3,\n                            const char *expected_decimal,\n                            const char *expected_hex,\n                            const char *expected_padded_hex)\n{\n    cork_u128  value = cork_u128_from_32(i0, i1, i2, i3);\n    test_one_u128_decimal(value, expected_decimal);\n    test_one_u128_hex(value, expected_hex);\n    test_one_u128_padded_hex(value, expected_padded_hex);\n}\n\nstatic void\ntest_one_u128_print_from_64(uint64_t i0, uint64_t i1,\n                            const char *expected_decimal,\n                            const char *expected_hex,\n                            const char *expected_padded_hex)\n{\n    cork_u128  value = cork_u128_from_64(i0, i1);\n    test_one_u128_decimal(value, expected_decimal);\n    test_one_u128_hex(value, expected_hex);\n    test_one_u128_padded_hex(value, expected_padded_hex);\n}\n\nSTART_TEST(test_u128_print)\n{\n    DESCRIBE_TEST;\n    test_one_u128_print_from_32(\n        0, 0, 0, 0,\n        \"0\",\n        \"0\",\n        \"00000000000000000000000000000000\"\n    );\n    test_one_u128_print_from_32(\n        0, 0, 0, 2,\n        \"2\",\n        \"2\",\n        \"00000000000000000000000000000002\"\n    );\n    test_one_u128_print_from_32(\n        0, 0, 0, 20,\n        \"20\",\n        \"14\",\n        \"00000000000000000000000000000014\"\n    );\n    test_one_u128_print_from_32(\n        0, 0, 0, 0xffffffff,\n        \"4294967295\",\n        \"ffffffff\",\n        \"000000000000000000000000ffffffff\"\n    );\n    test_one_u128_print_from_32(\n        0, 0, 1, 0,\n        \"4294967296\",\n        \"100000000\",\n        \"00000000000000000000000100000000\"\n    );\n    test_one_u128_print_from_32(\n        0, 0, 0xffffffff, 0xffffffff,\n        \"18446744073709551615\",\n        \"ffffffffffffffff\",\n        \"0000000000000000ffffffffffffffff\"\n    );\n    test_one_u128_print_from_32(\n        0, 1, 0, 0,\n        \"18446744073709551616\",\n        \"10000000000000000\",\n        \"00000000000000010000000000000000\"\n    );\n    test_one_u128_print_from_64(\n        0, 0,\n        \"0\",\n        \"0\",\n        \"00000000000000000000000000000000\"\n    );\n    test_one_u128_print_from_64(\n        0, 2,\n        \"2\",\n        \"2\",\n        \"00000000000000000000000000000002\"\n    );\n    test_one_u128_print_from_64(\n        0, 20,\n        \"20\",\n        \"14\",\n        \"00000000000000000000000000000014\"\n    );\n    test_one_u128_print_from_64(\n        0, UINT64_C(0xffffffffffffffff),\n        \"18446744073709551615\",\n        \"ffffffffffffffff\",\n        \"0000000000000000ffffffffffffffff\"\n    );\n    test_one_u128_print_from_64(\n        1, 0,\n        \"18446744073709551616\",\n        \"10000000000000000\",\n        \"00000000000000010000000000000000\"\n    );\n}\nEND_TEST\n\n\nstruct shift_test {\n    uint64_t i0;\n    uint64_t i1;\n    unsigned int j;\n    uint64_t res0;\n    uint64_t res1;\n};\n\nstatic void\ncheck_shift_test(cork_u128(op)(cork_u128, unsigned int), const char *op_str,\n                 const struct shift_test *test)\n{\n    cork_u128  value1 = cork_u128_from_64(test->i0, test->i1);\n    cork_u128  expected = cork_u128_from_64(test->res0, test->res1);\n    cork_u128  result = op(value1, test->j);\n    if (!cork_u128_eq(result, expected)) {\n        char  buf1[CORK_U128_HEX_LENGTH];\n        char  buf2[CORK_U128_HEX_LENGTH];\n        char  buf3[CORK_U128_HEX_LENGTH];\n        const char  *value1_str = cork_u128_to_hex(buf1, value1);\n        const char  *expected_str = cork_u128_to_hex(buf2, expected);\n        const char  *result_str = cork_u128_to_hex(buf3, result);\n        fprintf(stderr, \"#     %40s\\n\", value1_str);\n        fprintf(stderr, \"#  %s %40u\\n\", op_str, test->j);\n        fprintf(stderr, \"#   = %40s\\n\", expected_str);\n        fprintf(stderr, \"# got %40s\\n\", result_str);\n        fail(\"Unexpected shift error\");\n    }\n}\n\nstatic void\ncheck_shift_tests_(cork_u128(op)(cork_u128, unsigned int), const char *op_str,\n                   const struct shift_test *test, size_t count)\n{\n    size_t  i;\n    for (i = 0; i < count; i++) {\n        check_shift_test(op, op_str, test + i);\n    }\n}\n\n#define check_shift_tests(op, op_str, tests) \\\n    check_shift_tests_(op, op_str, \\\n            (tests), sizeof(tests) / sizeof(tests[0]))\n\n\nstatic const struct shift_test SHL_TESTS[] = {\n    {0, 1, 1, 0, 2},\n    {0, UINT64_C(0x8000000000000000), 1, 1, 0},\n    {UINT64_C(0x8000000000000000), 0, 1, 0, 0},\n#include \"u128-tests-shl.c.in\"\n};\n\nSTART_TEST(test_u128_shl)\n{\n    DESCRIBE_TEST;\n    check_shift_tests(cork_u128_shl, \"<<\", SHL_TESTS);\n}\nEND_TEST\n\n\nstatic const struct shift_test SHR_TESTS[] = {\n    {0, 1, 1, 0, 0},\n    {0, 2, 1, 0, 1},\n    {1, 0, 1, 0, UINT64_C(0x8000000000000000)},\n#include \"u128-tests-shr.c.in\"\n};\n\nSTART_TEST(test_u128_shr)\n{\n    DESCRIBE_TEST;\n    check_shift_tests(cork_u128_shr, \">>\", SHR_TESTS);\n}\nEND_TEST\n\n\nstruct arithmetic_test {\n    uint64_t i0;\n    uint64_t i1;\n    uint64_t j0;\n    uint64_t j1;\n    uint64_t res0;\n    uint64_t res1;\n};\n\nstatic void\ncheck_arithmetic_test(cork_u128(op)(cork_u128, cork_u128), const char *op_str,\n                      const struct arithmetic_test *test)\n{\n    cork_u128  value1 = cork_u128_from_64(test->i0, test->i1);\n    cork_u128  value2 = cork_u128_from_64(test->j0, test->j1);\n    cork_u128  expected = cork_u128_from_64(test->res0, test->res1);\n    cork_u128  result = op(value1, value2);\n    if (!cork_u128_eq(result, expected)) {\n        char  buf1[CORK_U128_HEX_LENGTH];\n        char  buf2[CORK_U128_HEX_LENGTH];\n        char  buf3[CORK_U128_HEX_LENGTH];\n        char  buf4[CORK_U128_HEX_LENGTH];\n        const char  *value1_str = cork_u128_to_hex(buf1, value1);\n        const char  *value2_str = cork_u128_to_hex(buf2, value2);\n        const char  *expected_str = cork_u128_to_hex(buf3, expected);\n        const char  *result_str = cork_u128_to_hex(buf4, result);\n        fprintf(stderr, \"#     %40s\\n\", value1_str);\n        fprintf(stderr, \"#   %s %40s\\n\", op_str, value2_str);\n        fprintf(stderr, \"#   = %40s\\n\", expected_str);\n        fprintf(stderr, \"# got %40s\\n\", result_str);\n        fail(\"Unexpected arithmetic error\");\n    }\n}\n\nstatic void\ncheck_arithmetic_tests_(cork_u128(op)(cork_u128, cork_u128), const char *op_str,\n                        const struct arithmetic_test *test, size_t count)\n{\n    size_t  i;\n    for (i = 0; i < count; i++) {\n        check_arithmetic_test(op, op_str, test + i);\n    }\n}\n\n#define check_arithmetic_tests(op, op_str, tests) \\\n    check_arithmetic_tests_(op, op_str, \\\n            (tests), sizeof(tests) / sizeof(tests[0]))\n\n\nstatic const struct arithmetic_test ADD_TESTS[] = {\n    {0, 0, 0, 0, 0, 0},\n    {0, 1, 0, 1, 0, 2},\n    {0, 1, 0, UINT64_C(0xffffffffffffffff), 1, 0},\n    {0, 1, UINT64_C(0xffffffffffffffff), UINT64_C(0xffffffffffffffff), 0, 0},\n#include \"u128-tests-add.c.in\"\n};\n\nSTART_TEST(test_u128_add)\n{\n    DESCRIBE_TEST;\n    check_arithmetic_tests(cork_u128_add, \"+\", ADD_TESTS);\n}\nEND_TEST\n\n\nstatic const struct arithmetic_test SUB_TESTS[] = {\n    {0, 0, 0, 0, 0, 0},\n    {0, 1, 0, 1, 0, 0},\n    {0, 2, 0, 1, 0, 1},\n    {1, 0, 0, 1, 0, UINT64_C(0xffffffffffffffff)},\n    {0, 1, 0, 2, UINT64_C(0xffffffffffffffff), UINT64_C(0xffffffffffffffff)},\n#include \"u128-tests-sub.c.in\"\n};\n\nSTART_TEST(test_u128_sub)\n{\n    DESCRIBE_TEST;\n    check_arithmetic_tests(cork_u128_sub, \"-\", SUB_TESTS);\n}\nEND_TEST\n\n\nstruct comparison_test {\n    uint64_t i0;\n    uint64_t i1;\n    uint64_t j0;\n    uint64_t j1;\n    bool expected;\n};\n\nstatic void\ncheck_comparison_test(bool(op)(cork_u128, cork_u128), const char *op_str,\n                      const struct comparison_test *test)\n{\n    cork_u128  value1 = cork_u128_from_64(test->i0, test->i1);\n    cork_u128  value2 = cork_u128_from_64(test->j0, test->j1);\n    bool  actual = op(value1, value2);\n    if (actual != test->expected) {\n        char  buf1[CORK_U128_HEX_LENGTH];\n        char  buf2[CORK_U128_HEX_LENGTH];\n        const char  *value1_str = cork_u128_to_hex(buf1, value1);\n        const char  *value2_str = cork_u128_to_hex(buf2, value2);\n        fprintf(stderr, \"#     %40s\\n\", value1_str);\n        fprintf(stderr, \"#  %s %40s\\n\", op_str, value2_str);\n        fprintf(stderr, \"#   = %s\\n\", test->expected? \"true\": \"false\");\n        fprintf(stderr, \"# got %s\\n\", actual? \"true\": \"false\");\n        fail(\"Unexpected comparison error\");\n    }\n}\n\nstatic void\ncheck_comparison_tests_(bool(op)(cork_u128, cork_u128), const char *op_str,\n                        const struct comparison_test *test, size_t count)\n{\n    size_t  i;\n    for (i = 0; i < count; i++) {\n        check_comparison_test(op, op_str, test + i);\n    }\n}\n\n#define check_comparison_tests(op, op_str, tests) \\\n    check_comparison_tests_(op, op_str, \\\n            (tests), sizeof(tests) / sizeof(tests[0]))\n\nstatic const struct comparison_test EQ_TESTS[] = {\n    {0, 0, 0, 0, true},\n    {0, 0, 0, 1, false},\n    {0, 2, 0, 1, false},\n    {0, 1, 0, UINT64_C(0x100000000), false},\n    {0, UINT64_C(0x100000000), 0, UINT64_C(0x100000000), true},\n#include \"u128-tests-eq.c.in\"\n};\n\nSTART_TEST(test_u128_eq)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_eq, \"==\", EQ_TESTS);\n}\nEND_TEST\n\nstatic const struct comparison_test NE_TESTS[] = {\n    {0, 0, 0, 0, false},\n    {0, 0, 0, 1, true},\n    {0, 2, 0, 1, true},\n    {0, 1, 0, UINT64_C(0x100000000), true},\n    {0, UINT64_C(0x100000000), 0, UINT64_C(0x100000000), false},\n#include \"u128-tests-ne.c.in\"\n};\n\nSTART_TEST(test_u128_ne)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_ne, \"!=\", NE_TESTS);\n}\nEND_TEST\n\nstatic const struct comparison_test LT_TESTS[] = {\n    {0, 0, 0, 0, false},\n    {0, 0, 0, 1, true},\n    {0, 2, 0, 1, false},\n    {0, 1, 0, UINT64_C(0x100000000), true},\n#include \"u128-tests-lt.c.in\"\n};\n\nSTART_TEST(test_u128_lt)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_lt, \"< \", LT_TESTS);\n}\nEND_TEST\n\nstatic const struct comparison_test LE_TESTS[] = {\n    {0, 0, 0, 0, true},\n    {0, 1, 0, 0, false},\n    {0, 1, 0, 2, true},\n    {0, UINT64_C(0x100000000), 0, 1, false},\n#include \"u128-tests-le.c.in\"\n};\n\nSTART_TEST(test_u128_le)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_le, \"<=\", LE_TESTS);\n}\nEND_TEST\n\nstatic const struct comparison_test GT_TESTS[] = {\n    {0, 0, 0, 0, false},\n    {0, 1, 0, 0, true},\n    {0, 1, 0, 2, false},\n    {0, UINT64_C(0x100000000), 0, 1, true},\n#include \"u128-tests-gt.c.in\"\n};\n\nSTART_TEST(test_u128_gt)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_gt, \"> \", GT_TESTS);\n}\nEND_TEST\n\nstatic const struct comparison_test GE_TESTS[] = {\n    {0, 0, 0, 0, true},\n    {0, 0, 0, 1, false},\n    {0, 2, 0, 1, true},\n    {0, 1, 0, UINT64_C(0x100000000), false},\n#include \"u128-tests-ge.c.in\"\n};\n\nSTART_TEST(test_u128_ge)\n{\n    DESCRIBE_TEST;\n    check_comparison_tests(cork_u128_ge, \">=\", GE_TESTS);\n}\nEND_TEST\n\n\n/*-----------------------------------------------------------------------\n * Testing harness\n */\n\nSuite *\ntest_suite()\n{\n    Suite  *s = suite_create(\"core\");\n\n    TCase  *tc_u128 = tcase_create(\"u128\");\n    tcase_add_test(tc_u128, test_u128_print);\n    tcase_add_test(tc_u128, test_u128_shl);\n    tcase_add_test(tc_u128, test_u128_shr);\n    tcase_add_test(tc_u128, test_u128_add);\n    tcase_add_test(tc_u128, test_u128_sub);\n    tcase_add_test(tc_u128, test_u128_eq);\n    tcase_add_test(tc_u128, test_u128_ne);\n    tcase_add_test(tc_u128, test_u128_lt);\n    tcase_add_test(tc_u128, test_u128_le);\n    tcase_add_test(tc_u128, test_u128_gt);\n    tcase_add_test(tc_u128, test_u128_ge);\n    suite_add_tcase(s, tc_u128);\n\n    return s;\n}\n\n\nint\nmain(int argc, const char **argv)\n{\n    int  number_failed;\n    Suite  *suite = test_suite();\n    SRunner  *runner = srunner_create(suite);\n\n    setup_allocator();\n    srunner_run_all(runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(runner);\n    srunner_free(runner);\n\n    return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;\n}\n"
  }
]